2018-05-10 13:44:18 +00:00
|
|
|
import base64
|
|
|
|
import os
|
|
|
|
import json
|
|
|
|
import uuid
|
|
|
|
|
2017-05-23 19:43:21 +00:00
|
|
|
import pytest
|
2018-05-10 13:44:18 +00:00
|
|
|
|
|
|
|
from contextlib import contextmanager
|
|
|
|
from collections import namedtuple
|
|
|
|
from httmock import urlmatch, HTTMock
|
2017-05-23 19:43:21 +00:00
|
|
|
|
|
|
|
from util.config.provider import KubernetesConfigProvider
|
|
|
|
|
2018-05-10 13:44:18 +00:00
|
|
|
def normalize_path(path):
|
|
|
|
return path.replace('/', '_')
|
2017-05-23 19:43:21 +00:00
|
|
|
|
2018-05-10 13:44:18 +00:00
|
|
|
@contextmanager
|
|
|
|
def fake_kubernetes_api(tmpdir_factory, files=None):
|
|
|
|
hostname = 'kubapi'
|
|
|
|
service_account_token_path = str(tmpdir_factory.mktemp("k8s").join("serviceaccount"))
|
|
|
|
auth_header = str(uuid.uuid4())
|
2017-05-23 19:43:21 +00:00
|
|
|
|
2018-05-10 13:44:18 +00:00
|
|
|
with open(service_account_token_path, 'w') as f:
|
|
|
|
f.write(auth_header)
|
2018-04-06 21:23:50 +00:00
|
|
|
|
2018-05-10 13:44:18 +00:00
|
|
|
global secret
|
|
|
|
secret = {
|
|
|
|
'data': {}
|
|
|
|
}
|
2018-04-06 21:23:50 +00:00
|
|
|
|
2018-05-10 13:44:18 +00:00
|
|
|
def write_file(config_dir, filepath, value):
|
|
|
|
normalized_path = normalize_path(filepath)
|
|
|
|
absolute_path = str(config_dir.join(normalized_path))
|
|
|
|
try:
|
|
|
|
os.makedirs(os.path.dirname(absolute_path))
|
|
|
|
except OSError:
|
|
|
|
pass
|
2017-05-23 19:43:21 +00:00
|
|
|
|
2018-05-10 13:44:18 +00:00
|
|
|
with open(absolute_path, 'w') as f:
|
|
|
|
f.write(value)
|
2017-05-23 19:43:21 +00:00
|
|
|
|
2018-05-10 13:44:18 +00:00
|
|
|
config_dir = tmpdir_factory.mktemp("config")
|
|
|
|
if files:
|
|
|
|
for filepath, value in files.iteritems():
|
|
|
|
normalized_path = normalize_path(filepath)
|
|
|
|
write_file(config_dir, filepath, value)
|
|
|
|
secret['data'][normalized_path] = base64.b64encode(value)
|
2017-05-23 19:43:21 +00:00
|
|
|
|
2018-05-10 13:44:18 +00:00
|
|
|
@urlmatch(netloc=hostname,
|
|
|
|
path='/api/v1/namespaces/quay-enterprise/secrets/quay-enterprise-config-secret$',
|
|
|
|
method='get')
|
|
|
|
def get_secret(_, __):
|
|
|
|
return {'status_code': 200, 'content': json.dumps(secret)}
|
2017-05-23 19:43:21 +00:00
|
|
|
|
2018-05-10 13:44:18 +00:00
|
|
|
@urlmatch(netloc=hostname,
|
|
|
|
path='/api/v1/namespaces/quay-enterprise/secrets/quay-enterprise-config-secret$',
|
|
|
|
method='put')
|
|
|
|
def put_secret(_, request):
|
|
|
|
updated_secret = json.loads(request.body)
|
|
|
|
for filepath, value in updated_secret['data'].iteritems():
|
|
|
|
if filepath not in secret['data']:
|
|
|
|
# Add
|
|
|
|
write_file(config_dir, filepath, base64.b64decode(value))
|
|
|
|
|
|
|
|
for filepath in secret['data']:
|
|
|
|
if filepath not in updated_secret['data']:
|
|
|
|
# Remove.
|
|
|
|
normalized_path = normalize_path(filepath)
|
|
|
|
os.remove(str(config_dir.join(normalized_path)))
|
|
|
|
|
|
|
|
secret['data'] = updated_secret['data']
|
|
|
|
return {'status_code': 200, 'content': json.dumps(secret)}
|
|
|
|
|
|
|
|
@urlmatch(netloc=hostname, path='/api/v1/namespaces/quay-enterprise$')
|
|
|
|
def get_namespace(_, __):
|
|
|
|
return {'status_code': 200, 'content': json.dumps({})}
|
|
|
|
|
|
|
|
@urlmatch(netloc=hostname)
|
|
|
|
def catch_all(url, _):
|
|
|
|
print url
|
|
|
|
return {'status_code': 404, 'content': '{}'}
|
|
|
|
|
|
|
|
with HTTMock(get_secret, put_secret, get_namespace, catch_all):
|
|
|
|
provider = KubernetesConfigProvider(str(config_dir), 'config.yaml', 'config.py',
|
|
|
|
api_host=hostname,
|
|
|
|
service_account_token_path=service_account_token_path)
|
|
|
|
|
|
|
|
# Validate all the files.
|
|
|
|
for filepath, value in files.iteritems():
|
|
|
|
normalized_path = normalize_path(filepath)
|
|
|
|
assert provider.volume_file_exists(normalized_path)
|
|
|
|
with provider.get_volume_file(normalized_path) as f:
|
|
|
|
assert f.read() == value
|
2017-06-27 21:32:12 +00:00
|
|
|
|
2018-05-10 13:44:18 +00:00
|
|
|
yield provider
|
2017-06-27 21:32:12 +00:00
|
|
|
|
2018-05-10 13:44:18 +00:00
|
|
|
|
|
|
|
def test_basic_config(tmpdir_factory):
|
|
|
|
basic_files = {
|
|
|
|
'config.yaml': 'FOO: bar',
|
|
|
|
}
|
|
|
|
|
|
|
|
with fake_kubernetes_api(tmpdir_factory, files=basic_files) as provider:
|
|
|
|
assert provider.config_exists()
|
|
|
|
assert provider.get_config() is not None
|
|
|
|
assert provider.get_config()['FOO'] == 'bar'
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize('filepath', [
|
|
|
|
'foo',
|
|
|
|
'foo/meh',
|
|
|
|
'foo/bar/baz',
|
2017-06-27 21:32:12 +00:00
|
|
|
])
|
2018-05-10 13:44:18 +00:00
|
|
|
def test_remove_file(filepath, tmpdir_factory):
|
|
|
|
basic_files = {
|
|
|
|
filepath: 'foo',
|
|
|
|
}
|
|
|
|
|
|
|
|
with fake_kubernetes_api(tmpdir_factory, files=basic_files) as provider:
|
|
|
|
normalized_path = normalize_path(filepath)
|
|
|
|
assert provider.volume_file_exists(normalized_path)
|
|
|
|
provider.remove_volume_file(normalized_path)
|
|
|
|
assert not provider.volume_file_exists(normalized_path)
|
|
|
|
|
|
|
|
|
|
|
|
class TestFlaskFile(object):
|
|
|
|
def save(self, buf):
|
|
|
|
buf.write('hello world!')
|
|
|
|
|
|
|
|
|
|
|
|
def test_save_file(tmpdir_factory):
|
|
|
|
basic_files = {}
|
|
|
|
|
|
|
|
with fake_kubernetes_api(tmpdir_factory, files=basic_files) as provider:
|
|
|
|
assert not provider.volume_file_exists('testfile')
|
|
|
|
flask_file = TestFlaskFile()
|
|
|
|
provider.save_volume_file(flask_file, 'testfile')
|
|
|
|
assert provider.volume_file_exists('testfile')
|