Adds tests for some config helpers
This commit is contained in:
parent
9695c98e5f
commit
465e342aba
3 changed files with 151 additions and 3 deletions
|
@ -1,3 +1,5 @@
|
||||||
|
import logging
|
||||||
|
|
||||||
from flask import request, make_response
|
from flask import request, make_response
|
||||||
|
|
||||||
from config_app.config_util.config import get_config_as_kube_secret
|
from config_app.config_util.config import get_config_as_kube_secret
|
||||||
|
@ -7,6 +9,7 @@ from config_app.c_app import app, config_provider
|
||||||
from config_app.config_endpoints.api import resource, ApiResource, nickname, kubernetes_only, validate_json_request
|
from config_app.config_endpoints.api import resource, ApiResource, nickname, kubernetes_only, validate_json_request
|
||||||
from config_app.config_util.k8saccessor import KubernetesAccessorSingleton, K8sApiException
|
from config_app.config_util.k8saccessor import KubernetesAccessorSingleton, K8sApiException
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@resource('/v1/kubernetes/deployments/')
|
@resource('/v1/kubernetes/deployments/')
|
||||||
class SuperUserKubernetesDeployment(ApiResource):
|
class SuperUserKubernetesDeployment(ApiResource):
|
||||||
|
@ -82,7 +85,7 @@ class QEDeploymentRollback(ApiResource):
|
||||||
deployment_names = request.get_json()['deploymentNames']
|
deployment_names = request.get_json()['deploymentNames']
|
||||||
|
|
||||||
# To roll back a deployment, we must do 2 things:
|
# To roll back a deployment, we must do 2 things:
|
||||||
# 1. Roll back the config secret to its old value (discarding changes we made in this session
|
# 1. Roll back the config secret to its old value (discarding changes we made in this session)
|
||||||
# 2. Trigger a rollback to the previous revision, so that the pods will be restarted with
|
# 2. Trigger a rollback to the previous revision, so that the pods will be restarted with
|
||||||
# the old config
|
# the old config
|
||||||
old_secret = get_config_as_kube_secret(config_provider.get_old_config_dir())
|
old_secret = get_config_as_kube_secret(config_provider.get_old_config_dir())
|
||||||
|
@ -93,7 +96,8 @@ class QEDeploymentRollback(ApiResource):
|
||||||
for name in deployment_names:
|
for name in deployment_names:
|
||||||
kube_accessor.rollback_deployment(name)
|
kube_accessor.rollback_deployment(name)
|
||||||
except K8sApiException as e:
|
except K8sApiException as e:
|
||||||
return make_response(e.message, 500)
|
logger.exception('Failed to rollback deployment.')
|
||||||
|
return make_response(e.message, 503)
|
||||||
|
|
||||||
return make_response('Ok', 204)
|
return make_response('Ok', 204)
|
||||||
|
|
||||||
|
@ -109,7 +113,8 @@ class SuperUserKubernetesConfiguration(ApiResource):
|
||||||
new_secret = get_config_as_kube_secret(config_provider.get_config_dir_path())
|
new_secret = get_config_as_kube_secret(config_provider.get_config_dir_path())
|
||||||
KubernetesAccessorSingleton.get_instance().replace_qe_secret(new_secret)
|
KubernetesAccessorSingleton.get_instance().replace_qe_secret(new_secret)
|
||||||
except K8sApiException as e:
|
except K8sApiException as e:
|
||||||
return make_response(e.message, 500)
|
logger.exception('Failed to deploy qe config secret to kubernetes.')
|
||||||
|
return make_response(e.message, 503)
|
||||||
|
|
||||||
return make_response('Ok', 201)
|
return make_response('Ok', 201)
|
||||||
|
|
||||||
|
|
75
config_app/config_util/config/test/test_helpers.py
Normal file
75
config_app/config_util/config/test/test_helpers.py
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
import pytest
|
||||||
|
import os
|
||||||
|
import base64
|
||||||
|
|
||||||
|
from backports.tempfile import TemporaryDirectory
|
||||||
|
|
||||||
|
from config_app.config_util.config import get_config_as_kube_secret
|
||||||
|
from util.config.validator import EXTRA_CA_DIRECTORY
|
||||||
|
|
||||||
|
|
||||||
|
def _create_temp_file_structure(file_structure):
|
||||||
|
temp_dir = TemporaryDirectory()
|
||||||
|
|
||||||
|
for filename, data in file_structure.iteritems():
|
||||||
|
if filename == EXTRA_CA_DIRECTORY:
|
||||||
|
extra_ca_dir_path = os.path.join(temp_dir.name, EXTRA_CA_DIRECTORY)
|
||||||
|
os.mkdir(extra_ca_dir_path)
|
||||||
|
|
||||||
|
for name, cert_value in data:
|
||||||
|
with open(os.path.join(extra_ca_dir_path, name), 'w') as f:
|
||||||
|
f.write(cert_value)
|
||||||
|
else:
|
||||||
|
with open(os.path.join(temp_dir.name, filename), 'w') as f:
|
||||||
|
f.write(data)
|
||||||
|
|
||||||
|
return temp_dir
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('file_structure, expected_secret', [
|
||||||
|
pytest.param({
|
||||||
|
'config.yaml': 'test:true',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'config.yaml': 'dGVzdDp0cnVl',
|
||||||
|
}, id='just a config value'),
|
||||||
|
pytest.param({
|
||||||
|
'config.yaml': 'test:true',
|
||||||
|
'otherfile.ext': 'im a file'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'config.yaml': 'dGVzdDp0cnVl',
|
||||||
|
'otherfile.ext': base64.b64encode('im a file')
|
||||||
|
}, id='config and another file'),
|
||||||
|
pytest.param({
|
||||||
|
'config.yaml': 'test:true',
|
||||||
|
'extra_ca_certs': [
|
||||||
|
('cert.crt', 'im a cert!'),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'config.yaml': 'dGVzdDp0cnVl',
|
||||||
|
'extra_ca_certs_cert.crt': base64.b64encode('im a cert!'),
|
||||||
|
}, id='config and an extra cert'),
|
||||||
|
pytest.param({
|
||||||
|
'config.yaml': 'test:true',
|
||||||
|
'otherfile.ext': 'im a file',
|
||||||
|
'extra_ca_certs': [
|
||||||
|
('cert.crt', 'im a cert!'),
|
||||||
|
('another.crt', 'im a different cert!'),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'config.yaml': 'dGVzdDp0cnVl',
|
||||||
|
'otherfile.ext': base64.b64encode('im a file'),
|
||||||
|
'extra_ca_certs_cert.crt': base64.b64encode('im a cert!'),
|
||||||
|
'extra_ca_certs_another.crt': base64.b64encode('im a different cert!'),
|
||||||
|
}, id='config, files, and extra certs!'),
|
||||||
|
])
|
||||||
|
def test_get_config_as_kube_secret(file_structure, expected_secret):
|
||||||
|
temp_dir = _create_temp_file_structure(file_structure)
|
||||||
|
|
||||||
|
secret = get_config_as_kube_secret(temp_dir.name)
|
||||||
|
assert secret == expected_secret
|
||||||
|
|
||||||
|
temp_dir.cleanup()
|
|
@ -0,0 +1,68 @@
|
||||||
|
import pytest
|
||||||
|
import os
|
||||||
|
|
||||||
|
from config_app.config_util.config.TransientDirectoryProvider import TransientDirectoryProvider
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('files_to_write, operations, expected_new_dir', [
|
||||||
|
pytest.param({
|
||||||
|
'config.yaml': 'a config',
|
||||||
|
}, ([], [], []), {
|
||||||
|
'config.yaml': 'a config',
|
||||||
|
}, id='just a config'),
|
||||||
|
pytest.param({
|
||||||
|
'config.yaml': 'a config',
|
||||||
|
'oldfile': 'hmmm'
|
||||||
|
}, ([], [], ['oldfile']), {
|
||||||
|
'config.yaml': 'a config',
|
||||||
|
}, id='delete a file'),
|
||||||
|
pytest.param({
|
||||||
|
'config.yaml': 'a config',
|
||||||
|
'oldfile': 'hmmm'
|
||||||
|
}, ([('newfile', 'asdf')], [], ['oldfile']), {
|
||||||
|
'config.yaml': 'a config',
|
||||||
|
'newfile': 'asdf'
|
||||||
|
}, id='delete and add a file'),
|
||||||
|
pytest.param({
|
||||||
|
'config.yaml': 'a config',
|
||||||
|
'somefile': 'before'
|
||||||
|
}, ([('newfile', 'asdf')], [('somefile', 'after')], []), {
|
||||||
|
'config.yaml': 'a config',
|
||||||
|
'newfile': 'asdf',
|
||||||
|
'somefile': 'after',
|
||||||
|
}, id='add new files and change files'),
|
||||||
|
])
|
||||||
|
def test_transient_dir_copy_config_dir(files_to_write, operations, expected_new_dir):
|
||||||
|
config_provider = TransientDirectoryProvider('', '', '')
|
||||||
|
|
||||||
|
for name, data in files_to_write.iteritems():
|
||||||
|
config_provider.write_volume_file(name, data)
|
||||||
|
|
||||||
|
config_provider.create_copy_of_config_dir()
|
||||||
|
|
||||||
|
for create in operations[0]:
|
||||||
|
(name, data) = create
|
||||||
|
config_provider.write_volume_file(name, data)
|
||||||
|
|
||||||
|
for update in operations[1]:
|
||||||
|
(name, data) = update
|
||||||
|
config_provider.write_volume_file(name, data)
|
||||||
|
|
||||||
|
for delete in operations[2]:
|
||||||
|
config_provider.remove_volume_file(delete)
|
||||||
|
|
||||||
|
# check that the new directory matches expected state
|
||||||
|
for filename, data in expected_new_dir.iteritems():
|
||||||
|
with open(os.path.join(config_provider.get_config_dir_path(), filename)) as f:
|
||||||
|
new_data = f.read()
|
||||||
|
assert new_data == data
|
||||||
|
|
||||||
|
# Now check that the old dir matches the original state
|
||||||
|
saved = config_provider.get_old_config_dir()
|
||||||
|
|
||||||
|
for filename, data in files_to_write.iteritems():
|
||||||
|
with open(os.path.join(saved, filename)) as f:
|
||||||
|
new_data = f.read()
|
||||||
|
assert new_data == data
|
||||||
|
|
||||||
|
config_provider.temp_dir.cleanup()
|
Reference in a new issue