Added 'k8s_deployed' fixture
Created a separate fixture for Kubernetes deployment.
Modified existing k8s related fixtures / tests so they
use it now and updated templates with k8s environments.
Also this patch includes few minor changes:
* removed unused fixture 'deploy_openstack' which
was a full copy of 'openstack_deployed' fixture;
* removed unused modules imports;
* fixed typos and docstrings.
Change-Id: Ic35551f3e52913cede753b92e7d5a81f54570b01
Reviewed-on: https://review.gerrithub.io/365234
Reviewed-by: <vrovachev@mirantis.com>
Reviewed-by: Dennis Dmitriev <dis.xcom@gmail.com>
Tested-by: Tatyanka Leontovich <tleontovich@mirantis.com>
diff --git a/tcp_tests/fixtures/k8s_fixtures.py b/tcp_tests/fixtures/k8s_fixtures.py
new file mode 100644
index 0000000..bec38a5
--- /dev/null
+++ b/tcp_tests/fixtures/k8s_fixtures.py
@@ -0,0 +1,75 @@
+# Copyright 2017 Mirantis, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import pytest
+
+from tcp_tests.helpers import ext
+from tcp_tests import logger
+from tcp_tests.managers import k8smanager
+
+LOG = logger.logger
+
+
+@pytest.fixture(scope='function')
+def k8s_actions(config, underlay, salt_deployed):
+ """Fixture that provides various actions for K8S
+
+ :param config: fixture provides oslo.config
+ :param underlay: fixture provides underlay manager
+ :param salt_deployed: fixture provides salt manager
+ :rtype: K8SManager
+
+ For use in tests or fixtures to deploy a custom K8S
+ """
+ return k8smanager.K8SManager(config, underlay, salt_deployed)
+
+
+@pytest.mark.revert_snapshot(ext.SNAPSHOT.k8s_deployed)
+@pytest.fixture(scope='function')
+def k8s_deployed(revert_snapshot, request, config, hardware, underlay,
+ common_services_deployed, k8s_actions):
+ """Fixture to get or install k8s on environment
+
+ :param revert_snapshot: fixture that reverts snapshot that is specified
+ in test with @pytest.mark.revert_snapshot(<name>)
+ :param request: fixture provides pytest data
+ :param config: fixture provides oslo.config
+ :param hardware: fixture provides enviromnet manager
+ :param underlay: fixture provides underlay manager
+ :param common_services_deployed: fixture provides CommonServicesManager
+ :param k8s_actions: fixture provides K8SManager instance
+ :rtype: K8SManager
+
+ If config.k8s.k8s_installed is not set, this fixture assumes
+ that the k8s services were not installed, and do the following:
+ - install k8s services
+ - make snapshot with name 'k8s_deployed'
+ - return K8SManager instance
+
+ If config.k8s.k8s_installed was set, this fixture assumes that
+ the k8s services were already installed, and do the following:
+ - return K8SManager instance
+
+ If you want to revert 'k8s_deployed' snapshot, please use mark:
+ @pytest.mark.revert_snapshot("k8s_deployed")
+ """
+
+ # Deploy Kubernetes cluster
+ if not config.k8s.k8s_installed:
+ steps_path = config.k8s_deploy.k8s_steps_path
+ commands = underlay.read_template(steps_path)
+ k8s_actions.install(commands)
+ hardware.create_snapshot(ext.SNAPSHOT.k8s_deployed)
+
+ return k8s_actions
\ No newline at end of file
diff --git a/tcp_tests/fixtures/openstack_fixtures.py b/tcp_tests/fixtures/openstack_fixtures.py
index f69c247..ae3b9e8 100644
--- a/tcp_tests/fixtures/openstack_fixtures.py
+++ b/tcp_tests/fixtures/openstack_fixtures.py
@@ -28,13 +28,14 @@
@pytest.fixture(scope='function')
def openstack_actions(config, underlay, salt_deployed):
- """Fixture that provides various actions for K8S
+ """Fixture that provides various actions for OpenStack
:param config: fixture provides oslo.config
:param underlay: fixture provides underlay manager
- :rtype: K8SManager
+ :param salt_deployed: fixture provides salt manager
+ :rtype: OpenstackManager
- For use in tests or fixtures to deploy a custom K8S
+ For use in tests or fixtures to deploy a custom OpenStack
"""
return openstack_manager.OpenstackManager(config, underlay, salt_deployed)
@@ -52,7 +53,8 @@
:param config: fixture provides oslo.config
:param hardware: fixture provides enviromnet manager
:param underlay: fixture provides underlay manager
- :param tcp_actions: fixture provides OpenstackManager instance
+ :param common_services_deployed: fixture provides CommonServicesManager
+ :param openstack_actions: fixture provides OpenstackManager instance
:rtype: OpenstackManager
If config.openstack.openstack_installed is not set, this fixture assumes
@@ -68,54 +70,7 @@
If you want to revert 'openstack_deployed' snapshot, please use mark:
@pytest.mark.revert_snapshot("openstack_deployed")
"""
- # Create Salt cluster
- if not config.openstack.openstack_installed:
- steps_path = config.openstack_deploy.openstack_steps_path
- commands = underlay.read_template(steps_path)
- openstack_actions.install(commands)
- hardware.create_snapshot(ext.SNAPSHOT.openstack_deployed)
-
- else:
- # 1. hardware environment created and powered on
- # 2. config.underlay.ssh contains SSH access to provisioned nodes
- # (can be passed from external config with TESTS_CONFIGS variable)
- # 3. config.tcp.* options contain access credentials to the already
- # installed TCP API endpoint
- pass
-
- return openstack_actions
-
-
-@pytest.mark.revert_snapshot(ext.SNAPSHOT.openstack_deployed)
-@pytest.fixture(scope='function')
-def deploy_openstack(revert_snapshot, request, config,
- hardware, underlay, common_services_deployed,
- openstack_actions):
- """Fixture to get or install OpenStack services on environment
-
- :param revert_snapshot: fixture that reverts snapshot that is specified
- in test with @pytest.mark.revert_snapshot(<name>)
- :param request: fixture provides pytest data
- :param config: fixture provides oslo.config
- :param hardware: fixture provides enviromnet manager
- :param underlay: fixture provides underlay manager
- :param tcp_actions: fixture provides OpenstackManager instance
- :rtype: OpenstackManager
-
- If config.openstack.openstack_installed is not set, this fixture assumes
- that the openstack services were not installed, and do the following:
- - install openstack services
- - make snapshot with name 'openstack_deployed'
- - return OpenstackManager instance
-
- If config.openstack.openstack_installed was set, this fixture assumes that
- the openstack services were already installed, and do the following:
- - return OpenstackManager instance
-
- If you want to revert 'openstack_deployed' snapshot, please use mark:
- @pytest.mark.revert_snapshot("openstack_deployed")
- """
- # Create Salt cluster
+ # Deploy Openstack cluster
if not config.openstack.openstack_installed:
steps_path = config.openstack_deploy.openstack_steps_path
commands = underlay.read_template(steps_path)
diff --git a/tcp_tests/fixtures/virtlet_ceph_fixtures.py b/tcp_tests/fixtures/virtlet_ceph_fixtures.py
index 9a13cb4..a9cd3db 100644
--- a/tcp_tests/fixtures/virtlet_ceph_fixtures.py
+++ b/tcp_tests/fixtures/virtlet_ceph_fixtures.py
@@ -12,40 +12,34 @@
# License for the specific language governing permissions and limitations
# under the License.
-import os
-
import pytest
-import yaml
from tcp_tests import logger
from tcp_tests.helpers import ext
-from tcp_tests import settings
from tcp_tests.managers import virtlet_ceph_manager
LOG = logger.logger
@pytest.fixture(scope='function')
-def virtlet_ceph_actions(config, underlay, salt_actions):
+def virtlet_ceph_actions(config, underlay):
"""Fixture that provides various actions for Virtlet project
:param config: fixture provides oslo.config
:param underlay: fixture provides underlay manager
:rtype: VirtletCephManager
"""
- return virtlet_ceph_manager.VirtletCephManager(config, underlay, salt_actions)
+ return virtlet_ceph_manager.VirtletCephManager(config, underlay)
@pytest.mark.revert_snapshot(ext.SNAPSHOT.virtlet_ceph_deployed)
@pytest.fixture(scope='function')
-def virtlet_ceph_deployed(revert_snapshot, request, config,
- hardware, underlay, common_services_deployed,
+def virtlet_ceph_deployed(revert_snapshot, config, hardware, underlay,
virtlet_deployed, virtlet_ceph_actions):
"""Fixture to get or install Virtlet project on the environment
:param revert_snapshot: fixture that reverts snapshot that is specified
in test with @pytest.mark.revert_snapshot(<name>)
- :param request: fixture provides pytest data
:param config: fixture provides oslo.config
:param hardware: fixture provides enviromnet manager
:param underlay: fixture provides underlay manager
@@ -67,7 +61,7 @@
If you want to revert 'virtlet_ceph_deployed' snapshot, please use mark:
@pytest.mark.revert_snapshot("virtlet_ceph_deployed")
"""
- # Create Salt cluster
+ # Deploy Virtlet with Ceph for Kubernetes
if not config.virtlet.ceph_installed:
steps_path = config.virtlet_deploy.virtlet_ceph_steps_path
commands = underlay.read_template(steps_path)
diff --git a/tcp_tests/fixtures/virtlet_fixtures.py b/tcp_tests/fixtures/virtlet_fixtures.py
index f70a201..301800e 100644
--- a/tcp_tests/fixtures/virtlet_fixtures.py
+++ b/tcp_tests/fixtures/virtlet_fixtures.py
@@ -12,43 +12,38 @@
# License for the specific language governing permissions and limitations
# under the License.
-import os
-
import pytest
-import yaml
from tcp_tests import logger
from tcp_tests.helpers import ext
-from tcp_tests import settings
from tcp_tests.managers import virtlet_manager
LOG = logger.logger
@pytest.fixture(scope='function')
-def virtlet_actions(config, underlay, salt_actions):
+def virtlet_actions(config, underlay):
"""Fixture that provides various actions for Virtlet project
:param config: fixture provides oslo.config
:param underlay: fixture provides underlay manager
:rtype: VirtletManager
"""
- return virtlet_manager.VirtletManager(config, underlay, salt_actions)
+ return virtlet_manager.VirtletManager(config, underlay)
@pytest.mark.revert_snapshot(ext.SNAPSHOT.virtlet_deployed)
@pytest.fixture(scope='function')
-def virtlet_deployed(revert_snapshot, request, config,
- hardware, underlay, common_services_deployed,
- virtlet_actions):
+def virtlet_deployed(revert_snapshot, config, hardware, underlay,
+ k8s_deployed, virtlet_actions):
"""Fixture to get or install Virtlet project on the environment
:param revert_snapshot: fixture that reverts snapshot that is specified
in test with @pytest.mark.revert_snapshot(<name>)
- :param request: fixture provides pytest data
:param config: fixture provides oslo.config
:param hardware: fixture provides enviromnet manager
:param underlay: fixture provides underlay manager
+ :param k8s_deployed: fixture provides K8SManager instance
:param virtlet_actions: fixture provides VirtletManager instance
:rtype: VirtletManager
@@ -66,7 +61,7 @@
If you want to revert 'virtlet_deployed' snapshot, please use mark:
@pytest.mark.revert_snapshot("virtlet_deployed")
"""
- # Create Salt cluster
+ # Deploy Virtlet for Kubernetes
if not config.virtlet.virtlet_installed:
steps_path = config.virtlet_deploy.virtlet_steps_path
commands = underlay.read_template(steps_path)
diff --git a/tcp_tests/helpers/ext.py b/tcp_tests/helpers/ext.py
index 470206b..518f483 100644
--- a/tcp_tests/helpers/ext.py
+++ b/tcp_tests/helpers/ext.py
@@ -42,6 +42,7 @@
'sl_deployed',
'virtlet_deployed',
'virtlet_ceph_deployed',
+ 'k8s_deployed'
)
LOG_LEVELS = enum(
diff --git a/tcp_tests/managers/k8s/__init__.py b/tcp_tests/managers/k8s/__init__.py
new file mode 100644
index 0000000..bd76aa7
--- /dev/null
+++ b/tcp_tests/managers/k8s/__init__.py
@@ -0,0 +1,20 @@
+# Copyright 2017 Mirantis, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+
+import urllib3
+
+from tcp_tests.managers.k8s.cluster import K8sCluster
+
+__all__ = ['K8sCluster']
+
+urllib3.disable_warnings() # Supress https insecure warning
diff --git a/tcp_tests/managers/k8s/base.py b/tcp_tests/managers/k8s/base.py
new file mode 100644
index 0000000..7adb41a
--- /dev/null
+++ b/tcp_tests/managers/k8s/base.py
@@ -0,0 +1,108 @@
+# Copyright 2017 Mirantis, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+
+
+class K8sBaseResource(object):
+ """docstring for K8sBaseResource"""
+
+ def __init__(self, manager, data):
+ self._manager = manager
+ self._add_details(data)
+
+ def __repr__(self):
+ reprkeys = sorted(k
+ for k in self.__dict__.keys()
+ if k[0] != '_' and
+ k not in ['manager'])
+ info = ", ".join("%s=%s" % (k, getattr(self, k)) for k in reprkeys)
+ return "<%s %s>" % (self.__class__.__name__, info)
+
+ @property
+ def api_version(self):
+ return self._data.api_version
+
+ def _add_details(self, data):
+ self._data = data
+ for k in [k for k in dir(data)
+ if not any((k.startswith('_'), k in ('to_dict', 'to_str')))]:
+ try:
+ setattr(self, k, getattr(data, k))
+ except AttributeError:
+ # In this case we already defined the attribute on the class
+ pass
+
+ def __eq__(self, other):
+ if not isinstance(other, K8sBaseResource):
+ return NotImplemented
+ # two resources of different types are not equal
+ if not isinstance(other, self.__class__):
+ return False
+ return self._info == other._info
+
+
+class K8sBaseManager(object):
+
+ resource_class = None
+
+ def __init__(self, api, namespace):
+ self._api = api
+ self._namespace = namespace
+ self._raw = None
+
+ @property
+ def api(self):
+ return self._api
+
+ @property
+ def namespace(self):
+ return self._namespace
+
+ def get(self, *args, **kwargs):
+ if not hasattr(self, '_get'):
+ raise NotImplementedError(
+ '{} does not have {}'.format(self, '_get'))
+
+ return self.resource_class(self, self._get(*args, **kwargs))
+
+ def list(self, *args, **kwargs):
+ if not hasattr(self, '_list'):
+ raise NotImplementedError(
+ '{} does not have {}'.format(self, '_list'))
+
+ lst = self._list(*args, **kwargs)
+
+ return [self.resource_class(self, item) for item in lst.items]
+
+ def create(self, *args, **kwargs):
+ if not hasattr(self, '_create'):
+ raise NotImplementedError(
+ '{} does not have {}'.format(self, '_create'))
+ return self.resource_class(self, self._create(*args, **kwargs))
+
+ def replace(self, *args, **kwargs):
+ if not hasattr(self, '_replace'):
+ raise NotImplementedError(
+ '{} does not have {}'.format(self, '_replace'))
+ return self._replace(*args, **kwargs)
+
+ def delete(self, *args, **kwargs):
+ if not hasattr(self, '_delete'):
+ raise NotImplementedError(
+ '{} does not have {}'.format(self, '_delete'))
+ return self._delete(*args, **kwargs)
+
+ def deletecollection(self, *args, **kwargs):
+ if not hasattr(self, '_deletecollection'):
+ raise NotImplementedError(
+ '{} does not have {}'.format(self, '_deletecollection'))
+ return self._deletecollection(*args, **kwargs)
diff --git a/tcp_tests/managers/k8s/cluster.py b/tcp_tests/managers/k8s/cluster.py
new file mode 100644
index 0000000..424ab32
--- /dev/null
+++ b/tcp_tests/managers/k8s/cluster.py
@@ -0,0 +1,110 @@
+# Copyright 2017 Mirantis, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+
+
+import base64
+import ssl
+
+from k8sclient.client import api_client
+from k8sclient.client.apis import apiv_api
+from k8sclient.client.apis import apisextensionsvbeta_api
+from k8sclient.client.apis import apisbatchv_api
+
+from tcp_tests.managers.k8s.componentstatuses import \
+ K8sComponentStatusManager
+from tcp_tests.managers.k8s.daemonsets import K8sDaemonSetManager
+from tcp_tests.managers.k8s.deployments import K8sDeploymentManager
+from tcp_tests.managers.k8s.endpoints import K8sEndpointManager
+from tcp_tests.managers.k8s.events import K8sEventManager
+from tcp_tests.managers.k8s.horizontalpodautoscalers import \
+ K8sHorizontalPodAutoscalerManager
+from tcp_tests.managers.k8s.ingresses import K8sIngressManager
+from tcp_tests.managers.k8s.jobs import K8sJobManager
+from tcp_tests.managers.k8s.limitranges import K8sLimitRangeManager
+from tcp_tests.managers.k8s.namespaces import K8sNamespaceManager
+from tcp_tests.managers.k8s.nodes import K8sNodeManager
+from tcp_tests.managers.k8s.persistentvolumeclaims import \
+ K8sPersistentVolumeClaimManager
+from tcp_tests.managers.k8s.persistentvolumes import \
+ K8sPersistentVolumeManager
+from tcp_tests.managers.k8s.pods import K8sPodManager
+from tcp_tests.managers.k8s.replicationcontrollers import \
+ K8sReplicationControllerManager
+from tcp_tests.managers.k8s.resourcequotas import K8sResourceQuotaManager
+from tcp_tests.managers.k8s.secrets import K8sSecretManager
+from tcp_tests.managers.k8s.serviceaccounts import \
+ K8sServiceAccountManager
+from tcp_tests.managers.k8s.services import K8sServiceManager
+from tcp_tests.managers.k8s.replicasets import K8sReplicaSetManager
+
+
+class K8sCluster(object):
+ """docstring for K8sCluster"""
+
+ def __init__(self, schema="https", user=None, password=None,
+ host='localhost', port='443', default_namespace='default'):
+ if user and password:
+ auth_string = '%s:%s' % (user, password)
+ auth = base64.encodestring(auth_string.encode()).decode()[:-1]
+ auth = "Basic {}".format(auth)
+ self._client = api_client.ApiClient(
+ '{schema}://{host}:{port}/'.format(
+ schema=schema, host=host, port=port))
+ self._client.set_default_header('Authorization', auth)
+ restcli_impl = self._client.RESTClient.IMPL
+ restcli_impl.ssl_pool_manager.connection_pool_kw['cert_reqs'] = \
+ ssl.CERT_NONE
+
+ else:
+ self._client = api_client.ApiClient(
+ '{schema}://{host}:{port}/'.format(
+ schema=schema, host=host, port=port))
+ self._api = apiv_api.ApivApi(self._client)
+ self._bapi = apisbatchv_api.ApisbatchvApi(self._client)
+ self._eapi = apisextensionsvbeta_api.ApisextensionsvbetaApi(
+ self._client)
+ self._default_namespace = default_namespace
+
+ self.nodes = K8sNodeManager(self._api, self._default_namespace)
+ self.pods = K8sPodManager(self._api, self._default_namespace)
+ self.endpoints = K8sEndpointManager(self._api, self._default_namespace)
+ self.namespaces = K8sNamespaceManager(self._api,
+ self._default_namespace)
+ self.services = K8sServiceManager(self._api, self._default_namespace)
+ self.serviceaccounts = K8sServiceAccountManager(
+ self._api, self._default_namespace)
+ self.secrets = K8sSecretManager(self._api, self._default_namespace)
+ self.events = K8sEventManager(self._api, self._default_namespace)
+ self.limitranges = K8sLimitRangeManager(self._api,
+ self._default_namespace)
+ self.jobs = K8sJobManager(self._bapi, self._default_namespace)
+ self.daemonsets = K8sDaemonSetManager(self._eapi,
+ self._default_namespace)
+ self.ingresses = K8sIngressManager(self._eapi, self._default_namespace)
+ self.deployments = K8sDeploymentManager(self._eapi,
+ self._default_namespace)
+ self.horizontalpodautoscalers = K8sHorizontalPodAutoscalerManager(
+ self._eapi, self._default_namespace)
+ self.componentstatuses = K8sComponentStatusManager(
+ self._api, self._default_namespace)
+ self.resourcequotas = K8sResourceQuotaManager(
+ self._api, self._default_namespace)
+ self.replicationcontrollers = K8sReplicationControllerManager(
+ self._api, self._default_namespace)
+ self.pvolumeclaims = K8sPersistentVolumeClaimManager(
+ self._api, self._default_namespace)
+ self.pvolumes = K8sPersistentVolumeManager(
+ self._api, self._default_namespace)
+ self.replicasets = K8sReplicaSetManager(
+ self._eapi, self._default_namespace
+ )
diff --git a/tcp_tests/managers/k8s/componentstatuses.py b/tcp_tests/managers/k8s/componentstatuses.py
new file mode 100644
index 0000000..a991576
--- /dev/null
+++ b/tcp_tests/managers/k8s/componentstatuses.py
@@ -0,0 +1,39 @@
+# Copyright 2017 Mirantis, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+
+
+from tcp_tests.managers.k8s.base import K8sBaseResource
+from tcp_tests.managers.k8s.base import K8sBaseManager
+
+
+class K8sComponentStatus(K8sBaseResource):
+ """docstring for K8sComponentStatus"""
+
+ def __repr__(self):
+ return "<K8sComponentStatus: %s>" % self.name
+
+ @property
+ def name(self):
+ return self.metadata.name
+
+
+class K8sComponentStatusManager(K8sBaseManager):
+ """docstring for ClassName"""
+
+ resource_class = K8sComponentStatus
+
+ def _get(self, name, **kwargs):
+ return self.api.read_namespaced_component_status(name=name, **kwargs)
+
+ def _list(self, **kwargs):
+ return self.api.list_namespaced_component_status(**kwargs)
diff --git a/tcp_tests/managers/k8s/daemonsets.py b/tcp_tests/managers/k8s/daemonsets.py
new file mode 100644
index 0000000..dc2c5f7
--- /dev/null
+++ b/tcp_tests/managers/k8s/daemonsets.py
@@ -0,0 +1,79 @@
+# Copyright 2017 Mirantis, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+
+
+from tcp_tests.managers.k8s.base import K8sBaseResource
+from tcp_tests.managers.k8s.base import K8sBaseManager
+
+
+class K8sDaemonSet(K8sBaseResource):
+ """docstring for K8sDaemonSet"""
+
+ def __repr__(self):
+ return "<K8sDaemonSet: %s>" % self.name
+
+ @property
+ def name(self):
+ return self.metadata.name
+
+ @property
+ def namespace(self):
+ return self.metadata.namespace
+
+
+class K8sDaemonSetManager(K8sBaseManager):
+ """docstring for ClassName"""
+
+ resource_class = K8sDaemonSet
+
+ def _get(self, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.read_namespaced_daemon_set(
+ name=name, namespace=namespace, **kwargs)
+
+ def _list(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.list_namespaced_daemon_set(
+ namespace=namespace, **kwargs)
+
+ def _full_list(self, **kwargs):
+ return self.api.list_daemon_set(**kwargs)
+
+ def _create(self, body, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.create_namespaced_daemon_set(
+ body=body, namespace=namespace, **kwargs)
+
+ def _replace(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.replace_namespaced_daemon_set(
+ body=body, name=name, namespace=namespace, **kwargs)
+
+ def _delete(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.delete_namespaced_daemon_set(
+ body=body, name=name, namespace=namespace, **kwargs)
+
+ def _deletecollection(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.deletecollection_namespaced_daemon_set(
+ namespace=namespace, **kwargs)
+
+ def full_list(self, *args, **kwargs):
+ lst = self._full_list(*args, **kwargs)
+ return [self.resource_class(self, item) for item in lst.items]
+
+ def update(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.patch_namespaced_daemon_set(
+ body=body, name=name, namespace=namespace, **kwargs)
diff --git a/tcp_tests/managers/k8s/deployments.py b/tcp_tests/managers/k8s/deployments.py
new file mode 100644
index 0000000..1dbd1d2
--- /dev/null
+++ b/tcp_tests/managers/k8s/deployments.py
@@ -0,0 +1,70 @@
+# Copyright 2017 Mirantis, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+
+
+from tcp_tests.managers.k8s.base import K8sBaseResource
+from tcp_tests.managers.k8s.base import K8sBaseManager
+
+
+class K8sDeployment(K8sBaseResource):
+ """docstring for K8sDeployment"""
+
+ def __repr__(self):
+ return "<K8sDeployment: %s>" % self.name
+
+ @property
+ def name(self):
+ return self.metadata.name
+
+
+class K8sDeploymentManager(K8sBaseManager):
+ """docstring for ClassName"""
+
+ resource_class = K8sDeployment
+
+ def _get(self, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.read_namespaced_deployment(
+ name=name, namespace=namespace, **kwargs)
+
+ def _list(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.list_namespaced_deployment(
+ namespace=namespace, **kwargs)
+
+ def _full_list(self, **kwargs):
+ return self.api.list_deployment(**kwargs)
+
+ def _create(self, body, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.create_namespaced_deployment(
+ body=body, namespace=namespace, **kwargs)
+
+ def _replace(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.replace_namespaced_deployment(
+ body=body, name=name, namespace=namespace, **kwargs)
+
+ def _delete(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.delete_namespaced_deployment(
+ body=body, name=name, namespace=namespace, **kwargs)
+
+ def _deletecollection(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.deletecollection_namespaced_deployment(
+ namespace=namespace, **kwargs)
+
+ def full_list(self, *args, **kwargs):
+ lst = self._full_list(*args, **kwargs)
+ return [self.resource_class(self, item) for item in lst.items]
diff --git a/tcp_tests/managers/k8s/endpoints.py b/tcp_tests/managers/k8s/endpoints.py
new file mode 100644
index 0000000..ed1066e
--- /dev/null
+++ b/tcp_tests/managers/k8s/endpoints.py
@@ -0,0 +1,70 @@
+# Copyright 2017 Mirantis, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+
+
+from tcp_tests.managers.k8s.base import K8sBaseResource
+from tcp_tests.managers.k8s.base import K8sBaseManager
+
+
+class K8sEndpoint(K8sBaseResource):
+ """docstring for K8sEndpoint"""
+
+ def __repr__(self):
+ return "<K8sEndpoint: %s>" % self.name
+
+ @property
+ def name(self):
+ return self.metadata.name
+
+
+class K8sEndpointManager(K8sBaseManager):
+ """docstring for ClassName"""
+
+ resource_class = K8sEndpoint
+
+ def _get(self, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.read_namespaced_endpoints(
+ name=name, namespace=namespace, **kwargs)
+
+ def _list(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.list_namespaced_endpoints(
+ namespace=namespace, **kwargs)
+
+ def _full_list(self, **kwargs):
+ return self.api.list_endpoints(**kwargs)
+
+ def _create(self, body, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.create_namespaced_endpoints(
+ body=body, namespace=namespace, **kwargs)
+
+ def _replace(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.replace_namespaced_endpoints(
+ body=body, name=body, namespace=namespace, **kwargs)
+
+ def _delete(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.delete_namespaced_endpoints(
+ body=body, name=name, namespace=namespace, **kwargs)
+
+ def _deletecollection(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.deletecollection_namespaced_endpoints(
+ namespace=namespace, **kwargs)
+
+ def full_list(self, *args, **kwargs):
+ lst = self._full_list(*args, **kwargs)
+ return [self.resource_class(self, item) for item in lst.items]
diff --git a/tcp_tests/managers/k8s/events.py b/tcp_tests/managers/k8s/events.py
new file mode 100644
index 0000000..099e9e4
--- /dev/null
+++ b/tcp_tests/managers/k8s/events.py
@@ -0,0 +1,69 @@
+# Copyright 2017 Mirantis, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+
+
+from tcp_tests.managers.k8s.base import K8sBaseResource
+from tcp_tests.managers.k8s.base import K8sBaseManager
+
+
+class K8sEvent(K8sBaseResource):
+ """docstring for K8sEvent"""
+
+ def __repr__(self):
+ return "<K8sEvent: %s>" % self.name
+
+ @property
+ def name(self):
+ return self.metadata.name
+
+
+class K8sEventManager(K8sBaseManager):
+ """docstring for ClassName"""
+
+ resource_class = K8sEvent
+
+ def _get(self, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.read_namespaced_event(
+ name=name, namespace=namespace, **kwargs)
+
+ def _list(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.list_namespaced_event(namespace=namespace, **kwargs)
+
+ def _full_list(self, **kwargs):
+ return self.api.list_event(**kwargs)
+
+ def _create(self, body, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.create_namespaced_event(
+ body=body, namespace=namespace, **kwargs)
+
+ def _replace(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.replace_namespaced_event(
+ body=body, name=name, namespace=namespace, **kwargs)
+
+ def _delete(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.delete_namespaced_event(
+ body=body, name=name, namespace=namespace, **kwargs)
+
+ def _deletecollection(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.deletecollection_namespaced_event(
+ namespace=namespace, **kwargs)
+
+ def full_list(self, *args, **kwargs):
+ lst = self._full_list(*args, **kwargs)
+ return [self.resource_class(self, item) for item in lst.items]
diff --git a/tcp_tests/managers/k8s/horizontalpodautoscalers.py b/tcp_tests/managers/k8s/horizontalpodautoscalers.py
new file mode 100644
index 0000000..6ce78e7
--- /dev/null
+++ b/tcp_tests/managers/k8s/horizontalpodautoscalers.py
@@ -0,0 +1,70 @@
+# Copyright 2017 Mirantis, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+
+
+from tcp_tests.managers.k8s.base import K8sBaseResource
+from tcp_tests.managers.k8s.base import K8sBaseManager
+
+
+class K8sHorizontalPodAutoscaler(K8sBaseResource):
+ """docstring for K8sHorizontalPodAutoscaler"""
+
+ def __repr__(self):
+ return "<K8sHorizontalPodAutoscaler: %s>" % self.name
+
+ @property
+ def name(self):
+ return self.metadata.name
+
+
+class K8sHorizontalPodAutoscalerManager(K8sBaseManager):
+ """docstring for ClassName"""
+
+ resource_class = K8sHorizontalPodAutoscaler
+
+ def _get(self, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.read_namespaced_horizontal_pod_autoscaler(
+ name=name, namespace=namespace, **kwargs)
+
+ def _list(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.list_namespaced_horizontal_pod_autoscaler(
+ namespace=namespace, **kwargs)
+
+ def _full_list(self, **kwargs):
+ return self.api.list_horizontal_pod_autoscaler(**kwargs)
+
+ def _create(self, body, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.create_namespaced_horizontal_pod_autoscaler(
+ body=body, namespace=namespace, **kwargs)
+
+ def _replace(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.replace_namespaced_horizontal_pod_autoscaler(
+ body=body, name=name, namespace=namespace, **kwargs)
+
+ def _delete(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.delete_namespaced_horizontal_pod_autoscaler(
+ body=body, name=name, namespace=namespace, **kwargs)
+
+ def _deletecollection(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.deletecollection_namespaced_horizontal_pod_autoscaler(
+ namespace=namespace, **kwargs)
+
+ def full_list(self, *args, **kwargs):
+ lst = self._full_list(*args, **kwargs)
+ return [self.resource_class(self, item) for item in lst.items]
diff --git a/tcp_tests/managers/k8s/ingresses.py b/tcp_tests/managers/k8s/ingresses.py
new file mode 100644
index 0000000..81b240e
--- /dev/null
+++ b/tcp_tests/managers/k8s/ingresses.py
@@ -0,0 +1,70 @@
+# Copyright 2017 Mirantis, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+
+
+from tcp_tests.managers.k8s.base import K8sBaseResource
+from tcp_tests.managers.k8s.base import K8sBaseManager
+
+
+class K8sIngress(K8sBaseResource):
+ """docstring for K8sIngress"""
+
+ def __repr__(self):
+ return "<K8sIngress: %s>" % self.name
+
+ @property
+ def name(self):
+ return self.metadata.name
+
+
+class K8sIngressManager(K8sBaseManager):
+ """docstring for ClassName"""
+
+ resource_class = K8sIngress
+
+ def _get(self, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.read_namespaced_ingress(
+ name=name, namespace=namespace, **kwargs)
+
+ def _list(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.list_namespaced_ingress(
+ namespace=namespace, **kwargs)
+
+ def _full_list(self, **kwargs):
+ return self.api.list_ingress(**kwargs)
+
+ def _create(self, body, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.create_namespaced_ingress(
+ body=body, namespace=namespace, **kwargs)
+
+ def _replace(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.replace_namespaced_ingress(
+ body=body, name=name, namespace=namespace, **kwargs)
+
+ def _delete(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.delete_namespaced_ingress(
+ body=body, name=name, namespace=namespace, **kwargs)
+
+ def _deletecollection(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.deletecollection_namespaced_ingress(
+ namespace=namespace, **kwargs)
+
+ def full_list(self, *args, **kwargs):
+ lst = self._full_list(*args, **kwargs)
+ return [self.resource_class(self, item) for item in lst.items]
diff --git a/tcp_tests/managers/k8s/jobs.py b/tcp_tests/managers/k8s/jobs.py
new file mode 100644
index 0000000..a2dbb81
--- /dev/null
+++ b/tcp_tests/managers/k8s/jobs.py
@@ -0,0 +1,69 @@
+# Copyright 2017 Mirantis, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+
+
+from tcp_tests.managers.k8s.base import K8sBaseResource
+from tcp_tests.managers.k8s.base import K8sBaseManager
+
+
+class K8sJob(K8sBaseResource):
+ """docstring for K8sJob"""
+
+ def __repr__(self):
+ return "<K8sJob: %s>" % self.name
+
+ @property
+ def name(self):
+ return self.metadata.name
+
+
+class K8sJobManager(K8sBaseManager):
+ """docstring for ClassName"""
+
+ resource_class = K8sJob
+
+ def _get(self, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.read_namespaced_job(
+ name=name, namespace=namespace, **kwargs)
+
+ def _list(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.list_namespaced_job(namespace=namespace, **kwargs)
+
+ def _create(self, body, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.create_namespaced_job(
+ body=body, namespace=namespace, **kwargs)
+
+ def _replace(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.replace_namespaced_job(
+ body=body, name=name, namespace=namespace, **kwargs)
+
+ def _delete(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.delete_namespaced_job(
+ body=body, name=name, namespace=namespace, **kwargs)
+
+ def _deletecollection(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.deletecollection_namespaced_job(
+ namespace=namespace, **kwargs)
+
+ def full_list(self, *args, **kwargs):
+ lst = self._full_list(*args, **kwargs)
+ return [self.resource_class(self, item) for item in lst.items]
+
+ def _full_list(self, **kwargs):
+ return self.api.list_job(**kwargs)
diff --git a/tcp_tests/managers/k8s/limitranges.py b/tcp_tests/managers/k8s/limitranges.py
new file mode 100644
index 0000000..7136300
--- /dev/null
+++ b/tcp_tests/managers/k8s/limitranges.py
@@ -0,0 +1,63 @@
+# Copyright 2017 Mirantis, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+
+
+from tcp_tests.managers.k8s.base import K8sBaseResource
+from tcp_tests.managers.k8s.base import K8sBaseManager
+
+
+class K8sLimitRange(K8sBaseResource):
+ """docstring for K8sLimitRange"""
+
+ def __repr__(self):
+ return "<K8sLimitRange: %s>" % self.name
+
+ @property
+ def name(self):
+ return self.metadata.name
+
+
+class K8sLimitRangeManager(K8sBaseManager):
+ """docstring for ClassName"""
+
+ resource_class = K8sLimitRange
+
+ def _get(self, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.read_namespaced_limit_range(
+ name=name, namespace=namespace, **kwargs)
+
+ def _list(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.list_namespaced_limit_range(
+ namespace=namespace, **kwargs)
+
+ def _create(self, body, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.create_namespaced_limit_range(
+ body=body, namespace=namespace, **kwargs)
+
+ def _replace(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.replace_namespaced_limit_range(
+ body=body, name=name, namespace=namespace, **kwargs)
+
+ def _delete(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.delete_namespaced_limit_range(
+ body=body, name=name, namespace=namespace, **kwargs)
+
+ def _deletecollection(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.deletecollection_namespaced_limit_range(
+ namespace=namespace, **kwargs)
diff --git a/tcp_tests/managers/k8s/namespaces.py b/tcp_tests/managers/k8s/namespaces.py
new file mode 100644
index 0000000..8c36302
--- /dev/null
+++ b/tcp_tests/managers/k8s/namespaces.py
@@ -0,0 +1,51 @@
+# Copyright 2017 Mirantis, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+
+
+from tcp_tests.managers.k8s.base import K8sBaseResource
+from tcp_tests.managers.k8s.base import K8sBaseManager
+
+
+class K8sNamespace(K8sBaseResource):
+ """docstring for ClassName"""
+
+ def __repr__(self):
+ return "<K8sNamespace: %s>" % self.name
+
+ @property
+ def name(self):
+ return self.metadata.name
+
+
+class K8sNamespaceManager(K8sBaseManager):
+ """docstring for ClassName"""
+
+ resource_class = K8sNamespace
+
+ def _get(self, name, **kwargs):
+ return self.api.read_namespaced_namespace(name, **kwargs)
+
+ def _list(self, **kwargs):
+ return self.api.list_namespaced_namespace(**kwargs)
+
+ def _create(self, body, **kwargs):
+ return self.api.create_namespaced_namespace(body, **kwargs)
+
+ def _replace(self, body, name, **kwargs):
+ return self.api.replace_namespaced_namespace(body, name, **kwargs)
+
+ def _delete(self, body, name, **kwargs):
+ return self.api.delete_namespaced_namespace(body, name, **kwargs)
+
+ def _deletecollection(self, **kwargs):
+ return self.api.deletecollection_namespaced_namespace(**kwargs)
diff --git a/tcp_tests/managers/k8s/nodes.py b/tcp_tests/managers/k8s/nodes.py
new file mode 100644
index 0000000..c6d4dbe
--- /dev/null
+++ b/tcp_tests/managers/k8s/nodes.py
@@ -0,0 +1,81 @@
+# Copyright 2017 Mirantis, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+
+
+from tcp_tests.managers.k8s.base import K8sBaseResource
+from tcp_tests.managers.k8s.base import K8sBaseManager
+
+
+class K8sNode(K8sBaseResource):
+ """docstring for ClassName"""
+
+ def __repr__(self):
+ return "<K8sNode: %s>" % self.name
+
+ @property
+ def name(self):
+ return self.metadata.name
+
+ @property
+ def labels(self):
+ return self.metadata.labels
+
+ @labels.setter
+ def labels(self, labels):
+ current_labels = {
+ label: None for label in self.labels
+ }
+ current_labels.update(labels)
+ self.add_labels(labels=current_labels)
+
+ def add_labels(self, labels):
+ if not isinstance(labels, dict):
+ raise TypeError("labels must be a dict!")
+ body = {
+ "metadata":
+ {
+ "labels": labels
+ }
+ }
+ self._add_details(self._manager.update(body=body, name=self.name))
+
+ def remove_labels(self, list_labels):
+ labels = {label: None for label in list_labels}
+ self.add_labels(labels=labels)
+
+
+class K8sNodeManager(K8sBaseManager):
+ """docstring for ClassName"""
+
+ resource_class = K8sNode
+
+ def _get(self, name, **kwargs):
+ return self.api.read_namespaced_node(name=name, **kwargs)
+
+ def _list(self, **kwargs):
+ return self.api.list_namespaced_node(**kwargs)
+
+ def _create(self, body, **kwargs):
+ return self.api.create_namespaced_node(body=body, **kwargs)
+
+ def _replace(self, body, name, **kwargs):
+ return self.api.replace_namespaced_node(body=body, name=name, **kwargs)
+
+ def _delete(self, body, name, **kwargs):
+ return self.api.delete_namespaced_node(body=body, name=name, **kwargs)
+
+ def _deletecollection(self, **kwargs):
+ return self.api.deletecollection_namespaced_node(**kwargs)
+
+ def update(self, body, name, **kwargs):
+ return self.api.patch_namespaced_node(body=body, name=name, **kwargs)
diff --git a/tcp_tests/managers/k8s/persistentvolumeclaims.py b/tcp_tests/managers/k8s/persistentvolumeclaims.py
new file mode 100644
index 0000000..f28f622
--- /dev/null
+++ b/tcp_tests/managers/k8s/persistentvolumeclaims.py
@@ -0,0 +1,63 @@
+# Copyright 2017 Mirantis, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+
+
+from tcp_tests.managers.k8s.base import K8sBaseResource
+from tcp_tests.managers.k8s.base import K8sBaseManager
+
+
+class K8sPersistentVolumeClaim(K8sBaseResource):
+ """docstring for K8sPersistentVolumeClaim"""
+
+ def __repr__(self):
+ return "<K8sPersistentVolumeClaim: %s>" % self.name
+
+ @property
+ def name(self):
+ return self.metadata.name
+
+
+class K8sPersistentVolumeClaimManager(K8sBaseManager):
+ """docstring for ClassName"""
+
+ resource_class = K8sPersistentVolumeClaim
+
+ def _get(self, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.read_namespaced_persistent_volume_claim(
+ name=name, namespace=namespace, **kwargs)
+
+ def _list(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.list_namespaced_persistent_volume_claim(
+ namespace=namespace, **kwargs)
+
+ def _create(self, body, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.create_namespaced_persistent_volume_claim(
+ body=body, namespace=namespace, **kwargs)
+
+ def _replace(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.replace_namespaced_persistent_volume_claim(
+ body=body, name=name, namespace=namespace, **kwargs)
+
+ def _delete(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.delete_namespaced_persistent_volume_claim(
+ body=body, name=name, namespace=namespace, **kwargs)
+
+ def _deletecollection(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.deletecollection_namespaced_persistent_volume_claim(
+ namespace=namespace, **kwargs)
diff --git a/tcp_tests/managers/k8s/persistentvolumes.py b/tcp_tests/managers/k8s/persistentvolumes.py
new file mode 100644
index 0000000..8ab7ec2
--- /dev/null
+++ b/tcp_tests/managers/k8s/persistentvolumes.py
@@ -0,0 +1,57 @@
+# Copyright 2017 Mirantis, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+
+
+from tcp_tests.managers.k8s.base import K8sBaseResource
+from tcp_tests.managers.k8s.base import K8sBaseManager
+
+
+class K8sPersistentVolume(K8sBaseResource):
+ """docstring for K8sPersistentVolume"""
+
+ def __repr__(self):
+ return "<K8sPersistentVolume: %s>" % self.name
+
+ @property
+ def name(self):
+ return self.metadata.name
+
+
+class K8sPersistentVolumeManager(K8sBaseManager):
+ """docstring for ClassName"""
+
+ resource_class = K8sPersistentVolume
+
+ def _get(self, name, **kwargs):
+ return self.api.read_namespaced_persistent_volume(
+ name=name, **kwargs)
+
+ def _list(self, **kwargs):
+ return self.api.list_namespaced_persistent_volume(
+ **kwargs)
+
+ def _create(self, body, **kwargs):
+ return self.api.create_namespaced_persistent_volume(
+ body, **kwargs)
+
+ def _replace(self, body, name, **kwargs):
+ return self.api.replace_namespaced_persistent_volume(
+ body=body, name=name, **kwargs)
+
+ def _delete(self, body, name, **kwargs):
+ return self.api.delete_namespaced_persistent_volume(
+ body=body, name=name, **kwargs)
+
+ def _deletecollection(self, **kwargs):
+ return self.api.deletecollection_namespaced_persistent_volume(
+ **kwargs)
diff --git a/tcp_tests/managers/k8s/pods.py b/tcp_tests/managers/k8s/pods.py
new file mode 100644
index 0000000..94abc20
--- /dev/null
+++ b/tcp_tests/managers/k8s/pods.py
@@ -0,0 +1,108 @@
+# Copyright 2017 Mirantis, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+
+from devops.helpers import helpers
+
+from tcp_tests.managers.k8s.base import K8sBaseResource
+from tcp_tests.managers.k8s.base import K8sBaseManager
+
+
+class K8sPod(K8sBaseResource):
+ """docstring for K8sPod"""
+
+ def __repr__(self):
+ return "<K8sPod: %s>" % self.name
+
+ @property
+ def name(self):
+ return self.metadata.name
+
+ @property
+ def phase(self):
+ return self.status.phase
+
+ @property
+ def namespace(self):
+ return self.metadata.namespace
+
+ def wait_phase(self, phase, timeout=60, interval=5):
+ """Wait phase of pod_name from namespace while timeout
+
+ :param list or str: phase
+ :param int: timeout
+
+ :rtype: None
+ """
+ if isinstance(phase, str):
+ phase = [phase]
+
+ def check():
+ self._add_details(self._manager.get(name=self.name,
+ namespace=self.namespace))
+ return self.phase in phase
+
+ helpers.wait(check, timeout=timeout, interval=interval,
+ timeout_msg='Timeout waiting({timeout}s), pod {pod_name} '
+ 'is not in "{phase}" phase'.format(
+ timeout=timeout,
+ pod_name=self.name,
+ phase=phase))
+
+ def wait_running(self, timeout=60, interval=5):
+ self.wait_phase(['Running'], timeout=timeout, interval=interval)
+
+
+class K8sPodManager(K8sBaseManager):
+ """docstring for ClassName"""
+
+ resource_class = K8sPod
+
+ def _get(self, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.read_namespaced_pod(
+ name=name, namespace=namespace, **kwargs)
+
+ def _list(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.list_namespaced_pod(namespace=namespace, **kwargs)
+
+ def _create(self, body, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.create_namespaced_pod(
+ body=body, namespace=namespace, **kwargs)
+
+ def _replace(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.replace_namespaced_pod(
+ body=body, name=name, namespace=namespace, **kwargs)
+
+ def _delete(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ # NOTE: the following two lines should be deleted after
+ # serialization is fixed in python-k8sclient
+ if isinstance(body, self.resource_class):
+ body = body.swagger_types
+ return self.api.delete_namespaced_pod(
+ body=body, name=name, namespace=namespace, **kwargs)
+
+ def _deletecollection(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.deletecollection_namespaced_pod(
+ namespace=namespace, **kwargs)
+
+ def full_list(self, *args, **kwargs):
+ lst = self._full_list(*args, **kwargs)
+ return [self.resource_class(self, item) for item in lst.items]
+
+ def _full_list(self, **kwargs):
+ return self.api.list_pod(**kwargs)
diff --git a/tcp_tests/managers/k8s/replicasets.py b/tcp_tests/managers/k8s/replicasets.py
new file mode 100644
index 0000000..31b6db6
--- /dev/null
+++ b/tcp_tests/managers/k8s/replicasets.py
@@ -0,0 +1,70 @@
+# Copyright 2017 Mirantis, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+
+
+from tcp_tests.managers.k8s.base import K8sBaseResource
+from tcp_tests.managers.k8s.base import K8sBaseManager
+
+
+class K8sReplicaSet(K8sBaseResource):
+ """docstring for K8sPod"""
+
+ def __repr__(self):
+ return "<K8sPod: %s>" % self.name
+
+ @property
+ def name(self):
+ return self.metadata.name
+
+
+class K8sReplicaSetManager(K8sBaseManager):
+ """docstring for ClassName"""
+
+ resource_class = K8sReplicaSet
+
+ def _get(self, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.read_namespaced_replica_set(
+ name=name, namespace=namespace, **kwargs)
+
+ def _list(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.list_namespaced_replica_set(namespace=namespace,
+ **kwargs)
+
+ def _create(self, body, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.create_namespaced_replica_set(
+ body=body, namespace=namespace, **kwargs)
+
+ def _replace(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.replace_namespaced_replica_set(
+ body=body, name=name, namespace=namespace, **kwargs)
+
+ def _delete(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.delete_namespaced_replica_set(
+ body=body, name=name, namespace=namespace, **kwargs)
+
+ def _deletecollection(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.deletecollection_namespaced_replica_set(
+ namespace=namespace, **kwargs)
+
+ def full_list(self, *args, **kwargs):
+ lst = self._full_list(*args, **kwargs)
+ return [self.resource_class(self, item) for item in lst.items]
+
+ def _full_list(self, **kwargs):
+ return self.api.list_replica_set(**kwargs)
diff --git a/tcp_tests/managers/k8s/replicationcontrollers.py b/tcp_tests/managers/k8s/replicationcontrollers.py
new file mode 100644
index 0000000..6cf7da4
--- /dev/null
+++ b/tcp_tests/managers/k8s/replicationcontrollers.py
@@ -0,0 +1,70 @@
+# Copyright 2017 Mirantis, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+
+
+from tcp_tests.managers.k8s.base import K8sBaseResource
+from tcp_tests.managers.k8s.base import K8sBaseManager
+
+
+class K8sReplicationController(K8sBaseResource):
+ """docstring for K8sReplicationController"""
+
+ def __repr__(self):
+ return "<K8sReplicationController: %s>" % self.name
+
+ @property
+ def name(self):
+ return self.metadata.name
+
+
+class K8sReplicationControllerManager(K8sBaseManager):
+ """docstring for ClassName"""
+
+ resource_class = K8sReplicationController
+
+ def _get(self, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.read_namespaced_replication_controller(
+ name=name, namespace=namespace, **kwargs)
+
+ def _list(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.list_namespaced_replication_controller(
+ namespace=namespace, **kwargs)
+
+ def _create(self, body, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.create_namespaced_replication_controller(
+ body=body, namespace=namespace, **kwargs)
+
+ def _replace(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.replace_namespaced_replication_controller(
+ body=body, name=name, namespace=namespace, **kwargs)
+
+ def _delete(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.delete_namespaced_replication_controller(
+ body=body, name=name, namespace=namespace, **kwargs)
+
+ def _deletecollection(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.deletecollection_namespaced_replication_controller(
+ namespace=namespace, **kwargs)
+
+ def full_list(self, *args, **kwargs):
+ lst = self._full_list(*args, **kwargs)
+ return [self.resource_class(self, item) for item in lst.items]
+
+ def _full_list(self, **kwargs):
+ return self.api.list_replication_controller(**kwargs)
diff --git a/tcp_tests/managers/k8s/resourcequotas.py b/tcp_tests/managers/k8s/resourcequotas.py
new file mode 100644
index 0000000..49d81d5
--- /dev/null
+++ b/tcp_tests/managers/k8s/resourcequotas.py
@@ -0,0 +1,70 @@
+# Copyright 2017 Mirantis, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+
+
+from tcp_tests.managers.k8s.base import K8sBaseResource
+from tcp_tests.managers.k8s.base import K8sBaseManager
+
+
+class K8sResourceQuota(K8sBaseResource):
+ """docstring for K8sResourceQuota"""
+
+ def __repr__(self):
+ return "<K8sResourceQuota: %s>" % self.name
+
+ @property
+ def name(self):
+ return self.metadata.name
+
+
+class K8sResourceQuotaManager(K8sBaseManager):
+ """docstring for ClassName"""
+
+ resource_class = K8sResourceQuota
+
+ def _get(self, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.read_namespaced_resource_quota(
+ name=name, namespace=namespace, **kwargs)
+
+ def _list(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.list_namespaced_resource_quota(
+ namespace=namespace, **kwargs)
+
+ def _create(self, body, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.create_namespaced_resource_quota(
+ body=body, namespace=namespace, **kwargs)
+
+ def _replace(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.replace_namespaced_resource_quota(
+ body=body, name=name, namespace=namespace, **kwargs)
+
+ def _delete(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.delete_namespaced_resource_quota(
+ body=body, name=name, namespace=namespace, **kwargs)
+
+ def _deletecollection(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.deletecollection_namespaced_resource_quota(
+ namespace=namespace, **kwargs)
+
+ def full_list(self, *args, **kwargs):
+ lst = self._full_list(*args, **kwargs)
+ return [self.resource_class(self, item) for item in lst.items]
+
+ def _full_list(self, **kwargs):
+ return self.api.list_resourse_quota(**kwargs)
diff --git a/tcp_tests/managers/k8s/secrets.py b/tcp_tests/managers/k8s/secrets.py
new file mode 100644
index 0000000..355c884
--- /dev/null
+++ b/tcp_tests/managers/k8s/secrets.py
@@ -0,0 +1,70 @@
+# Copyright 2017 Mirantis, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+
+
+from tcp_tests.managers.k8s.base import K8sBaseResource
+from tcp_tests.managers.k8s.base import K8sBaseManager
+
+
+class K8sSecret(K8sBaseResource):
+ """docstring for K8sSecret"""
+
+ def __repr__(self):
+ return "<K8sSecret: %s>" % self.name
+
+ @property
+ def name(self):
+ return self.metadata.name
+
+
+class K8sSecretManager(K8sBaseManager):
+ """docstring for ClassName"""
+
+ resource_class = K8sSecret
+
+ def _get(self, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.read_namespaced_secret(
+ name=name, namespace=namespace, **kwargs)
+
+ def _list(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.list_namespaced_secret(
+ namespace=namespace, **kwargs)
+
+ def _create(self, body, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.create_namespaced_secret(
+ body=body, namespace=namespace, **kwargs)
+
+ def _replace(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.replace_namespaced_secret(
+ body=body, name=name, namespace=namespace, **kwargs)
+
+ def _delete(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.delete_namespaced_secret(
+ body=body, name=name, namespace=namespace, **kwargs)
+
+ def _deletecollection(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.deletecollection_namespaced_secret(
+ namespace=namespace, **kwargs)
+
+ def full_list(self, *args, **kwargs):
+ lst = self._full_list(*args, **kwargs)
+ return [self.resource_class(self, item) for item in lst.items]
+
+ def _full_list(self, **kwargs):
+ return self.api.list_secret(**kwargs)
diff --git a/tcp_tests/managers/k8s/serviceaccounts.py b/tcp_tests/managers/k8s/serviceaccounts.py
new file mode 100644
index 0000000..bf58b4c
--- /dev/null
+++ b/tcp_tests/managers/k8s/serviceaccounts.py
@@ -0,0 +1,70 @@
+# Copyright 2017 Mirantis, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+
+
+from tcp_tests.managers.k8s.base import K8sBaseResource
+from tcp_tests.managers.k8s.base import K8sBaseManager
+
+
+class K8sServiceAccount(K8sBaseResource):
+ """docstring for K8sServiceAccount"""
+
+ def __repr__(self):
+ return "<K8sServiceAccount: %s>" % self.name
+
+ @property
+ def name(self):
+ return self.metadata.name
+
+
+class K8sServiceAccountManager(K8sBaseManager):
+ """docstring for K8sServiceAccountManager"""
+
+ resource_class = K8sServiceAccount
+
+ def _get(self, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.read_namespaced_service_account(
+ name=name, namespace=namespace, **kwargs)
+
+ def _list(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.list_namespaced_service_account(
+ namespace=namespace, **kwargs)
+
+ def _create(self, body, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.create_namespaced_service_account(
+ body=body, namespace=namespace, **kwargs)
+
+ def _replace(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.replace_namespaced_service_account(
+ body=body, name=name, namespace=namespace, **kwargs)
+
+ def _delete(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.delete_namespaced_service_account(
+ body=body, name=name, namespace=namespace, **kwargs)
+
+ def _deletecollection(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.deletecollection_namespaced_service_account(
+ namespace=namespace, **kwargs)
+
+ def full_list(self, *args, **kwargs):
+ lst = self._full_list(*args, **kwargs)
+ return [self.resource_class(self, item) for item in lst.items]
+
+ def _full_list(self, **kwargs):
+ return self.api.list_service_account(**kwargs)
diff --git a/tcp_tests/managers/k8s/services.py b/tcp_tests/managers/k8s/services.py
new file mode 100644
index 0000000..97a6be7
--- /dev/null
+++ b/tcp_tests/managers/k8s/services.py
@@ -0,0 +1,68 @@
+# Copyright 2017 Mirantis, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+
+
+from tcp_tests.managers.k8s.base import K8sBaseResource
+from tcp_tests.managers.k8s.base import K8sBaseManager
+
+
+class K8sService(K8sBaseResource):
+ """docstring for K8sService"""
+
+ def __repr__(self):
+ return "<K8sService: %s>" % self.name
+
+ @property
+ def name(self):
+ return self.metadata.name
+
+ @property
+ def namespace(self):
+ return self.metadata.namespace
+
+
+class K8sServiceManager(K8sBaseManager):
+ """docstring for K8sServiceManager"""
+
+ resource_class = K8sService
+
+ def _get(self, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.read_namespaced_service(
+ name=name, namespace=namespace, **kwargs)
+
+ def _list(self, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.list_namespaced_service(namespace=namespace, **kwargs)
+
+ def _create(self, body, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.create_namespaced_service(
+ body=body, namespace=namespace, **kwargs)
+
+ def _replace(self, body, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.replace_namespaced_service(
+ body=body, name=name, namespace=namespace, **kwargs)
+
+ def _delete(self, name, namespace=None, **kwargs):
+ namespace = namespace or self.namespace
+ return self.api.delete_namespaced_service(
+ name=name, namespace=namespace, **kwargs)
+
+ def full_list(self, *args, **kwargs):
+ lst = self._full_list(*args, **kwargs)
+ return [self.resource_class(self, item) for item in lst.items]
+
+ def _full_list(self, **kwargs):
+ return self.api.list_service(**kwargs)
diff --git a/tcp_tests/managers/k8smanager.py b/tcp_tests/managers/k8smanager.py
new file mode 100644
index 0000000..3801436
--- /dev/null
+++ b/tcp_tests/managers/k8smanager.py
@@ -0,0 +1,271 @@
+# Copyright 2017 Mirantis, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import time
+
+import yaml
+
+from devops.helpers import helpers
+
+from tcp_tests import logger
+from tcp_tests.managers.execute_commands import ExecuteCommandsMixin
+from tcp_tests.managers.k8s import cluster
+
+
+LOG = logger.logger
+
+
+class K8SManager(ExecuteCommandsMixin):
+ """docstring for K8SManager"""
+
+ __config = None
+ __underlay = None
+
+ def __init__(self, config, underlay, salt):
+ self.__config = config
+ self.__underlay = underlay
+ self._salt = salt
+ self._api_client = None
+ super(K8SManager, self).__init__(
+ config=config, underlay=underlay)
+
+ def install(self, commands):
+ self.execute_commands(commands,
+ label='Install Kubernetes services')
+ self.__config.k8s.k8s_installed = True
+ self.__config.k8s.kube_host = self.get_proxy_api()
+
+ def get_proxy_api(self):
+ k8s_proxy_ip_pillars = self._salt.get_pillar(
+ tgt='I@haproxy:proxy:enabled:true',
+ pillar='haproxy:proxy:listen:k8s_secure:binds:address')
+ k8s_proxy_ip = set([ip
+ for item in k8s_proxy_ip_pillars
+ for node,ip in item.items()])
+ assert len(k8s_proxy_ip) == 1, \
+ ("Found {0} Kubernetes endpoints in pillars,"
+ " expected one!").format(len(k8s_proxy_ip))
+ return k8s_proxy_ip.pop()
+
+ @property
+ def api(self):
+ if self._api_client is None:
+ self._api_client = cluster.K8sCluster(
+ user=self.__config.k8s_deploy.kubernetes_admin_user,
+ password=self.__config.k8s_deploy.kubernetes_admin_password,
+ host=self.__config.k8s.kube_host,
+ port=self.__config.k8s.kube_apiserver_port,
+ default_namespace='default')
+ return self._api_client
+
+ def get_pod_phase(self, pod_name, namespace=None):
+ return self.api.pods.get(
+ name=pod_name, namespace=namespace).phase
+
+ def wait_pod_phase(self, pod_name, phase, namespace=None, timeout=60):
+ """Wait phase of pod_name from namespace while timeout
+
+ :param str: pod_name
+ :param str: namespace
+ :param list or str: phase
+ :param int: timeout
+
+ :rtype: None
+ """
+ if isinstance(phase, str):
+ phase = [phase]
+
+ def check():
+ return self.get_pod_phase(pod_name, namespace) in phase
+
+ helpers.wait(check, timeout=timeout,
+ timeout_msg='Timeout waiting, pod {pod_name} is not in '
+ '"{phase}" phase'.format(
+ pod_name=pod_name, phase=phase))
+
+ def wait_pods_phase(self, pods, phase, timeout=60):
+ """Wait timeout seconds for phase of pods
+
+ :param pods: list of K8sPod
+ :param phase: list or str
+ :param timeout: int
+
+ :rtype: None
+ """
+ if isinstance(phase, str):
+ phase = [phase]
+
+ def check(pod_name, namespace):
+ return self.get_pod_phase(pod_name, namespace) in phase
+
+ def check_all_pods():
+ return all(check(pod.name, pod.metadata.namespace) for pod in pods)
+
+ helpers.wait(
+ check_all_pods,
+ timeout=timeout,
+ timeout_msg='Timeout waiting, pods {0} are not in "{1}" '
+ 'phase'.format([pod.name for pod in pods], phase))
+
+ def check_pod_create(self, body, namespace=None, timeout=300, interval=5):
+ """Check creating sample pod
+
+ :param k8s_pod: V1Pod
+ :param namespace: str
+ :rtype: V1Pod
+ """
+ LOG.info("Creating pod in k8s cluster")
+ LOG.debug(
+ "POD spec to create:\n{}".format(
+ yaml.dump(body, default_flow_style=False))
+ )
+ LOG.debug("Timeout for creation is set to {}".format(timeout))
+ LOG.debug("Checking interval is set to {}".format(interval))
+ pod = self.api.pods.create(body=body, namespace=namespace)
+ pod.wait_running(timeout=300, interval=5)
+ LOG.info("Pod '{0}' is created in '{1}' namespace".format(
+ pod.name, pod.namespace))
+ return self.api.pods.get(name=pod.name, namespace=pod.namespace)
+
+ def wait_pod_deleted(self, podname, timeout=60, interval=5):
+ helpers.wait(
+ lambda: podname not in [pod.name for pod in self.api.pods.list()],
+ timeout=timeout,
+ interval=interval,
+ timeout_msg="Pod deletion timeout reached!"
+ )
+
+ def check_pod_delete(self, k8s_pod, timeout=300, interval=5,
+ namespace=None):
+ """Deleting pod from k8s
+
+ :param k8s_pod: tcp_tests.managers.k8s.nodes.K8sNode
+ :param k8sclient: tcp_tests.managers.k8s.cluster.K8sCluster
+ """
+ LOG.info("Deleting pod '{}'".format(k8s_pod.name))
+ LOG.debug("Pod status:\n{}".format(k8s_pod.status))
+ LOG.debug("Timeout for deletion is set to {}".format(timeout))
+ LOG.debug("Checking interval is set to {}".format(interval))
+ self.api.pods.delete(body=k8s_pod, name=k8s_pod.name,
+ namespace=namespace)
+ self.wait_pod_deleted(k8s_pod.name, timeout, interval)
+ LOG.debug("Pod '{}' is deleted".format(k8s_pod.name))
+
+ def check_service_create(self, body, namespace=None):
+ """Check creating k8s service
+
+ :param body: dict, service spec
+ :param namespace: str
+ :rtype: K8sService object
+ """
+ LOG.info("Creating service in k8s cluster")
+ LOG.debug(
+ "Service spec to create:\n{}".format(
+ yaml.dump(body, default_flow_style=False))
+ )
+ service = self.api.services.create(body=body, namespace=namespace)
+ LOG.info("Service '{0}' is created in '{1}' namespace".format(
+ service.name, service.namespace))
+ return self.api.services.get(name=service.name,
+ namespace=service.namespace)
+
+ def check_ds_create(self, body, namespace=None):
+ """Check creating k8s DaemonSet
+
+ :param body: dict, DaemonSet spec
+ :param namespace: str
+ :rtype: K8sDaemonSet object
+ """
+ LOG.info("Creating DaemonSet in k8s cluster")
+ LOG.debug(
+ "DaemonSet spec to create:\n{}".format(
+ yaml.dump(body, default_flow_style=False))
+ )
+ ds = self.api.daemonsets.create(body=body, namespace=namespace)
+ LOG.info("DaemonSet '{0}' is created in '{1}' namespace".format(
+ ds.name, ds.namespace))
+ return self.api.daemonsets.get(name=ds.name, namespace=ds.namespace)
+
+ def check_ds_ready(self, dsname, namespace=None):
+ """Check if k8s DaemonSet is ready
+
+ :param dsname: str, ds name
+ :return: bool
+ """
+ ds = self.api.daemonsets.get(name=dsname, namespace=namespace)
+ return (ds.status.current_number_scheduled ==
+ ds.status.desired_number_scheduled)
+
+ def wait_ds_ready(self, dsname, namespace=None, timeout=60, interval=5):
+ """Wait until all pods are scheduled on nodes
+
+ :param dsname: str, ds name
+ :param timeout: int
+ :param interval: int
+ """
+ helpers.wait(
+ lambda: self.check_ds_ready(dsname, namespace=namespace),
+ timeout=timeout, interval=interval)
+
+ def check_namespace_create(self, name):
+ """Check creating k8s Namespace
+
+ :param name: str
+ :rtype: K8sNamespace object
+ """
+ LOG.info("Creating Namespace in k8s cluster")
+ ns = self.api.namespaces.create(body={'metadata': {'name': name}})
+ LOG.info("Namespace '{0}' is created".format(ns.name))
+ # wait 10 seconds until a token for new service account is created
+ time.sleep(10)
+ return self.api.namespaces.get(name=ns.name)
+
+ def create_objects(self, path):
+ if isinstance(path, str):
+ path = [path]
+ params = ' '.join(["-f {}".format(p) for p in path])
+ cmd = 'kubectl create {params}'.format(params=params)
+ with self.__underlay.remote(
+ host=self.__config.k8s.kube_host) as remote:
+ LOG.info("Running command '{cmd}' on node {node}".format(
+ cmd=cmd,
+ node=remote.hostname)
+ )
+ result = remote.check_call(cmd)
+ LOG.info(result['stdout'])
+
+ def get_running_pods(self, pod_name, namespace=None):
+ pods = [pod for pod in self.api.pods.list(namespace=namespace)
+ if (pod_name in pod.name and pod.status.phase == 'Running')]
+ return pods
+
+ def get_pods_number(self, pod_name, namespace=None):
+ pods = self.get_running_pods(pod_name, namespace)
+ return len(pods)
+
+ def get_running_pods_by_ssh(self, pod_name, namespace=None):
+ with self.__underlay.remote(
+ host=self.__config.k8s.kube_host) as remote:
+ result = remote.check_call("kubectl get pods --namespace {} |"
+ " grep {} | awk '{{print $1 \" \""
+ " $3}}'".format(namespace,
+ pod_name))['stdout']
+ running_pods = [data.strip().split()[0] for data in result
+ if data.strip().split()[1] == 'Running']
+ return running_pods
+
+ def get_pods_restarts(self, pod_name, namespace=None):
+ pods = [pod.status.container_statuses[0].restart_count
+ for pod in self.get_running_pods(pod_name, namespace)]
+ return sum(pods)
diff --git a/tcp_tests/managers/saltmanager.py b/tcp_tests/managers/saltmanager.py
index 304ff75..f8a3fd8 100644
--- a/tcp_tests/managers/saltmanager.py
+++ b/tcp_tests/managers/saltmanager.py
@@ -11,7 +11,6 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-# import time
from collections import defaultdict
@@ -151,3 +150,7 @@
r = self.run_state(tgt=tgt, state=s, args=args, kwargs=kwargs)
rets.append(r)
return rets
+
+ def get_pillar(self, tgt, pillar):
+ result = self.local(tgt=tgt, fun='pillar.get', args=pillar)
+ return result['return']
diff --git a/tcp_tests/managers/virtlet_ceph_manager.py b/tcp_tests/managers/virtlet_ceph_manager.py
index 49c4c64..5a79cf2 100644
--- a/tcp_tests/managers/virtlet_ceph_manager.py
+++ b/tcp_tests/managers/virtlet_ceph_manager.py
@@ -21,10 +21,9 @@
__config = None
__underlay = None
- def __init__(self, config, underlay, salt):
+ def __init__(self, config, underlay):
self.__config = config
self.__underlay = underlay
- self._salt = salt
super(VirtletCephManager, self).__init__(
config=config, underlay=underlay)
diff --git a/tcp_tests/managers/virtlet_manager.py b/tcp_tests/managers/virtlet_manager.py
index c696ed4..f8d1ced 100644
--- a/tcp_tests/managers/virtlet_manager.py
+++ b/tcp_tests/managers/virtlet_manager.py
@@ -21,10 +21,9 @@
__config = None
__underlay = None
- def __init__(self, config, underlay, salt):
+ def __init__(self, config, underlay):
self.__config = config
self.__underlay = underlay
- self._salt = salt
super(VirtletManager, self).__init__(
config=config, underlay=underlay)
diff --git a/tcp_tests/requirements.txt b/tcp_tests/requirements.txt
index 0a69202..fea3368 100644
--- a/tcp_tests/requirements.txt
+++ b/tcp_tests/requirements.txt
@@ -13,4 +13,5 @@
jira
testrail
functools32
+python-k8sclient==0.4.0
salt-pepper
diff --git a/tcp_tests/settings_oslo.py b/tcp_tests/settings_oslo.py
index c68f1f2..a932296 100644
--- a/tcp_tests/settings_oslo.py
+++ b/tcp_tests/settings_oslo.py
@@ -49,6 +49,9 @@
_default_virtlet_ceph_prepare_tests_steps_path = pkg_resources.resource_filename(
__name__, 'templates/{0}/virtlet_ceph.yaml'.format(
settings.LAB_CONFIG_NAME))
+_default_k8s_steps = pkg_resources.resource_filename(
+ __name__, 'templates/{0}/k8s.yaml'.format(
+ settings.LAB_CONFIG_NAME))
hardware_opts = [
ct.Cfg('manager', ct.String(),
@@ -171,6 +174,12 @@
]
k8s_deploy_opts = [
+ ct.Cfg('k8s_steps_path', ct.String(),
+ help="Path to YAML with steps to deploy Kubernetes",
+ default=_default_k8s_steps),
+ ct.Cfg('kubernetes_admin_user', ct.String(), default='admin'),
+ ct.Cfg('kubernetes_admin_password', ct.String(),
+ default='sbPfel23ZigJF3Bm'),
ct.Cfg('kubernetes_docker_package', ct.String(), default=''),
ct.Cfg('kubernetes_hyperkube_image', ct.String(),
default='{}/mirantis/kubernetes/hyperkube-amd64:v1.6.2-2'.format(
@@ -184,6 +193,8 @@
ct.Cfg('kubernetes_calico_cni_image', ct.String(),
default='{}/mirantis/projectcalico/calico/cni:latest'.format(
settings.DOCKER_REGISTRY)),
+ ct.Cfg('kubernetes_netchecker_enabled', ct.Boolean(),
+ help="", default=True),
ct.Cfg('kubernetes_netchecker_agent_image', ct.String(),
default='mirantis/k8s-netchecker-agent:latest'),
ct.Cfg('kubernetes_netchecker_server_image', ct.String(),
@@ -191,6 +202,8 @@
]
k8s_opts = [
+ ct.Cfg('k8s_installed', ct.Boolean(),
+ help="", default=False),
ct.Cfg('kube_host', ct.IPAddress(),
help="", default='0.0.0.0'),
ct.Cfg('kube_apiserver_port', ct.Integer(),
diff --git a/tcp_tests/templates/virtual-mcp11-k8s-calico-minimal/openstack.yaml b/tcp_tests/templates/virtual-mcp11-k8s-calico-minimal/k8s.yaml
similarity index 100%
rename from tcp_tests/templates/virtual-mcp11-k8s-calico-minimal/openstack.yaml
rename to tcp_tests/templates/virtual-mcp11-k8s-calico-minimal/k8s.yaml
diff --git a/tcp_tests/templates/virtual-mcp11-k8s-calico/common-services.yaml b/tcp_tests/templates/virtual-mcp11-k8s-calico/common-services.yaml
index dd06454..5d8864c 100644
--- a/tcp_tests/templates/virtual-mcp11-k8s-calico/common-services.yaml
+++ b/tcp_tests/templates/virtual-mcp11-k8s-calico/common-services.yaml
@@ -42,51 +42,6 @@
retry: {count: 1, delay: 5}
skip_fail: false
-- description: Install etcd
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@etcd:server' state.sls etcd.server.service
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 1, delay: 5}
- skip_fail: false
-
-- description: Check the etcd health
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@etcd:server' cmd.run '. /var/lib/etcd/configenv && etcdctl cluster-health'
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 1, delay: 5}
- skip_fail: false
-
-- description: Install Kubernetes and Calico
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@kubernetes:master' state.sls kubernetes.master.kube-addons;
- salt --hard-crash --state-output=mixed --state-verbose=False -C 'I@kubernetes:pool' state.sls kubernetes.pool;
- salt --hard-crash --state-output=mixed --state-verbose=False -C 'I@kubernetes:pool' cmd.run 'calicoctl node status';
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 1, delay: 5}
- skip_fail: false
-
-- description: Setup NAT for Calico
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@etcd:server' --subset 1 state.sls etcd.server.setup
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 1, delay: 5}
- skip_fail: false
-
-- description: Run whole master to check consistency
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@kubernetes:master' state.sls kubernetes exclude=kubernetes.master.setup
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 1, delay: 5}
- skip_fail: true
-
-
-- description: Register addons
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@kubernetes:master' --subset 1 state.sls kubernetes.master.setup
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 1, delay: 5}
- skip_fail: false
-
# Isntall SL core services
- description: Install glusterfs
cmd: salt --hard-crash --state-output=mixed --state-verbose=False
diff --git a/tcp_tests/templates/virtual-mcp11-k8s-calico/k8s.yaml b/tcp_tests/templates/virtual-mcp11-k8s-calico/k8s.yaml
new file mode 100644
index 0000000..d63fba3
--- /dev/null
+++ b/tcp_tests/templates/virtual-mcp11-k8s-calico/k8s.yaml
@@ -0,0 +1,52 @@
+{% from 'virtual-mcp11-k8s-calico/underlay.yaml' import HOSTNAME_CFG01 with context %}
+
+- description: Install etcd
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@etcd:server' state.sls etcd.server.service
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 1, delay: 5}
+ skip_fail: false
+
+- description: Check the etcd health
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@etcd:server' cmd.run '. /var/lib/etcd/configenv && etcdctl cluster-health'
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 1, delay: 5}
+ skip_fail: false
+
+- description: Install Kubernetes and Calico
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@kubernetes:master' state.sls kubernetes.master.kube-addons;
+ salt --hard-crash --state-output=mixed --state-verbose=False -C 'I@kubernetes:pool' state.sls kubernetes.pool;
+ salt --hard-crash --state-output=mixed --state-verbose=False -C 'I@kubernetes:pool' cmd.run 'calicoctl node status';
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 1, delay: 5}
+ skip_fail: false
+
+- description: Setup NAT for Calico
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@etcd:server' --subset 1 state.sls etcd.server.setup
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 1, delay: 5}
+ skip_fail: false
+
+- description: Run whole master to check consistency
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@kubernetes:master' state.sls kubernetes exclude=kubernetes.master.setup
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 1, delay: 5}
+ skip_fail: true
+
+- description: Register addons
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@kubernetes:master' --subset 1 state.sls kubernetes.master.setup
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 1, delay: 5}
+ skip_fail: false
+
+# Run conformance tests
+- description: Run tests
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False 'ctl01*' cmd.run "docker run --rm --net=host -e API_SERVER='http://127.0.0.1:8080' docker-dev-virtual.docker.mirantis.net/mirantis/kubernetes/k8s-conformance:v1.6.2-2_1493800192393 >> e2e.output"
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 1, delay: 5}
+ skip_fail: false
diff --git a/tcp_tests/templates/virtual-mcp11-k8s-calico/openstack.yaml b/tcp_tests/templates/virtual-mcp11-k8s-calico/openstack.yaml
deleted file mode 100644
index 21c99b3..0000000
--- a/tcp_tests/templates/virtual-mcp11-k8s-calico/openstack.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-{% from 'virtual-mcp11-k8s-calico/underlay.yaml' import HOSTNAME_CFG01 with context %}
-
-# Install OpenStack control services
-
-- description: Run tests
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False 'ctl01*' cmd.run "docker run --rm --net=host -e API_SERVER='http://127.0.0.1:8080' docker-dev-virtual.docker.mirantis.net/mirantis/kubernetes/k8s-conformance:v1.6.2-2_1493800192393 >> e2e.output"
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 1, delay: 5}
- skip_fail: false
diff --git a/tcp_tests/templates/virtual-mcp11-k8s-contrail/common-services.yaml b/tcp_tests/templates/virtual-mcp11-k8s-contrail/common-services.yaml
index 2f98744..cc5b267 100644
--- a/tcp_tests/templates/virtual-mcp11-k8s-contrail/common-services.yaml
+++ b/tcp_tests/templates/virtual-mcp11-k8s-contrail/common-services.yaml
@@ -55,180 +55,3 @@
node_name: {{ HOSTNAME_CFG01 }}
retry: {count: 1, delay: 5}
skip_fail: false
-
-#Kubernetes
-- description: Install docker
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@docker:host' state.sls docker.host
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 1, delay: 5}
- skip_fail: false
-
-- description: Check docker
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@docker:host' cmd.run 'docker ps'
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 1, delay: 5}
- skip_fail: false
-
-- description: Install etcd
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@etcd:server' state.sls etcd.server.service
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 1, delay: 5}
- skip_fail: false
-
-- description: Check the etcd health
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@etcd:server' cmd.run '. /var/lib/etcd/configenv && etcdctl cluster-health'
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 1, delay: 5}
- skip_fail: false
-
-- description: Install keepalived on primary controller
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@keepalived:cluster and *01*' state.sls keepalived
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 1, delay: 10}
- skip_fail: true
-
-- description: Install keepalived on all controllers
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@keepalived:cluster' state.sls keepalived
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 1, delay: 10}
- skip_fail: true
-
-- description: Install nginx
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@nginx:server' state.sls nginx
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 1, delay: 5}
- skip_fail: false
-
-- description: Install Kubernetes Addons
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@kubernetes:master' state.sls kubernetes.master.kube-addons
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 1, delay: 5}
- skip_fail: true
-
-- description: Install Kubernetes components
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@kubernetes:pool' state.sls kubernetes.pool
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 1, delay: 5}
- skip_fail: false
-
-- description: Setup etcd server on primary controller
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@kubernetes:master and *01*' state.sls etcd.server.setup
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 1, delay: 5}
- skip_fail: false
-
-- description: Run Kubernetes master without setup
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@kubernetes:master' state.sls kubernetes exclude=kubernetes.master.setup
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 1, delay: 5}
- skip_fail: true
-
-- description: Run Kubernetes master setup
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@kubernetes:master and *01*' state.sls kubernetes.master.setup
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 1, delay: 5}
- skip_fail: true
-
-- description: Restart Kubelet
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@kubernetes:pool' service.restart 'kubelet'
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 1, delay: 5}
- skip_fail: true
-
-# Opencontrail
-- description: Install RabbitMQ
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@rabbitmq:server' state.sls rabbitmq
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 2, delay: 10}
- skip_fail: false
-
-- description: Check RabbitMQ
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@rabbitmq:server' cmd.run "rabbitmqctl cluster_status"
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 1, delay: 10}
- skip_fail: false
-
-- description: Install Opencontrail db on ctl01
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@opencontrail:database and *01*' state.sls opencontrail.database
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 2, delay: 20}
- skip_fail: false
-
-- description: Install Opencontrail db on all nodes
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@opencontrail:database' state.sls opencontrail.database
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 2, delay: 20}
- skip_fail: false
-
-- description: Install Opencontrail control on ctl01
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@opencontrail:control and *01*' state.sls opencontrail exclude=opencontrail.client
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 1, delay: 5}
- skip_fail: false
-
-- description: Install Opencontrail control on all nodes
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@opencontrail:control' state.sls opencontrail exclude=opencontrail.client
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 1, delay: 5}
- skip_fail: false
-
-- description: Install Opencontrail on collector
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@opencontrail:collector' state.sls opencontrail exclude=opencontrail.client
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 1, delay: 5}
- skip_fail: false
-
-- description: Test Opencontrail
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@opencontrail:control' cmd.run 'contrail-status'
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 1, delay: 5}
- skip_fail: false
-
-- description: Install Opencontrail client
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@opencontrail:database:id:1' state.sls 'opencontrail.client'
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 1, delay: 5}
- skip_fail: false
-
-- description: Install Opencontrail client on computes
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@opencontrail:compute' state.sls 'opencontrail.client'
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 1, delay: 5}
- skip_fail: false
-
-- description: Install Opencontrail on computes
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@opencontrail:compute' state.sls 'opencontrail'
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 1, delay: 5}
- skip_fail: false
-
-- description: Reboot Opencontrail compute nodes
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False
- -C 'I@opencontrail:compute' system.reboot
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 1, delay: 5}
- skip_fail: false
diff --git a/tcp_tests/templates/virtual-mcp11-k8s-contrail/k8s.yaml b/tcp_tests/templates/virtual-mcp11-k8s-contrail/k8s.yaml
new file mode 100644
index 0000000..0cdb087
--- /dev/null
+++ b/tcp_tests/templates/virtual-mcp11-k8s-contrail/k8s.yaml
@@ -0,0 +1,185 @@
+{% from 'virtual-mcp11-k8s-contrail/underlay.yaml' import HOSTNAME_CFG01 with context %}
+
+#Kubernetes
+- description: Install docker
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@docker:host' state.sls docker.host
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 1, delay: 5}
+ skip_fail: false
+
+- description: Check docker
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@docker:host' cmd.run 'docker ps'
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 1, delay: 5}
+ skip_fail: false
+
+- description: Install etcd
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@etcd:server' state.sls etcd.server.service
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 1, delay: 5}
+ skip_fail: false
+
+- description: Check the etcd health
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@etcd:server' cmd.run '. /var/lib/etcd/configenv && etcdctl cluster-health'
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 1, delay: 5}
+ skip_fail: false
+
+- description: Install keepalived on primary controller
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@keepalived:cluster and *01*' state.sls keepalived
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 1, delay: 10}
+ skip_fail: true
+
+- description: Install keepalived on all controllers
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@keepalived:cluster' state.sls keepalived
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 1, delay: 10}
+ skip_fail: true
+
+- description: Install nginx
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@nginx:server' state.sls nginx
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 1, delay: 5}
+ skip_fail: false
+
+- description: Install Kubernetes Addons
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@kubernetes:master' state.sls kubernetes.master.kube-addons
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 1, delay: 5}
+ skip_fail: true
+
+- description: Install Kubernetes components
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@kubernetes:pool' state.sls kubernetes.pool
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 1, delay: 5}
+ skip_fail: false
+
+- description: Setup etcd server on primary controller
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@kubernetes:master and *01*' state.sls etcd.server.setup
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 1, delay: 5}
+ skip_fail: false
+
+- description: Run Kubernetes master without setup
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@kubernetes:master' state.sls kubernetes exclude=kubernetes.master.setup
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 1, delay: 5}
+ skip_fail: true
+
+- description: Run Kubernetes master setup
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@kubernetes:master and *01*' state.sls kubernetes.master.setup
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 1, delay: 5}
+ skip_fail: true
+
+- description: Restart Kubelet
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@kubernetes:pool' service.restart 'kubelet'
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 1, delay: 5}
+ skip_fail: true
+
+# Opencontrail
+- description: Install RabbitMQ
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@rabbitmq:server' state.sls rabbitmq
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 2, delay: 10}
+ skip_fail: false
+
+- description: Check RabbitMQ
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@rabbitmq:server' cmd.run "rabbitmqctl cluster_status"
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 1, delay: 10}
+ skip_fail: false
+
+- description: Install Opencontrail db on ctl01
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@opencontrail:database and *01*' state.sls opencontrail.database
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 2, delay: 20}
+ skip_fail: false
+
+- description: Install Opencontrail db on all nodes
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@opencontrail:database' state.sls opencontrail.database
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 2, delay: 20}
+ skip_fail: false
+
+- description: Install Opencontrail control on ctl01
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@opencontrail:control and *01*' state.sls opencontrail exclude=opencontrail.client
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 1, delay: 5}
+ skip_fail: false
+
+- description: Install Opencontrail control on all nodes
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@opencontrail:control' state.sls opencontrail exclude=opencontrail.client
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 1, delay: 5}
+ skip_fail: false
+
+- description: Install Opencontrail on collector
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@opencontrail:collector' state.sls opencontrail exclude=opencontrail.client
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 1, delay: 5}
+ skip_fail: false
+
+- description: Test Opencontrail
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@opencontrail:control' cmd.run 'contrail-status'
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 1, delay: 5}
+ skip_fail: false
+
+- description: Install Opencontrail client
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@opencontrail:database:id:1' state.sls 'opencontrail.client'
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 1, delay: 5}
+ skip_fail: false
+
+- description: Install Opencontrail client on computes
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@opencontrail:compute' state.sls 'opencontrail.client'
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 1, delay: 5}
+ skip_fail: false
+
+- description: Install Opencontrail on computes
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@opencontrail:compute' state.sls 'opencontrail'
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 1, delay: 5}
+ skip_fail: false
+
+- description: Reboot Opencontrail compute nodes
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False
+ -C 'I@opencontrail:compute' system.reboot
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 1, delay: 5}
+ skip_fail: false
+
+# Run conformance tests
+- description: Run tests
+ cmd: salt --hard-crash --state-output=mixed --state-verbose=False 'ctl01*' cmd.run "docker run --rm --net=host -e API_SERVER='http://127.0.0.1:8080' docker-dev-virtual.docker.mirantis.net/mirantis/kubernetes/k8s-conformance:v1.6.1-1_1491395924598 >> e2e.output"
+ node_name: {{ HOSTNAME_CFG01 }}
+ retry: {count: 1, delay: 5}
+ skip_fail: false
\ No newline at end of file
diff --git a/tcp_tests/templates/virtual-mcp11-k8s-contrail/openstack.yaml b/tcp_tests/templates/virtual-mcp11-k8s-contrail/openstack.yaml
deleted file mode 100644
index 54e4a73..0000000
--- a/tcp_tests/templates/virtual-mcp11-k8s-contrail/openstack.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-{% from 'virtual-mcp11-k8s-contrail/underlay.yaml' import HOSTNAME_CFG01 with context %}
-
-# Install OpenStack control services
-
-- description: Run tests
- cmd: salt --hard-crash --state-output=mixed --state-verbose=False 'ctl01*' cmd.run "docker run --rm --net=host -e API_SERVER='http://127.0.0.1:8080' docker-dev-virtual.docker.mirantis.net/mirantis/kubernetes/k8s-conformance:v1.6.1-1_1491395924598 >> e2e.output"
- node_name: {{ HOSTNAME_CFG01 }}
- retry: {count: 1, delay: 5}
- skip_fail: false
\ No newline at end of file
diff --git a/tcp_tests/tests/system/conftest.py b/tcp_tests/tests/system/conftest.py
index 89dfc3d..015c7ed 100644
--- a/tcp_tests/tests/system/conftest.py
+++ b/tcp_tests/tests/system/conftest.py
@@ -24,6 +24,7 @@
from tcp_tests.fixtures.stacklight_fixtures import *
from tcp_tests.fixtures.virtlet_fixtures import *
from tcp_tests.fixtures.virtlet_ceph_fixtures import *
+from tcp_tests.fixtures.k8s_fixtures import *
__all__ = sorted([ # sort for documentation
@@ -52,6 +53,9 @@
# stacklight_fixtures
'sl_actions',
'sl_deployed',
+ # k8s fixtures
+ 'k8s_actions',
+ 'k8s_deployed',
'virtlet_actions',
'virtlet_deployed',
'virtlet_ceph_actions',
diff --git a/tcp_tests/tests/system/test_install_k8s.py b/tcp_tests/tests/system/test_install_k8s.py
index 742ecc6..36f42b8 100644
--- a/tcp_tests/tests/system/test_install_k8s.py
+++ b/tcp_tests/tests/system/test_install_k8s.py
@@ -11,13 +11,9 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-import copy
-import time
import pytest
-from tcp_tests import settings
-from tcp_tests.helpers import ext
from tcp_tests import logger
LOG = logger.logger
@@ -25,37 +21,31 @@
@pytest.mark.deploy
class Testk8sInstall(object):
- """Test class for testing mcp10 vxlan deploy"""
+ """Test class for testing Kubernetes deploy"""
- #salt_cmd = 'salt -l debug ' # For debug output
- #salt_call_cmd = 'salt-call -l debug ' # For debug output
- salt_cmd = 'salt --hard-crash --state-output=mixed --state-verbose=False ' # For cause only output
- salt_call_cmd = 'salt-call --hard-crash --state-output=mixed --state-verbose=False ' # For cause only output
- #salt_cmd = 'salt --state-output=terse --state-verbose=False ' # For reduced output
- #salt_call_cmd = 'salt-call --state-output=terse --state-verbose=False ' # For reduced output
-
- # @pytest.mark.snapshot_needed
- # @pytest.mark.fail_snapshot
- def test_k8s_install(self, underlay, sl_deployed, openstack_deployed,
- show_step):
- """Test for deploying an mcp environment and check it
+ @pytest.mark.fail_snapshot
+ def test_k8s_install(self, sl_deployed, k8s_deployed):
+ """Test for deploying MCP environment with k8s+stacklight and check it
Scenario:
1. Prepare salt on hosts
2. Setup controller nodes
3. Setup compute nodes
4. Setup stack light nodes
+ 5. Setup Kubernetes cluster
"""
LOG.info("*************** DONE **************")
- def test_only_k8s_install(self, underlay, openstack_deployed, show_step):
- """Test for deploying an mcp environment and check it
+ @pytest.mark.fail_snapshot
+ def test_only_k8s_install(self, k8s_deployed):
+ """Test for deploying MCP environment with k8s and check it
Scenario:
1. Prepare salt on hosts
2. Setup controller nodes
3. Setup compute nodes
+ 4. Setup Kubernetes cluster
"""
LOG.info("*************** DONE **************")
\ No newline at end of file