diff --git a/.travis.yml b/.travis.yml index 17993ef14..cea3a5e76 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,8 +13,14 @@ env: - TOXENV=docs - TOXENV=coverage,codecov +before_install: + - sudo add-apt-repository ppa:0k53d-karl-f830m/hitch -y + - sudo apt-get -qq update + - sudo apt-get install hitch + install: - pip install tox + - hitch --frontend=[*]:8443 --backend=[localhost]:8080 --daemon $TRAVIS_BUILD_DIR/scripts/example.pem script: - tox diff --git a/kubernetes/client/configuration.py b/kubernetes/client/configuration.py index 10ec4decf..bf0fd7334 100644 --- a/kubernetes/client/configuration.py +++ b/kubernetes/client/configuration.py @@ -85,6 +85,9 @@ class ConfigurationObject(object): self.cert_file = None # client key file self.key_file = None + # check host name + # Set this to True/False to enable/disable SSL hostname verification. + self.assert_hostname = None @property def logger_file(self): diff --git a/kubernetes/client/rest.py b/kubernetes/client/rest.py index 2683b8f90..826d4467b 100644 --- a/kubernetes/client/rest.py +++ b/kubernetes/client/rest.py @@ -95,13 +95,20 @@ class RESTClientObject(object): # key file key_file = config.key_file + kwargs = { + 'num_pools': pools_size, + 'cert_reqs': cert_reqs, + 'ca_certs': ca_certs, + 'cert_file': cert_file, + 'key_file': key_file, + } + + if config.assert_hostname is not None: + kwargs['assert_hostname'] = config.assert_hostname + # https pool manager self.pool_manager = urllib3.PoolManager( - num_pools=pools_size, - cert_reqs=cert_reqs, - ca_certs=ca_certs, - cert_file=cert_file, - key_file=key_file + **kwargs ) def request(self, method, url, query_params=None, headers=None, diff --git a/kubernetes/e2e_test/base.py b/kubernetes/e2e_test/base.py index 84e5668e2..2205a9976 100644 --- a/kubernetes/e2e_test/base.py +++ b/kubernetes/e2e_test/base.py @@ -10,8 +10,11 @@ # License for the specific language governing permissions and limitations # under the License. +import copy +import os import urllib3 +from kubernetes.client.configuration import configuration def is_k8s_running(): try: @@ -19,3 +22,11 @@ def is_k8s_running(): return True except urllib3.exceptions.HTTPError: return False + + +def setSSLConfiguration(): + config = copy.copy(configuration) + config.verify_ssl = True + config.ssl_ca_cert = os.path.dirname(__file__) + '/../../scripts/example.pem' + config.assert_hostname = False + return config \ No newline at end of file diff --git a/kubernetes/e2e_test/test_batch.py b/kubernetes/e2e_test/test_batch.py index ac4b3fc6e..cb710baea 100644 --- a/kubernetes/e2e_test/test_batch.py +++ b/kubernetes/e2e_test/test_batch.py @@ -17,14 +17,21 @@ import uuid from kubernetes.client import api_client from kubernetes.client.apis import batch_v1_api +from kubernetes.client.configuration import configuration from kubernetes.e2e_test import base class TestClientBatch(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.API_URL = 'http://127.0.0.1:8080/' + cls.config = configuration + @unittest.skipUnless( base.is_k8s_running(), "Kubernetes is not available") def test_job_apis(self): - client = api_client.ApiClient('http://127.0.0.1:8080/') + client = api_client.ApiClient(self.API_URL, config=self.config) api = batch_v1_api.BatchV1Api(client) name = 'test-job-' + str(uuid.uuid4()) @@ -52,4 +59,12 @@ class TestClientBatch(unittest.TestCase): self.assertEqual(name, resp.metadata.name) resp = api.delete_namespaced_job( - name=name, body={}, namespace='default') \ No newline at end of file + name=name, body={}, namespace='default') + + +class TestClientBatchSSL(TestClientBatch): + + @classmethod + def setUpClass(cls): + cls.API_URL = 'https://127.0.0.1:8443/' + cls.config = base.setSSLConfiguration() diff --git a/kubernetes/e2e_test/test_client.py b/kubernetes/e2e_test/test_client.py index 84f0ea6f6..a6ee3d6c4 100644 --- a/kubernetes/e2e_test/test_client.py +++ b/kubernetes/e2e_test/test_client.py @@ -17,14 +17,21 @@ import uuid from kubernetes.client import api_client from kubernetes.client.apis import core_v1_api +from kubernetes.client.configuration import configuration from kubernetes.e2e_test import base class TestClient(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.API_URL = 'http://127.0.0.1:8080/' + cls.config = configuration + @unittest.skipUnless( base.is_k8s_running(), "Kubernetes is not available") def test_pod_apis(self): - client = api_client.ApiClient('http://127.0.0.1:8080/') + client = api_client.ApiClient(self.API_URL, config=self.config) api = core_v1_api.CoreV1Api(client) name = 'test-' + str(uuid.uuid4()) @@ -53,7 +60,7 @@ class TestClient(unittest.TestCase): @unittest.skipUnless( base.is_k8s_running(), "Kubernetes is not available") def test_service_apis(self): - client = api_client.ApiClient('http://127.0.0.1:8080/') + client = api_client.ApiClient(self.API_URL, config=self.config) api = core_v1_api.CoreV1Api(client) name = 'frontend-' + str(uuid.uuid4()) @@ -94,7 +101,7 @@ class TestClient(unittest.TestCase): @unittest.skipUnless( base.is_k8s_running(), "Kubernetes is not available") def test_replication_controller_apis(self): - client = api_client.ApiClient('http://127.0.0.1:8080/') + client = api_client.ApiClient(self.API_URL, config=self.config) api = core_v1_api.CoreV1Api(client) name = 'frontend-' + str(uuid.uuid4()) @@ -129,7 +136,7 @@ class TestClient(unittest.TestCase): @unittest.skipUnless( base.is_k8s_running(), "Kubernetes is not available") def test_configmap_apis(self): - client = api_client.ApiClient('http://127.0.0.1:8080/') + client = api_client.ApiClient(self.API_URL, config=self.config) api = core_v1_api.CoreV1Api(client) name = 'test-configmap-' + str(uuid.uuid4()) @@ -167,10 +174,18 @@ class TestClient(unittest.TestCase): @unittest.skipUnless( base.is_k8s_running(), "Kubernetes is not available") def test_node_apis(self): - client = api_client.ApiClient('http://127.0.0.1:8080/') + client = api_client.ApiClient(self.API_URL, config=self.config) api = core_v1_api.CoreV1Api(client) for item in api.list_node().items: node = api.read_node(name=item.metadata.name) self.assertTrue(len(node.metadata.labels) > 0) - self.assertTrue(isinstance(node.metadata.labels, dict)) \ No newline at end of file + self.assertTrue(isinstance(node.metadata.labels, dict)) + + +class TestClientSSL(TestClient): + + @classmethod + def setUpClass(cls): + cls.API_URL = 'https://127.0.0.1:8443/' + cls.config = base.setSSLConfiguration() diff --git a/kubernetes/e2e_test/test_extensions.py b/kubernetes/e2e_test/test_extensions.py index 42030911a..69da8b8cf 100644 --- a/kubernetes/e2e_test/test_extensions.py +++ b/kubernetes/e2e_test/test_extensions.py @@ -18,15 +18,22 @@ import yaml from kubernetes.client import api_client from kubernetes.client.apis import extensions_v1beta1_api +from kubernetes.client.configuration import configuration from kubernetes.client.models import v1_delete_options from kubernetes.e2e_test import base class TestClientExtensions(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.API_URL = 'http://127.0.0.1:8080/' + cls.config = configuration + @unittest.skipUnless( base.is_k8s_running(), "Kubernetes is not available") def test_create_deployment(self): - client = api_client.ApiClient('http://127.0.0.1:8080/') + client = api_client.ApiClient(self.API_URL, config=self.config) api = extensions_v1beta1_api.ExtensionsV1beta1Api(client) name = 'nginx-deployment-' + str(uuid.uuid4()) deployment = '''apiVersion: extensions/v1beta1 @@ -58,7 +65,7 @@ spec: @unittest.skipUnless( base.is_k8s_running(), "Kubernetes is not available") def test_create_daemonset(self): - client = api_client.ApiClient('http://127.0.0.1:8080/') + client = api_client.ApiClient(self.API_URL, config=self.config) api = extensions_v1beta1_api.ExtensionsV1beta1Api(client) name = 'nginx-app-' + str(uuid.uuid4()) daemonset = { @@ -90,4 +97,12 @@ spec: self.assertIsNotNone(resp) options = v1_delete_options.V1DeleteOptions() - resp = api.delete_namespaced_daemon_set(name, 'default', body=options) \ No newline at end of file + resp = api.delete_namespaced_daemon_set(name, 'default', body=options) + + +class TestClientExtensionsSSL(TestClientExtensions): + + @classmethod + def setUpClass(cls): + cls.API_URL = 'https://127.0.0.1:8443/' + cls.config = base.setSSLConfiguration() diff --git a/scripts/example.pem b/scripts/example.pem new file mode 100755 index 000000000..5031637b8 --- /dev/null +++ b/scripts/example.pem @@ -0,0 +1,45 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC322Zo7ETx0bAw +0kJytMDPa76VT+TRgZj6AzS8xm+kRXeqLDJ+6ZmDvZkNKwbwIKAmccWvY/OJNv/0 +c5f1Hd6Y+vK9Qxi4f62ZbavKJpcxIFepa/hmrkRN0Iw9ZahzRZy07jw9SFxZTKEK +GTj/sb+SCUMwaJFZN0D6zhtqR70NjdHp14JWJsUtarBBtoGzEtINJgRkTS9ej6Fj +bh2RGz6HKiWQgX9W7v5P7zFek9IUDEczBr/aQlFXwE0tNUMjbZyMM4TfgITcx+mj +FbR3+hoZLJg0NMKT2wSiKvp1DU0KR5xF8S4q4OUC5yyvV2ylHPdvWldh+6LXcrx/ +oSxhpYDhAgMBAAECggEAUNZfhbx0Z9ppXF3mJ2b/63MVHbM+CTuxFiP4uROKnLCK +d8DtBs4Q2FKxi4+igkvl/mFBqOcKegc7rLByXKygZaTYu4xXvy8sFeyZfs1O5qOw +x2YYlpUCpTAPqSMcWGqABzFEPTGmoQDHQZhrbkkp0LzP1OX1GkPoBx4+AZG/Nsin +aWrTgfPNOtK2RGyLuS3rNn+NWh1jlm/37AVayKxSTirL5XXZUOW3Yye5ROZDWddr +rKzkhIsF/zcUxsQvFtMtjFPRFhKlasAx6MgPB2ptzj5Ykq29jumVfBd9O6voqDMW +ZFnN7G/wjLz8RM9hyW6hBLwIJV4ybJ1DagwqhGNzUQKBgQDxVQOsIWrHkxwZXA8a +iVJDpGlYc6jPlam2T2m3yXPqXfXlZ7Qx+RcmYY94QdEgeF1DGI8xNc1PSiSKjWH0 ++c3jbabB6kk82Qi2RzbApnjQdzlnWv29jiRgPVgPZcoSiMQFmtG8pUFgI8zOCsQK +1iZTgx6KxMpZpo4xSZiBPR2mzQKBgQDDCBuIjPYQwG4MPTyTyorvsCaZmxkLgFXd +nBhPFtjVAUuLamoche27VXdFgTpYRF8EflIyeSQ3+Dkr8tceMkZaX4Ih3pKEsMxI +AZALSVBp0Hdz06RGsqc5dPU8N0asNvEZfoNhTBJ0cD/TYABOg3PQyPr7Ez5Y/SdR +UYaG30l6ZQKBgAaljcVW4kb+4T49j9juQUrFo3UhMlwNRjBUPZgnPz8MOXKJCah6 +sM2I0FfCkEzxo7fuXDtBvRba9uit/i2uF6KU6YvbtQqs+5VxnqttqlQrhHQ5SFXJ +LW1NIzjBV/BsveFdozsr3gIU2lYua7nUrheMu/Gce+o+MRpgaYfdtAxdAoGBAJAz +RmhIEQeBv9w8yrVbZC6kR2X7TyE52kLoTvDrK5cSRhDmtV4xh/yizHUPf1wT8U0Z +OR0ohKb9WQgtnPAuq+XWCBmSvzJsph33SdGOe25BPJDfQu8i2JGa8Fd9Zzudw9Xd +vLYL0PlWpVpb+N4UQ2VztF4/dDHHu3JcnOLL5UAhAoGBAJ26mvFsFi4iznYHaK7l +duuJtFHkfi3OQhNQN8PBPu4bat+WL5GA3QhGbdLYJXNse5BbytWeG0gw6TY8SYYV +KJgaBxUrGyVF6DBb7Bef5I+YKFu3Q30gzXhyUudC767AJ8DaEudTObjdKWjJlPBG +T4ouTQt/t6W+er9GlqaLpKCw +-----END PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIICuDCCAaCgAwIBAgIJAOUAihuiFPxaMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV +BAMMCWxvY2FsaG9zdDAeFw0xNzAyMDIyMTQ0MTVaFw0yNzAxMzEyMTQ0MTVaMBQx +EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBALfbZmjsRPHRsDDSQnK0wM9rvpVP5NGBmPoDNLzGb6RFd6osMn7pmYO9mQ0r +BvAgoCZxxa9j84k2//Rzl/Ud3pj68r1DGLh/rZltq8omlzEgV6lr+GauRE3QjD1l +qHNFnLTuPD1IXFlMoQoZOP+xv5IJQzBokVk3QPrOG2pHvQ2N0enXglYmxS1qsEG2 +gbMS0g0mBGRNL16PoWNuHZEbPocqJZCBf1bu/k/vMV6T0hQMRzMGv9pCUVfATS01 +QyNtnIwzhN+AhNzH6aMVtHf6GhksmDQ0wpPbBKIq+nUNTQpHnEXxLirg5QLnLK9X +bKUc929aV2H7otdyvH+hLGGlgOECAwEAAaMNMAswCQYDVR0TBAIwADANBgkqhkiG +9w0BAQsFAAOCAQEABblz/REaCmzZq/wlRN3NdwRuLvSz1peAVQNmuEfpIsYDxHIU +ognnm+afEo6O18PjBXFSP4r1vsc/TTGk1T3xP4FgPJ9xLsUNQk9Kch05vQIwJtcQ +iIdMRhGVdxSg8V29KTFImfcbS/VkV9Ev/FKHifs+PL9rJMBpE/r6xe6D6p+d9jw5 +cpCw+kgGHZVWA+8GEjyCGZIHyMAL6YwC246N6uTPuDHyvQZZHqh9r602bp5zpMbw +ZW4+YD7+PEAhFmTRYiqUPTyBPRBKcIZdkKtND/CQ4IwtHJ+ApjwQuXBjKUpPJroh +s5cwhxeaimBe9C9axIuuUd8LAVTXLFVwL0wEYw== +-----END CERTIFICATE----- diff --git a/tox.ini b/tox.ini index c9e8aee09..bfb56cf07 100644 --- a/tox.ini +++ b/tox.ini @@ -21,12 +21,12 @@ commands = [testenv:py27-functional] commands = python -V - {toxinidir}/scripts/kube-init.sh nosetests [] + {toxinidir}/scripts/kube-init.sh nosetests -v [] [testenv:py35-functional] commands = python -V - {toxinidir}/scripts/kube-init.sh nosetests [] + {toxinidir}/scripts/kube-init.sh nosetests -v [] [testenv:coverage] commands =