Skip to content

Commit

Permalink
Merge branch 'hotfix' into 'master'
Browse files Browse the repository at this point in the history
HOTFIX 2.1.1

See merge request arenadata/development/adcm!3725
  • Loading branch information
kuhella committed Apr 11, 2024
2 parents 032e0c0 + 680f1a2 commit 57fb341
Show file tree
Hide file tree
Showing 10 changed files with 137 additions and 17 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ APP_IMAGE ?= hub.adsw.io/adcm/adcm
APP_TAG ?= $(subst /,_,$(BRANCH_NAME))
SELENOID_HOST ?= 10.92.2.65
SELENOID_PORT ?= 4444
ADCM_VERSION = "2.1.0"
ADCM_VERSION = "2.1.1"

.PHONY: help

Expand Down
13 changes: 13 additions & 0 deletions python/adcm/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,10 @@
"format": "{asctime} {levelname} {module} {message}",
"style": "{",
},
"ldap": {
"format": "{levelname} {module}: {message}",
"style": "{",
},
},
"handlers": {
"adcm_file": {
Expand Down Expand Up @@ -266,6 +270,11 @@
"formatter": "adcm",
"stream": "ext://sys.stderr",
},
"ldap_stdout_handler": {
"class": "logging.StreamHandler",
"formatter": "ldap",
"stream": "ext://sys.stdout",
},
},
"loggers": {
"adcm": {
Expand Down Expand Up @@ -297,6 +306,10 @@
"handlers": ["stream_stdout_handler", "stream_stderr_handler"],
"level": LOG_LEVEL,
},
"django_auth_ldap": {
"handlers": ["ldap_stdout_handler"],
"level": LOG_LEVEL,
},
},
}

Expand Down
8 changes: 4 additions & 4 deletions python/api_v2/group_config/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ class Meta:
fields = ["id", "name", "description", "hosts"]

def validate_name(self, value):
model = self.context["view"].get_parent_object()
parent_content_type = ContentType.objects.get_for_model(model=model)
queryset = GroupConfig.objects.filter(name=value, object_type=parent_content_type)
object_ = self.context["view"].get_parent_object()
parent_content_type = ContentType.objects.get_for_model(model=object_)
queryset = GroupConfig.objects.filter(name=value, object_type=parent_content_type, object_id=object_.pk)
if queryset.exists():
raise ValidationError(
f"Group config with name {value} already exists for {parent_content_type} {model.name}"
f"Group config with name {value} already exists for {parent_content_type} {object_.name}"
)
return value
6 changes: 5 additions & 1 deletion python/api_v2/tests/bundles/cluster_one/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@
export:
- boolean

- name: service_1
- &service_1
name: service_1
type: service
version: *version
config:
Expand Down Expand Up @@ -225,3 +226,6 @@

components:
component: {}

- <<: *service_1
name: service_1_clone
6 changes: 4 additions & 2 deletions python/api_v2/tests/test_cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,11 +271,12 @@ def test_service_prototypes_success(self):
)

self.assertEqual(response.status_code, HTTP_200_OK)
self.assertEqual(len(response.json()), 6)
self.assertEqual(len(response.json()), 7)
self.assertListEqual(
[prototype["displayName"] for prototype in response.json()],
[
"service_1",
"service_1_clone",
"service_2",
"service_3_manual_add",
"service_4_save_config_without_required_field",
Expand All @@ -292,11 +293,12 @@ def test_service_candidates_success(self):
)

self.assertEqual(response.status_code, HTTP_200_OK)
self.assertEqual(len(response.json()), 5)
self.assertEqual(len(response.json()), 6)
self.assertListEqual(
[prototype["displayName"] for prototype in response.json()],
[
"service_1",
"service_1_clone",
"service_2",
"service_4_save_config_without_required_field",
"service_5_variant_type_without_values",
Expand Down
2 changes: 1 addition & 1 deletion python/api_v2/tests/test_component.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def setUp(self) -> None:
self.component_2_to_delete = ServiceComponent.objects.get(
prototype__name="component_2", service=self.service_1, cluster=self.cluster_1
)
self.action_1 = Action.objects.get(name="action_1_comp_1")
self.action_1 = Action.objects.get(name="action_1_comp_1", prototype=self.component_1.prototype)

def test_list(self):
response = self.client.get(
Expand Down
65 changes: 65 additions & 0 deletions python/api_v2/tests/test_group_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,71 @@ def setUp(self) -> None:
self.test_user = self.create_user(**self.test_user_credentials)


class TestGroupConfigNaming(BaseServiceGroupConfigTestCase):
def test_create_group_with_same_name_for_different_entities_of_same_type_success(self) -> None:
service_2 = self.add_services_to_cluster(service_names=["service_1_clone"], cluster=self.cluster_1).get()
component_of_service_2 = ServiceComponent.objects.get(service=service_2, prototype__name=self.component_1.name)

with self.subTest("Cluster"):
self.assertEqual(GroupConfig.objects.filter(name=self.cluster_1_group_config.name).count(), 1)

response = self.client.post(
path=reverse(viewname="v2:cluster-group-config-list", kwargs={"cluster_pk": self.cluster_2.pk}),
data={"name": self.cluster_1_group_config.name, "description": "group-config-new"},
)

self.assertEqual(response.status_code, HTTP_201_CREATED)
self.assertEqual(GroupConfig.objects.filter(name=self.cluster_1_group_config.name).count(), 2)

with self.subTest("Service"):
self.assertEqual(GroupConfig.objects.filter(name=self.service_1_group_config.name).count(), 1)

response = self.client.post(
path=reverse(
viewname="v2:service-group-config-list",
kwargs={"cluster_pk": self.cluster_1.pk, "service_pk": service_2.pk},
),
data={"name": self.service_1_group_config.name, "description": "group-config-new"},
)

self.assertEqual(response.status_code, HTTP_201_CREATED)
self.assertEqual(GroupConfig.objects.filter(name=self.service_1_group_config.name).count(), 2)

with self.subTest("Component"):
name = "component_group"
self.assertEqual(GroupConfig.objects.filter(name=name).count(), 0)

response = self.client.post(
path=reverse(
viewname="v2:component-group-config-list",
kwargs={
"cluster_pk": self.cluster_1.pk,
"service_pk": service_2.pk,
"component_pk": component_of_service_2.pk,
},
),
data={"name": name, "description": "group-config-new"},
)

self.assertEqual(response.status_code, HTTP_201_CREATED)
self.assertEqual(GroupConfig.objects.filter(name=name).count(), 1)

response = self.client.post(
path=reverse(
viewname="v2:component-group-config-list",
kwargs={
"cluster_pk": self.cluster_1.pk,
"service_pk": self.service_1.pk,
"component_pk": self.component_1.pk,
},
),
data={"name": name, "description": "group-config-new"},
)

self.assertEqual(response.status_code, HTTP_201_CREATED)
self.assertEqual(GroupConfig.objects.filter(name=name).count(), 2)


class TestClusterGroupConfig(BaseClusterGroupConfigTestCase):
def test_list_success(self):
response = self.client.get(
Expand Down
11 changes: 6 additions & 5 deletions python/cm/adcm_config/checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

from cm.adcm_config.utils import config_is_ro, group_keys_to_flat, proto_ref
from cm.checker import FormatError, SchemaError, process_rule
from cm.errors import raise_adcm_ex
from cm.errors import AdcmEx, raise_adcm_ex
from cm.models import GroupConfig, Prototype, StagePrototype


Expand Down Expand Up @@ -255,10 +255,11 @@ def check_config_type(

if spec["type"] == "variant":
source = spec["limits"]["source"]
if source["strict"] and source["type"] == "inline" and value not in source["value"]:
msg = f'not in variant list: "{source["value"]}"'
raise_adcm_ex(code="CONFIG_VALUE_ERROR", msg=tmpl2.format(msg))
if source["strict"]:
if source["type"] == "inline" and value not in source["value"]:
msg = f'not in variant list: "{source["value"]}"'
raise AdcmEx(code="CONFIG_VALUE_ERROR", msg=tmpl2.format(msg))

if not default and source["type"] in ("config", "builtin") and value not in source["value"]:
msg = f'not in variant list: "{source["value"]}"'
raise_adcm_ex(code="CONFIG_VALUE_ERROR", msg=tmpl2.format(msg))
raise AdcmEx(code="CONFIG_VALUE_ERROR", msg=tmpl2.format(msg))
32 changes: 32 additions & 0 deletions python/cm/migrations/0116_fix_null_jsonfield.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# 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.

# Generated by Django 3.2.23 on 2024-04-09 11:31

from django.db import migrations
from django.db.models import Q


def fix_null_jsonfield(apps, schema_editor):
Action = apps.get_model("cm", "Action")
Action.objects.filter(Q(ui_options__isnull=True) | Q(ui_options="{}")).update(ui_options={})


class Migration(migrations.Migration):
dependencies = [
("cm", "0059_auto_20200904_0910"),
("cm", "0115_auto_20231025_1823"),
]

operations = [
migrations.RunPython(code=fix_null_jsonfield, reverse_code=migrations.RunPython.noop),
]
9 changes: 6 additions & 3 deletions python/rbac/ldap.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,17 @@ def get_groups_by_user_dn(
scope=user_search.scope,
filterstr=user_search.filterstr.replace(replace, search_expr),
)
# Remove references from the Search Result https://www.rfc-editor.org/rfc/rfc4511#section-4.5.3
users = [user for user in users if user[0] is not None]

if len(users) != 1:
err_msg = f"Not one user found by `{search_expr}` search"
return None, err_msg
return [], [], err_msg

user_dn_, user_attrs = users[0]
if user_dn_.strip().lower() != user_dn.strip().lower():
err_msg = f"Got different user dn: {(user_dn_, user_dn)}. Tune search"
return None, err_msg
return [], [], err_msg

group_cns = []
group_dns_lower = []
Expand Down Expand Up @@ -251,7 +254,7 @@ def get_user_model(self) -> type[User]:

@contextmanager
def _ldap_connection(self) -> ldap.ldapobject.LDAPObject:
ldap.set_option(ldap.OPT_REFERRALS, 0)
ldap.set_option(ldap.OPT_REFERRALS, ldap.OPT_OFF)
conn = ldap.initialize(self.default_settings["SERVER_URI"])
conn.protocol_version = ldap.VERSION3
configure_tls(self.is_tls, os.environ.get(CERT_ENV_KEY, ""), conn)
Expand Down

0 comments on commit 57fb341

Please sign in to comment.