diff --git a/.travis.yml b/.travis.yml index 227e1bbb..186ed8ec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,6 +15,7 @@ python: env: - OPENSHIFT_VERSION=latest + - OPENSHIFT_VERSION=3.6 - OPENSHIFT_VERSION=1.5 - OPENSHIFT_VERSION=1.4 - OPENSHIFT_VERSION=1.3 diff --git a/openshift/ansiblegen/examples/v1_route.yml b/openshift/ansiblegen/examples/v1_route.yml index c04d97d3..ef2c6da2 100644 --- a/openshift/ansiblegen/examples/v1_route.yml +++ b/openshift/ansiblegen/examples/v1_route.yml @@ -5,8 +5,8 @@ name: myroute namespace: k8s-project host: www.example.com - target_reference_kind: Service - target_reference_name: service-name + spec_to_kind: Service + spec_to_name: service-name tls_termination: edge tls_key: |- -----BEGIN PRIVATE KEY----- @@ -28,8 +28,8 @@ namespace: k8s-project host: www.example.com tls_termination: reencrypt - target_reference_kind: Service - target_reference_name: other-service-name + spec_to_kind: Service + spec_to_name: other-service-name tls_destination_ca_certificate: |- -----BEGIN CERTIFICATE----- destination cetricate_contents @@ -41,8 +41,8 @@ namespace: k8s-project host: www.example.com path: /foo/bar/baz.html - target_reference_kind: Service - target_reference_name: whimsy-name + spec_to_kind: Service + spec_to_name: whimsy-name tls_termination: edge tls_key: |- -----BEGIN PRIVATE KEY----- diff --git a/openshift/client/api_client.py b/openshift/client/api_client.py index 1d71a99d..0407ceca 100644 --- a/openshift/client/api_client.py +++ b/openshift/client/api_client.py @@ -1,9 +1,14 @@ +from __future__ import absolute_import + from kubernetes.client.api_client import ApiClient as K8sApiClient +from . import models + class ApiClient(K8sApiClient): def _ApiClient__deserialize(self, data, klass): try: return super(ApiClient, self).__deserialize(data, klass) except AttributeError: - klass = eval('models.' + klass) + klass = getattr(models, klass) return super(ApiClient, self).__deserialize_model(data, klass) + diff --git a/openshift/config/__init__.py b/openshift/config/__init__.py new file mode 100644 index 00000000..3960b7da --- /dev/null +++ b/openshift/config/__init__.py @@ -0,0 +1,4 @@ +from kubernetes.config.config_exception import ConfigException +from kubernetes.config.incluster_config import load_incluster_config +from kubernetes.config.kube_config import list_kube_config_contexts, load_kube_config +from .kube_config import new_client_from_config \ No newline at end of file diff --git a/openshift/config/kube_config.py b/openshift/config/kube_config.py new file mode 100644 index 00000000..a6fb0d2b --- /dev/null +++ b/openshift/config/kube_config.py @@ -0,0 +1,12 @@ +from kubernetes.config import load_kube_config +from openshift.client import ApiClient, ConfigurationObject + + +def new_client_from_config(config_file=None, context=None): + """Loads configuration the same as load_kube_config but returns an ApiClient + to be used with any API object. This will allow the caller to concurrently + talk with multiple clusters.""" + client_config = ConfigurationObject() + load_kube_config(config_file=config_file, context=context, + client_configuration=client_config) + return ApiClient(config=client_config) \ No newline at end of file diff --git a/openshift/helper/__init__.py b/openshift/helper/__init__.py index 239100d6..461d542d 100644 --- a/openshift/helper/__init__.py +++ b/openshift/helper/__init__.py @@ -14,12 +14,11 @@ from dictdiffer import diff -from kubernetes import config, watch +from kubernetes import watch from kubernetes.client.rest import ApiException from kubernetes.config.config_exception import ConfigException -from openshift import client -from openshift.client import configuration, ApiClient +from openshift import client, config from openshift.client.models import V1DeleteOptions from .exceptions import OpenShiftException @@ -63,7 +62,7 @@ class KubernetesObjectHelper(object): - def __init__(self, api_version, kind, debug=False, reset_logfile=True, timeout=20): + def __init__(self, api_version, kind, debug=False, reset_logfile=True, timeout=20, **auth): self.api_version = api_version self.kind = kind self.model = self.get_model(api_version, kind) @@ -75,36 +74,39 @@ def __init__(self, api_version, kind, debug=False, reset_logfile=True, timeout=2 if debug: self.enable_debug(reset_logfile) - try: - config.load_kube_config() - except Exception as exc: - logger.debug("Unable to load default config: {}".format(exc)) - - self.api_client = self.api_client = ApiClient() + self.set_client_config(**auth) - def set_client_config(self, **kwargs): + def set_client_config(self, **auth): """ Convenience method for updating the configuration object, and instantiating a new client """ - if kwargs.get('kubeconfig') or kwargs.get('context'): - # Attempt to load config from file - try: - config.load_kube_config(config_file=kwargs.get('kubeconfig'), - context=kwargs.get('context')) - except IOError as e: + config_file = auth.get('kubeconfig') + context = auth.get('context') + + try: + self.api_client = config.new_client_from_config(config_file, context) + except ConfigException as e: + raise OpenShiftException( + "Error accessing context {}.".format(auth.get('context')), error=str(e)) + except IOError as e: + if config_file is not None: + # Missing specified config file, cannot continue raise OpenShiftException( - "Failed to access {}. Does the file exist?".format(kwargs.get('kubeconfig')), error=str(e) + "Failed to access {}. Does the file exist?".format(config_file), error=str(e) ) - except ConfigException as e: - raise OpenShiftException( - "Error accessing context {}.".format(kwargs.get('context')), error=str(e)) + else: + # Default config is missing, but other auth params may be provided, continue + logger.debug("Unable to load default config: {}".format(e)) + + if auth.get('host') is not None: + self.api_client.host = auth['host'] + + auth_keys = ['api_key', 'ssl_ca_cert', 'cert_file', 'key_file', 'verify_ssl'] - auth_keys = ['api_key', 'host', 'ssl_ca_cert', 'cert_file', 'key_file', 'verify_ssl'] for key in auth_keys: - if kwargs.get(key, None) is not None: + if auth.get(key, None) is not None: if key == 'api_key': - configuration.api_key = {'authorization': kwargs[key]} + self.api_client.config.api_key = {'authorization': auth[key]} else: - setattr(configuration, key, kwargs[key]) - self.api_client = self.api_client = ApiClient() + setattr(self.api_client.config, key, auth[key]) @staticmethod def enable_debug(reset_logfile=True): @@ -135,7 +137,7 @@ def get_object(self, name, namespace=None): return k8s_obj def patch_object(self, name, namespace, k8s_obj): - logger.debug('Starting create object') + logger.debug('Starting patch object') empty_status = self.properties['status']['class']() k8s_obj.status = empty_status k8s_obj.metadata.resource_version = None @@ -151,7 +153,7 @@ def patch_object(self, name, namespace, k8s_obj): except ApiException as exc: msg = json.loads(exc.body).get('message', exc.reason) if exc.body.startswith('{') else exc.body raise OpenShiftException(msg, status=exc.status) - return_obj = self.__read_stream(w, stream) + return_obj = self.__read_stream(w, stream, name) if not return_obj: self.__wait_for_response(name, namespace, 'patch') return return_obj @@ -165,14 +167,17 @@ def create_project(self, metadata, display_name=None, description=None): """ # TODO: handle admin-level project creation + w, stream = self.__create_stream(None) try: proj_req = client.V1ProjectRequest(metadata=metadata, display_name=display_name, description=description) - client.OapiApi().create_project_request(proj_req) + client.OapiApi(self.api_client).create_project_request(proj_req) except ApiException as exc: msg = json.loads(exc.body).get('message', exc.reason) if exc.body.startswith('{') else exc.body raise OpenShiftException(msg, status=exc.status) - return_obj = self.__wait_for_response(metadata.name, None, 'create') + return_obj = self.__read_stream(w, stream, metadata.name) + if not return_obj: + return_obj = self.__wait_for_response(metadata.name, None, 'create') return return_obj @@ -186,6 +191,7 @@ def create_object(self, namespace, k8s_obj=None, body=None): """ logger.debug('Starting create object') w, stream = self.__create_stream(namespace) + name = None if k8s_obj: name = k8s_obj.metadata.name elif body: @@ -206,7 +212,7 @@ def create_object(self, namespace, k8s_obj=None, body=None): msg = json.loads(exc.body).get('message', exc.reason) if exc.body.startswith('{') else exc.body raise OpenShiftException(msg, status=exc.status) - return_obj = self.__read_stream(w, stream) + return_obj = self.__read_stream(w, stream, name) # Allow OpenShift annotations to be added to Namespace #if isinstance(k8s_obj, client.models.V1Namespace): @@ -220,27 +226,39 @@ def create_object(self, namespace, k8s_obj=None, body=None): def delete_object(self, name, namespace): logger.debug('Starting delete object {0} {1} {2}'.format(self.kind, name, namespace)) delete_method = self.lookup_method('delete', namespace) - w, stream = self.__create_stream(namespace) + + if self.kind in ('project', 'namespace'): + w, stream = self.__create_stream(namespace) + + status_obj = None if not namespace: try: if 'body' in inspect.getargspec(delete_method).args: - delete_method(name, body=V1DeleteOptions()) + status_obj = delete_method(name, body=V1DeleteOptions()) else: - delete_method(name) + status_obj = delete_method(name) except ApiException as exc: msg = json.loads(exc.body).get('message', exc.reason) raise OpenShiftException(msg, status=exc.status) else: try: if 'body' in inspect.getargspec(delete_method).args: - delete_method(name, namespace, body=V1DeleteOptions()) + status_obj = delete_method(name, namespace, body=V1DeleteOptions()) else: - delete_method(name, namespace) + status_obj = delete_method(name, namespace) except ApiException as exc: msg = json.loads(exc.body).get('message', exc.reason) if exc.body.startswith('{') else exc.body raise OpenShiftException(msg, status=exc.status) - self.__read_stream(w, stream) - #self.__wait_for_response(name, namespace, 'delete') + + if status_obj is None or status_obj.status == 'Failure': + msg = 'Failed to delete {}'.format(name) + if namespace is not None: + msg += ' in namespace {}'.format(namespace) + msg += ' status: {}'.format(status_obj) + raise OpenShiftException(msg) + + if self.kind in ('project', 'namespace'): + self.__read_stream(w, stream, name) def replace_object(self, name, namespace, k8s_obj=None, body=None): """ Replace an existing object. Pass in a model object or request dict(). @@ -276,13 +294,14 @@ def replace_object(self, name, namespace, k8s_obj=None, body=None): msg = json.loads(exc.body).get('message', exc.reason) if exc.body.startswith('{') else exc.body raise OpenShiftException(msg, status=exc.status) - return_obj = self.__read_stream(w, stream) + return_obj = self.__read_stream(w, stream, name) if not return_obj: return_obj = self.__wait_for_response(name, namespace, 'replace') return return_obj - def objects_match(self, obj_a, obj_b): + @staticmethod + def objects_match(obj_a, obj_b): """ Test the equality of two objects. Returns bool, diff object. Use list(diff object) to log or iterate over differences """ if obj_a is None and obj_b is None: @@ -352,7 +371,7 @@ def lookup_method(self, operation, namespace=None): method = None for api in apis: api_class = getattr(client.apis, api) - method = getattr(api_class(), method_name, None) + method = getattr(api_class(self.api_client), method_name, None) if method is not None: break if method is None: @@ -438,7 +457,7 @@ def __wait_for_response(self, name, namespace, action): def __create_stream(self, namespace): """ Create a stream that gets events for the our model """ w = watch.Watch() - w._api_client = self.api_client # monkey patch for access to OpenShift models + w._api_client = self.api_client # monkey patch for access to OpenShift models list_method = self.lookup_method('list', namespace) if namespace: stream = w.stream(list_method, namespace, _request_timeout=self.timeout) @@ -446,7 +465,7 @@ def __create_stream(self, namespace): stream = w.stream(list_method, _request_timeout=self.timeout) return w, stream - def __read_stream(self, watcher, stream): + def __read_stream(self, watcher, stream, name): #TODO https://cobe.io/blog/posts/kubernetes-watch-python/ <--- might help? return_obj = None @@ -463,33 +482,44 @@ def __read_stream(self, watcher, stream): else: logger.debug(repr(event)) - if event['type'] == 'DELETED': - # Object was deleted - return_obj = obj - watcher.stop() - break - elif obj is not None: - # Object is either added or modified. Check the status and determine if we - # should continue waiting - if hasattr(obj, 'status'): - status = getattr(obj, 'status') - if hasattr(status, 'phase'): - if status.phase == 'Active': - # TODO other phase values ?? - return_obj = obj - watcher.stop() - break - elif hasattr(status, 'conditions'): - conditions = getattr(status, 'conditions') - if conditions and len(conditions) > 0: - # We know there is a status, but it's up to the user to determine meaning. + if event['object'].metadata.name == name: + if event['type'] == 'DELETED': + # Object was deleted + return_obj = obj + watcher.stop() + break + elif obj is not None: + # Object is either added or modified. Check the status and determine if we + # should continue waiting + if hasattr(obj, 'status'): + status = getattr(obj, 'status') + if hasattr(status, 'phase'): + if status.phase == 'Active': + # TODO other phase values ?? + # TODO test namespaces for OpenShift annotations if needed + return_obj = obj + watcher.stop() + break + elif hasattr(status, 'conditions'): + conditions = getattr(status, 'conditions') + if conditions and len(conditions) > 0: + # We know there is a status, but it's up to the user to determine meaning. + return_obj = obj + watcher.stop() + break + elif obj.kind == 'Service' and status is not None: return_obj = obj watcher.stop() break - elif obj.kind == 'Service' and status is not None: - return_obj = obj - watcher.stop() - break + elif obj.kind == 'Route': + route_statuses = set() + for route_ingress in status.ingress: + for condition in route_ingress.conditions: + route_statuses.add(condition.type) + if route_statuses <= set(['Ready', 'Admitted']): + return_obj = obj + watcher.stop() + break except Exception as exc: # A timeout occurred diff --git a/openshift/helper/ansible.py b/openshift/helper/ansible.py index 76f35aa7..06ae7d63 100644 --- a/openshift/helper/ansible.py +++ b/openshift/helper/ansible.py @@ -322,7 +322,7 @@ def __set_obj_attribute(self, obj, property_path, param_value, param_name): elif prop_kind.startswith('list['): if getattr(obj, prop_name) is None: setattr(obj, prop_name, []) - obj_type = prop_kind.replace('list[', '').replace(']','') + obj_type = prop_kind.replace('list[', '').replace(']', '') if obj_type not in ('str', 'int', 'bool', 'list', 'dict'): self.__compare_obj_list(getattr(obj, prop_name), param_value, obj_type, param_name) else: @@ -678,4 +678,3 @@ def add_meta(prop_name, prop_prefix, prop_alt_prefix): if prop == 'type': args[arg_prefix + prop]['choices'] = self.__convert_params_to_choices(properties) return args - diff --git a/setup.cfg b/setup.cfg index 1a74fcca..dfb0bbe3 100644 --- a/setup.cfg +++ b/setup.cfg @@ -7,7 +7,7 @@ all_files = 1 upload-dir = doc/build/html [flake8] -exclude=.tox/,venv/,openshift/__init__.py,openshift/client/,openshift/client/models/,openshift/client/apis/,openshift/test/,scripts/ +exclude=.tox/,venv/,openshift/__init__.py,openshift/client/,openshift/client/models/,openshift/client/apis/,openshift/test/,scripts/,_modules/ max_line_length = 120 [yapf] diff --git a/test/functional/conftest.py b/test/functional/conftest.py index 61874a62..a388b7a2 100644 --- a/test/functional/conftest.py +++ b/test/functional/conftest.py @@ -64,7 +64,27 @@ def kubeconfig(openshift_container, tmpdir_factory): if openshift_container is None: return None else: - tar_stream, _ = openshift_container.get_archive('/var/lib/origin/openshift.local.config/master/admin.kubeconfig') + openshift_container.exec_run('oc login -u test -p test') + tar_stream, _ = openshift_container.get_archive( + '/var/lib/origin/openshift.local.config/master/admin.kubeconfig') + tar_obj = tarfile.open(fileobj=io.BytesIO(tar_stream.read())) + kubeconfig_contents = tar_obj.extractfile('admin.kubeconfig').read() + + kubeconfig_file = tmpdir_factory.mktemp('kubeconfig').join('admin.kubeconfig') + kubeconfig_file.write(kubeconfig_contents) + return kubeconfig_file + + +@pytest.fixture(scope='session') +def admin_kubeconfig(openshift_container, tmpdir_factory): + # get_archive returns a stream of the tar archive containing the requested + # files/directories, so we need use BytesIO as an intermediate step. + if openshift_container is None: + return None + else: + openshift_container.exec_run('oc login -u system:admin') + tar_stream, _ = openshift_container.get_archive( + '/var/lib/origin/openshift.local.config/master/admin.kubeconfig') tar_obj = tarfile.open(fileobj=io.BytesIO(tar_stream.read())) kubeconfig_contents = tar_obj.extractfile('admin.kubeconfig').read() @@ -76,14 +96,32 @@ def kubeconfig(openshift_container, tmpdir_factory): @pytest.fixture(scope='module') def ansible_helper(request, kubeconfig): _, api_version, resource = request.module.__name__.split('_', 2) - helper = AnsibleModuleHelper(api_version, resource, debug=True, reset_logfile=False) + auth = {} if kubeconfig is not None: auth = { 'kubeconfig': str(kubeconfig), 'host': 'https://localhost:8443', 'verify_ssl': False } - helper.set_client_config(**auth) + helper = AnsibleModuleHelper(api_version, resource, debug=True, reset_logfile=False, **auth) + helper.api_client.config.debug = True + + return helper + + +@pytest.fixture(scope='module') +def admin_ansible_helper(request, admin_kubeconfig): + _, api_version, resource = request.module.__name__.split('_', 2) + auth = {} + if admin_kubeconfig is not None: + auth = { + 'kubeconfig': str(admin_kubeconfig), + 'host': 'https://localhost:8443', + 'verify_ssl': False + } + helper = AnsibleModuleHelper(api_version, resource, debug=True, reset_logfile=False, **auth) + helper.api_client.config.debug = True + return helper @@ -113,47 +151,53 @@ def compare_func(ansible_helper, k8s_obj, parameters): ansible_helper.log(list(diff)) ansible_helper.log('\n\n') assert match + return compare_func @pytest.fixture(scope='module') def namespace(kubeconfig): name = "test-{}".format(uuid.uuid4()) - helper = AnsibleModuleHelper('v1', 'namespace', debug=True, reset_logfile=False) + + auth = {} if kubeconfig is not None: auth = { 'kubeconfig': str(kubeconfig), 'host': 'https://localhost:8443', 'verify_ssl': False } - helper.set_client_config(**auth) + helper = AnsibleModuleHelper('v1', 'namespace', debug=True, reset_logfile=False, **auth) k8s_obj = helper.create_object(models.V1Namespace(metadata=models.V1ObjectMeta(name=name))) + assert k8s_obj is not None - yield k8s_obj + yield name helper.delete_object(name, None) @pytest.fixture() def object_name(): - name = 'test-{}'.format(uuid.uuid4()) + # v1.3 services cannot be longer than 24 characters long + # truncate at 23 to avoid a trailing '-' + name = 'test-{}'.format(uuid.uuid4())[:23] return name @pytest.fixture(scope='module') def project(kubeconfig): name = "test-{}".format(uuid.uuid4()) - helper = AnsibleModuleHelper('v1', 'project', debug=True, reset_logfile=False) + auth = {} if kubeconfig is not None: auth = { 'kubeconfig': str(kubeconfig), 'host': 'https://localhost:8443', 'verify_ssl': False } - helper.set_client_config(**auth) + helper = AnsibleModuleHelper('v1', 'project', debug=True, reset_logfile=False, **auth) k8s_obj = helper.create_project(metadata=models.V1ObjectMeta(name=name)) + assert k8s_obj is not None yield name @@ -161,16 +205,16 @@ def project(kubeconfig): def _get_id(argvalue): - type = '' + op_type = '' if argvalue.get('create'): - type = 'create' + op_type = 'create' elif argvalue.get('patch'): - type = 'patch' + op_type = 'patch' elif argvalue.get('remove'): - type = 'remove' + op_type = 'remove' elif argvalue.get('replace'): - type = 'replace' - return type + '_' + argvalue[type]['name'] + '_' + "{:0>3}".format(argvalue['seq']) + op_type = 'replace' + return op_type + '_' + argvalue[op_type]['name'] + '_' + "{:0>3}".format(argvalue['seq']) def pytest_generate_tests(metafunc): @@ -204,4 +248,4 @@ def pytest_generate_tests(metafunc): unique_namespaces = dict() for task in tasks: unique_namespaces[task['create']['namespace']] = None - metafunc.parametrize("namespaces", list(unique_namespaces.keys())) \ No newline at end of file + metafunc.parametrize("namespaces", list(unique_namespaces.keys())) diff --git a/test/functional/test_v1_deployment_config.py b/test/functional/test_v1_deployment_config.py index 61bf5079..e7bcf0c8 100644 --- a/test/functional/test_v1_deployment_config.py +++ b/test/functional/test_v1_deployment_config.py @@ -87,4 +87,4 @@ def test_remove_deployment(ansible_helper, deployment_config): name = deployment_config.metadata.name ansible_helper.delete_object(name, namespace) k8s_obj = ansible_helper.get_object(name, namespace) - assert k8s_obj is None \ No newline at end of file + assert k8s_obj is None diff --git a/test/functional/test_v1_namespace.py b/test/functional/test_v1_namespace.py index 5a22b775..91b5f18b 100644 --- a/test/functional/test_v1_namespace.py +++ b/test/functional/test_v1_namespace.py @@ -31,52 +31,52 @@ def replace_params(replace_tasks, object_name): @pytest.fixture() -def k8s_namespace(ansible_helper, create_params): - request_body = ansible_helper.request_body_from_params(create_params) +def k8s_namespace(admin_ansible_helper, create_params): + request_body = admin_ansible_helper.request_body_from_params(create_params) name = create_params.get('name') - k8s_obj = ansible_helper.create_object(None, body=request_body) + k8s_obj = admin_ansible_helper.create_object(None, body=request_body) yield k8s_obj try: - ansible_helper.delete_object(name, None) + admin_ansible_helper.delete_object(name, None) except OpenShiftException as ex: # Swallow exception if object is already removed if ex.value.get('status') != 404: raise -def test_create_namespace(ansible_helper, create_params, k8s_namespace, obj_compare): - obj_compare(ansible_helper, k8s_namespace, create_params) +def test_create_namespace(admin_ansible_helper, create_params, k8s_namespace, obj_compare): + obj_compare(admin_ansible_helper, k8s_namespace, create_params) -def test_get_namespace(ansible_helper, k8s_namespace): +def test_get_namespace(admin_ansible_helper, k8s_namespace): name = k8s_namespace.metadata.name - k8s_obj = ansible_helper.get_object(name, None) + k8s_obj = admin_ansible_helper.get_object(name, None) assert k8s_obj is not None -def test_patch_namespace(ansible_helper, k8s_namespace, patch_params, obj_compare): +def test_patch_namespace(admin_ansible_helper, k8s_namespace, patch_params, obj_compare): name = patch_params.get('name') existing_obj = k8s_namespace updated_obj = copy.deepcopy(existing_obj) - ansible_helper.object_from_params(patch_params, obj=updated_obj) - match, _ = ansible_helper.objects_match(existing_obj, updated_obj) + admin_ansible_helper.object_from_params(patch_params, obj=updated_obj) + match, _ = admin_ansible_helper.objects_match(existing_obj, updated_obj) assert not match - new_obj = ansible_helper.patch_object(name, None, updated_obj) + new_obj = admin_ansible_helper.patch_object(name, None, updated_obj) assert new_obj is not None - obj_compare(ansible_helper, new_obj, patch_params) + obj_compare(admin_ansible_helper, new_obj, patch_params) -def test_replace_namespace(ansible_helper, k8s_namespace, replace_params, obj_compare): +def test_replace_namespace(admin_ansible_helper, k8s_namespace, replace_params, obj_compare): name = replace_params.get('name') - request_body = ansible_helper.request_body_from_params(replace_params) - k8s_obj = ansible_helper.replace_object(name, None, body=request_body) - obj_compare(ansible_helper, k8s_obj, replace_params) + request_body = admin_ansible_helper.request_body_from_params(replace_params) + k8s_obj = admin_ansible_helper.replace_object(name, None, body=request_body) + obj_compare(admin_ansible_helper, k8s_obj, replace_params) -def test_remove_namespace(ansible_helper, k8s_namespace): +def test_remove_namespace(admin_ansible_helper, k8s_namespace): name = k8s_namespace.metadata.name - ansible_helper.delete_object(name, None) - k8s_obj = ansible_helper.get_object(name, None) - assert k8s_obj is None \ No newline at end of file + admin_ansible_helper.delete_object(name, None) + k8s_obj = admin_ansible_helper.get_object(name, None) + assert k8s_obj is None diff --git a/test/functional/test_v1_project.py b/test/functional/test_v1_project.py index 2a97257f..dc397b82 100644 --- a/test/functional/test_v1_project.py +++ b/test/functional/test_v1_project.py @@ -61,4 +61,4 @@ def test_remove_project(ansible_helper, openshift_project): name = openshift_project.metadata.name ansible_helper.delete_object(name, None) k8s_obj = ansible_helper.get_object(name, None) - assert k8s_obj is None \ No newline at end of file + assert k8s_obj is None diff --git a/test/functional/test_v1_route.py b/test/functional/test_v1_route.py index 3ff3ec64..e898bf2d 100644 --- a/test/functional/test_v1_route.py +++ b/test/functional/test_v1_route.py @@ -87,4 +87,4 @@ def test_remove_route(ansible_helper, route): namespace = route.metadata.namespace ansible_helper.delete_object(name, namespace) k8s_obj = ansible_helper.get_object(name, namespace) - assert k8s_obj is None \ No newline at end of file + assert k8s_obj is None diff --git a/test/functional/test_v1_service.py b/test/functional/test_v1_service.py index 7a1893f4..5c1789b7 100644 --- a/test/functional/test_v1_service.py +++ b/test/functional/test_v1_service.py @@ -91,4 +91,4 @@ def test_remove_service(ansible_helper, service): namespace = service.metadata.namespace ansible_helper.delete_object(name, namespace) k8s_obj = ansible_helper.get_object(name, namespace) - assert k8s_obj is None \ No newline at end of file + assert k8s_obj is None diff --git a/tox.ini b/tox.ini index 98d85008..d48b16d8 100644 --- a/tox.ini +++ b/tox.ini @@ -1,14 +1,15 @@ [tox] envlist = - py{27}-{lint} - py{27,35}-openshift{latest,15,14,13}-functional + py{27,35}-{lint} + py{27,35}-openshift{latest,36,15,14,13}-functional [testenv] usedevelop = True setenv = openshift13: openshift_version=v1.3.3 openshift14: openshift_version=v1.4.1 - openshift15: openshift_verison=v1.5.0-alpha.3 + openshift15: openshift_verison=v1.5.0-rc.0 + openshift36: openshift_version=v3.6.0-alpha.0 deps = -rrequirements.txt @@ -40,6 +41,7 @@ commands = [travis:env] OPENSHIFT_VERSION = latest: openshiftlatest + 3.6: openshift36 1.5: openshift15 1.4: openshift14 1.3: openshift13 @@ -78,7 +80,7 @@ OPENSHIFT_VERSION = # W503 line break before binary operator # The following matches github.com/ansible/ansible/tox.ini ignore = E123,E124,E127,E128,E201,E202,E203,E211,E221,E222,E225,E226,E228,E227,E231,E241,E251,E261,E262,E265,E266,E301,E302,E303,E402,E502,E713,E731,W391,W503 -# Matches line length set at github.com/ansible/ansible/tox.ini +# Matches line length set at github.com/ansible/ansible/tox.ini max-line-length = 160 -# Not worrying about style in the following +# Not worrying about style in the following exclude = .tox/*,test/*,openshift/test/*,openshift/client/models/*,openshift/client/apis/*,openshift/client/__init__.py,openshift/__init__.py