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