Skip to content

Commit

Permalink
issue-9 && issue-14
Browse files Browse the repository at this point in the history
  • Loading branch information
mabulgu committed Aug 1, 2020
1 parent 3adcf29 commit f413810
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 11 deletions.
8 changes: 6 additions & 2 deletions kfk/commons.py
Expand Up @@ -21,9 +21,11 @@ def delete_last_applied_configuration(resource_dict):
del resource_dict["metadata"]["annotations"]["kubectl.kubernetes.io/last-applied-configuration"]


def add_resource_kv_config(config, dict_part):
def add_resource_kv_config(config, dict_part, *converters):
if type(config) is tuple:
for config_str in config:
for converter in converters:
config_str = converter(config_str)
config_arr = get_kv_config_arr(config_str)
dict_part[config_arr[0]] = convert_string_to_type(config_arr[1])
else:
Expand All @@ -36,9 +38,11 @@ def get_kv_config_arr(config_str):
return config_str.split('=')


def delete_resource_config(config, dict_part):
def delete_resource_config(config, dict_part, *converters):
if type(config) is tuple:
for config_str in config:
for converter in converters:
config_str = converter(config_str)
if config_str in dict_part:
del dict_part[config_str]
else:
Expand Down
7 changes: 6 additions & 1 deletion kfk/configs_command.py
Expand Up @@ -2,6 +2,7 @@

from kfk.command import kfk
from kfk import topics_command
from kfk import users_command
from kfk.commons import print_missing_options_for_command


Expand All @@ -11,12 +12,16 @@
@click.option('--delete-config', help='Config keys to remove', multiple=True)
@click.option('--add-config', help='Key Value pairs of configs to add.', multiple=True)
@click.option('--entity-name', help='Name of entity', required=True)
@click.option('--entity-type', help='Type of entity (topics/users/clusters)', required=True)
@click.option('--entity-type', help='Type of entity (topics/users/clusters)',
type=click.Choice(['topics', 'users'], case_sensitive=True))
@kfk.command()
def configs(entity_type, entity_name, add_config, delete_config, describe, cluster, namespace):
"""Add/Remove entity config for a topic, client, user or broker"""
if len(add_config) > 0 or len(delete_config) > 0 or (describe is not None):
if entity_type == "topics":
topics_command.alter(entity_name, None, None, add_config, delete_config, cluster, namespace)
elif entity_type == "users":
users_command.alter(entity_name, None, None, False, False, tuple(), None, None, None, None, None,
add_config, delete_config, cluster, namespace)
else:
print_missing_options_for_command("configs")
5 changes: 3 additions & 2 deletions kfk/users_command.py
Expand Up @@ -9,6 +9,7 @@
print_resource_found_msg
from kfk.config import *
from kfk.kubectl_command_builder import Kubectl
from kfk.utils import snake_to_camel_case


@click.option('-n', '--namespace', help='Namespace to use', required=True)
Expand Down Expand Up @@ -137,11 +138,11 @@ def alter(user, authentication_type, authorization_type, add_acl, delete_acl, op
if len(quota_tuple) > 0:
if user_dict["spec"].get("quotas") is None:
user_dict["spec"]["quotas"] = {}
add_resource_kv_config(quota_tuple, user_dict["spec"]["quotas"])
add_resource_kv_config(quota_tuple, user_dict["spec"]["quotas"], snake_to_camel_case)

if len(delete_quota_tuple) > 0:
if user_dict["spec"].get("quotas") is not None:
delete_resource_config(delete_quota_tuple, user_dict["spec"]["quotas"])
delete_resource_config(delete_quota_tuple, user_dict["spec"]["quotas"], snake_to_camel_case)

user_yaml = yaml.dump(user_dict)
user_temp_file = create_temp_file(user_yaml)
Expand Down
5 changes: 5 additions & 0 deletions kfk/utils.py
Expand Up @@ -30,3 +30,8 @@ def convert_string_to_boolean(str_val):
return True
else:
return False


def snake_to_camel_case(snake_str):
components = snake_str.split('_')
return components[0] + ''.join(x.title() for x in components[1:])
93 changes: 92 additions & 1 deletion tests/test_configs_command.py
Expand Up @@ -11,13 +11,19 @@ def setUp(self):
self.cluster = "my-cluster"
self.namespace = "kafka"
self.topic = "my-topic"
self.user = "my-user"

def test_no_option(self):
result = self.runner.invoke(kfk, ['configs', '--entity-type', 'topics', '--entity-name', self.topic, '-c',
self.cluster, '-n', self.namespace])
self.cluster, '-n', self.namespace])
assert result.exit_code == 0
assert "Missing options: kfk configs" in result.output

def test_wrong_entity_type(self):
result = self.runner.invoke(kfk, ['configs', '--entity-type', 'foos', '--entity-name', self.topic, '-c',
self.cluster, '-n', self.namespace])
assert result.exit_code == 2

@mock.patch('kfk.topics_command.create_temp_file')
@mock.patch('kfk.commons.get_resource_yaml')
@mock.patch('kfk.topics_command.resource_exists')
Expand Down Expand Up @@ -60,3 +66,88 @@ def test_add_two_topic_configs(self, mock_os, mock_resource_exists, mock_get_res
expected_topic_yaml = file.read()
result_topic_yaml = mock_create_temp_file.call_args[0][0]
assert expected_topic_yaml == result_topic_yaml

@mock.patch('kfk.topics_command.create_temp_file')
@mock.patch('kfk.commons.get_resource_yaml')
@mock.patch('kfk.topics_command.resource_exists')
@mock.patch('kfk.topics_command.os')
def test_delete_one_topic_config(self, mock_os, mock_resource_exists, mock_get_resource_yaml, mock_create_temp_file):
mock_resource_exists.return_value = True

with open(r'files/yaml/topic_with_two_configs.yaml') as file:
topic_yaml = file.read()
mock_get_resource_yaml.return_value = topic_yaml

result = self.runner.invoke(kfk,
['configs', '--delete-config', 'cleanup.policy', '--entity-type', 'topics',
'--entity-name', self.topic, '-c', self.cluster, '-n', self.namespace])
assert result.exit_code == 0

with open(r'files/yaml/topic_with_one_config.yaml') as file:
expected_topic_yaml = file.read()
result_topic_yaml = mock_create_temp_file.call_args[0][0]
assert expected_topic_yaml == result_topic_yaml

@mock.patch('kfk.users_command.create_temp_file')
@mock.patch('kfk.commons.get_resource_yaml')
@mock.patch('kfk.users_command.resource_exists')
@mock.patch('kfk.users_command.os')
def test_add_one_user_config(self, mock_os, mock_resource_exists, mock_get_resource_yaml, mock_create_temp_file):
mock_resource_exists.return_value = True

with open(r'files/yaml/user_with_authentication.yaml') as file:
user_yaml = file.read()
mock_get_resource_yaml.return_value = user_yaml

result = self.runner.invoke(kfk,
['configs', '--add-config', 'request_percentage=55', '--entity-type', 'users',
'--entity-name', self.user, '-c', self.cluster, '-n', self.namespace])
assert result.exit_code == 0

with open(r'files/yaml/user_with_one_quota.yaml') as file:
expected_user_yaml = file.read()
result_user_yaml = mock_create_temp_file.call_args[0][0]
assert expected_user_yaml == result_user_yaml

@mock.patch('kfk.users_command.create_temp_file')
@mock.patch('kfk.commons.get_resource_yaml')
@mock.patch('kfk.users_command.resource_exists')
@mock.patch('kfk.users_command.os')
def test_add_two_user_configs(self, mock_os, mock_resource_exists, mock_get_resource_yaml, mock_create_temp_file):
mock_resource_exists.return_value = True

with open(r'files/yaml/user_with_authentication.yaml') as file:
user_yaml = file.read()
mock_get_resource_yaml.return_value = user_yaml

result = self.runner.invoke(kfk,
['configs', '--add-config', 'request_percentage=55', '--add-config',
'consumer_byte_rate=2097152', '--entity-type', 'users',
'--entity-name', self.user, '-c', self.cluster, '-n', self.namespace])
assert result.exit_code == 0

with open(r'files/yaml/user_with_two_quotas.yaml') as file:
expected_user_yaml = file.read()
result_user_yaml = mock_create_temp_file.call_args[0][0]
assert expected_user_yaml == result_user_yaml

@mock.patch('kfk.users_command.create_temp_file')
@mock.patch('kfk.commons.get_resource_yaml')
@mock.patch('kfk.users_command.resource_exists')
@mock.patch('kfk.users_command.os')
def test_delete_one_user_config(self, mock_os, mock_resource_exists, mock_get_resource_yaml, mock_create_temp_file):
mock_resource_exists.return_value = True

with open(r'files/yaml/user_with_two_quotas.yaml') as file:
user_yaml = file.read()
mock_get_resource_yaml.return_value = user_yaml

result = self.runner.invoke(kfk,
['configs', '--delete-config', 'consumer_byte_rate', '--entity-type', 'users',
'--entity-name', self.user, '-c', self.cluster, '-n', self.namespace])
assert result.exit_code == 0

with open(r'files/yaml/user_with_one_quota.yaml') as file:
expected_user_yaml = file.read()
result_user_yaml = mock_create_temp_file.call_args[0][0]
assert expected_user_yaml == result_user_yaml
8 changes: 4 additions & 4 deletions tests/test_users_command.py
Expand Up @@ -241,7 +241,7 @@ def test_alter_user_for_quota(self, mock_os, mock_resource_exists, mock_get_reso

result = self.runner.invoke(kfk,
['users', '--alter', '--user', self.user, '--authentication-type',
'scram-sha-512', '--quota', 'requestPercentage=55',
'scram-sha-512', '--quota', 'request_percentage=55',
'-c', self.cluster, '-n', self.namespace])
assert result.exit_code == 0

Expand All @@ -263,8 +263,8 @@ def test_alter_user_for_two_quotas(self, mock_os, mock_resource_exists, mock_get

result = self.runner.invoke(kfk,
['users', '--alter', '--user', self.user, '--authentication-type',
'scram-sha-512', '--quota', 'requestPercentage=55',
'--quota', 'consumerByteRate=2097152',
'scram-sha-512', '--quota', 'request_percentage=55',
'--quota', 'consumer_byte_rate=2097152',
'-c', self.cluster, '-n', self.namespace])
assert result.exit_code == 0

Expand All @@ -286,7 +286,7 @@ def test_alter_user_with_two_quotas_delete_one_quota(self, mock_os, mock_resourc

result = self.runner.invoke(kfk,
['users', '--alter', '--user', self.user, '--delete-quota',
'consumerByteRate',
'consumer_byte_rate',
'-c', self.cluster, '-n', self.namespace])
assert result.exit_code == 0

Expand Down
7 changes: 6 additions & 1 deletion tests/test_utils.py
@@ -1,4 +1,4 @@
from kfk.utils import convert_string_to_type
from kfk.utils import convert_string_to_type, snake_to_camel_case
from unittest import TestCase


Expand All @@ -20,3 +20,8 @@ def test_convert_string_to_boolean(self):
def test_convert_string_to_str(self):
val_str = "test"
self.assertEqual(convert_string_to_type(val_str), "test")

def test_snake_to_camel_case(self):
val_str = "this_is_the_test_string"
self.assertEqual(snake_to_camel_case(val_str), "thisIsTheTestString")

0 comments on commit f413810

Please sign in to comment.