211 lines
8.1 KiB
Python
211 lines
8.1 KiB
Python
# Copyright 2016 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 iso8601
|
|
|
|
from devops.helpers import helpers
|
|
from k8sclient.client import rest
|
|
import pytest
|
|
import yaml
|
|
|
|
from fuel_ccp_tests import logger
|
|
from fuel_ccp_tests import settings
|
|
|
|
LOG = logger.logger
|
|
|
|
|
|
class AppControllerResoucesStatus(object):
|
|
"""Helper class to check defined resources creation of AppController"""
|
|
|
|
resources = [
|
|
"dependency.appcontroller.k8s",
|
|
"definition.appcontroller.k8s"
|
|
]
|
|
|
|
def __init__(self, k8sclient, kube_ssh, expected_result=None):
|
|
"""
|
|
:param k8sclient: fuel_ccp_tests.managers.k8s.cluster.K8sCluster
|
|
:param kube_ssh: devops.helpers.ssh_client.SSHClient
|
|
:param expected_result: list of strings in 'type/object_name' format
|
|
"""
|
|
super(AppControllerResoucesStatus, self).__init__()
|
|
self.__k8s = k8sclient
|
|
self.__managers = {
|
|
"job": lambda: self.__k8s.jobs,
|
|
"pod": lambda: self.__k8s.pods,
|
|
"replicaset": lambda: self.__k8s.replicasets,
|
|
"service": lambda: self.__k8s.services,
|
|
}
|
|
self.__ssh = kube_ssh
|
|
self.__linear_order = []
|
|
self.register_linear_objects(expected_result)
|
|
|
|
def get_k8s_object(self, resource):
|
|
resource_type, resource_name = resource.split('/')
|
|
if resource_name is None:
|
|
raise ValueError("Resource '{}' has wrong format".format(
|
|
resource
|
|
))
|
|
return self.__managers[resource_type]().get(name=resource_name)
|
|
|
|
def register_linear_objects(self, list_resources=None):
|
|
"""Method to register check actions for each type of resources
|
|
|
|
:param list_resources: list of strings "type/object"
|
|
:raises: TypeError, KeyError, ValueError
|
|
"""
|
|
# The following object will return function (checker) to run
|
|
def obj_exists(resource):
|
|
return lambda: self.get_k8s_object(resource) is not None
|
|
if list_resources:
|
|
if not isinstance(list_resources, list):
|
|
raise TypeError("list_resources must be a list instance!")
|
|
result = []
|
|
for resource in list_resources:
|
|
try:
|
|
res_func = obj_exists(resource)
|
|
# To restore original name of object
|
|
setattr(res_func, '__resource_repr', resource)
|
|
except KeyError:
|
|
raise KeyError(
|
|
"Resource '{}' has unsupported type!".format(resource))
|
|
result.append(res_func)
|
|
self.__linear_order = result
|
|
|
|
def _linear_check(self, func):
|
|
"""Action to run check
|
|
|
|
:param func: function to run
|
|
"""
|
|
# Each function must be created with this attribute
|
|
resource_repr = getattr(func, '__resource_repr')
|
|
# Additional flag to detect if object has already created
|
|
must_created = getattr(func, '__to_be_created', None)
|
|
try:
|
|
result = func()
|
|
LOG.info("{} is created".format(resource_repr))
|
|
except rest.ApiException as err:
|
|
LOG.debug(err)
|
|
if must_created is None:
|
|
setattr(func, '__to_be_created', True)
|
|
LOG.info("{} should be created".format(resource_repr))
|
|
result = False
|
|
return result
|
|
|
|
def linear_check(self):
|
|
"""Action to wait until all checks are done
|
|
Each check has own timeout equals 300 secs"""
|
|
creation_dates = []
|
|
for item in self.__linear_order:
|
|
resource_repr = getattr(item, '__resource_repr')
|
|
helpers.wait(
|
|
lambda: self._linear_check(item), timeout=300, interval=2,
|
|
timeout_msg="{} creation timeout reached".format(resource_repr)
|
|
)
|
|
k8s_obj = self.get_k8s_object(resource_repr)
|
|
creation_date = iso8601.parse_date(
|
|
k8s_obj.metadata.creation_timestamp)
|
|
creation_dates.append(creation_date)
|
|
if len(creation_dates) > 1:
|
|
assert creation_dates[-2] <= creation_dates[-1], (
|
|
"The order of linear objects is broken!")
|
|
LOG.info("Linear check passed!")
|
|
|
|
def thirdparty_resources(self):
|
|
result = yaml.load(
|
|
self.__ssh.check_call(
|
|
"kubectl get thirdpartyresources -o yaml").stdout_str
|
|
)
|
|
return [item['metadata']['name'] for item in result['items']]
|
|
|
|
|
|
@pytest.mark.AppController
|
|
@pytest.mark.component_k8s
|
|
class TestAppController(object):
|
|
|
|
kube_settings = {
|
|
"hyperkube_image_repo": settings.HYPERKUBE_IMAGE_REPO,
|
|
"hyperkube_image_tag": settings.HYPERKUBE_IMAGE_TAG,
|
|
"searchdomains": settings.SEARCH_DOMAINS,
|
|
}
|
|
|
|
@pytest.mark.ac_linear_test
|
|
@pytest.mark.skipif(settings.AC_PATH is None,
|
|
reason="ApplicationController repo path is not set!")
|
|
def test_linear(self, underlay, k8scluster, show_step):
|
|
"""Linear test of AppController work
|
|
|
|
Scenario:
|
|
1. Create AppController in k8s
|
|
2. Wait until pod with AppController is Running
|
|
3. Wait until required thirdparty resources are created
|
|
4. Create dependencies from test
|
|
5. Create definitions from test
|
|
6. Run AppController to create defined resources
|
|
7. Check if resources are created in expected order
|
|
"""
|
|
node_name = underlay.node_names()[0]
|
|
remote = underlay.remote(node_name=underlay.node_names()[0])
|
|
ac_path = settings.AC_PATH
|
|
ac_filepath = "%s/manifests/appcontroller.yaml" % ac_path
|
|
LOG.info("Trying to read %s" % ac_filepath)
|
|
with open(ac_filepath, 'r') as f:
|
|
ac_pod = yaml.load(f.read())
|
|
cmd_ac_run = "kubectl exec -i k8s-appcontroller ac-run"
|
|
|
|
show_step(1)
|
|
show_step(2)
|
|
k8scluster.check_pod_create(body=ac_pod)
|
|
|
|
# Load expected order to perform future checks
|
|
expected_filepath = "%s/tests/linear/expected_order.yaml" % ac_path
|
|
LOG.info(
|
|
"Trying to read file with expected order %s" % expected_filepath)
|
|
with open(expected_filepath) as f:
|
|
expected_order = yaml.load(f.read())
|
|
acr = AppControllerResoucesStatus(k8scluster.api, remote,
|
|
expected_order)
|
|
show_step(3)
|
|
helpers.wait(
|
|
lambda: set(acr.thirdparty_resources()).issubset(acr.resources),
|
|
timeout=120, interval=2, timeout_msg="Resources creation timeout"
|
|
)
|
|
|
|
create_cmd_template = "echo '{}' | kubectl create -f -"
|
|
|
|
show_step(4)
|
|
deps_filename = "%s/tests/linear/dependencies.yaml" % ac_path
|
|
LOG.info("Trying to read dependencies file %s" % deps_filename)
|
|
with open(deps_filename) as f:
|
|
deps_content = f.read()
|
|
cmd = create_cmd_template.format(deps_content)
|
|
helpers.wait(
|
|
lambda: underlay.check_call(
|
|
cmd, node_name=node_name, expected=[0, 1]
|
|
).exit_code == 0,
|
|
timeout=30, interval=2, timeout_msg="Dependencies creation failed")
|
|
|
|
show_step(5)
|
|
defs_filename = "%s/tests/linear/definitions.yaml" % ac_path
|
|
LOG.info("Trying to read definitions file %s" % defs_filename)
|
|
with open(defs_filename) as f:
|
|
defs_content = f.read()
|
|
cmd = create_cmd_template.format(defs_content)
|
|
underlay.check_call(cmd, node_name=node_name)
|
|
|
|
show_step(6)
|
|
underlay.check_call(cmd_ac_run, node_name=node_name)
|
|
|
|
show_step(7)
|
|
acr.linear_check()
|