Skip to content

Commit ee9978e

Browse files
[confcom] bugfix for json input being case-insensitive (#8895)
* making it so the case of fields in a dict doesn't matter when translating configs * updating version to 1.2.6 * updating image layers
1 parent 9f04828 commit ee9978e

File tree

6 files changed

+74
-36
lines changed

6 files changed

+74
-36
lines changed

src/confcom/HISTORY.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
Release History
44
===============
55

6+
1.2.6
7+
++++++
8+
* bugfix making it so the fields in the --input format are case-insensitive
9+
610
1.2.5
711
++++++
812
* consolidating functions for --input policygen

src/confcom/azext_confcom/data/internal_config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "1.2.5",
2+
"version": "1.2.6",
33
"hcsshim_config": {
44
"maxVersion": "1.0.0",
55
"minVersion": "0.0.1"

src/confcom/azext_confcom/template_util.py

Lines changed: 53 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def __exit__(self, exc_type, exc_value, traceback) -> None:
4444
self._client.close()
4545

4646

47-
def case_insensitive_dict_get(dictionary, search_key) -> Any:
47+
def case_insensitive_dict_get(dictionary, search_key, default_value=None) -> Any:
4848
if not isinstance(dictionary, dict):
4949
return None
5050
# if the cases happen to match, immediately return .get() result
@@ -55,7 +55,7 @@ def case_insensitive_dict_get(dictionary, search_key) -> Any:
5555
for key in dictionary.keys():
5656
if key.lower() == search_key.lower():
5757
return dictionary[key]
58-
return None
58+
return default_value
5959

6060

6161
def deep_dict_update(source: dict, destination: dict):
@@ -1572,99 +1572,119 @@ def convert_config_v0_to_v1(old_data):
15721572

15731573
# Prepare the structure of the new JSON
15741574
new_data = {
1575-
config.ACI_FIELD_VERSION: old_data.get(config.ACI_FIELD_VERSION, "1.0"), # default if missing
1576-
config.ACI_FIELD_CONTAINERS_REGO_FRAGMENTS: [], # empty by default in your example
1575+
config.ACI_FIELD_VERSION: case_insensitive_dict_get(
1576+
old_data, config.ACI_FIELD_VERSION, "1.0"
1577+
), # default if missing
1578+
config.ACI_FIELD_CONTAINERS_REGO_FRAGMENTS: [],
15771579
config.ACI_FIELD_CONTAINERS: []
15781580
}
15791581

1580-
old_containers = old_data.get(config.ACI_FIELD_CONTAINERS, [])
1582+
old_containers = case_insensitive_dict_get(old_data, config.ACI_FIELD_CONTAINERS, [])
15811583

15821584
for old_container in old_containers:
15831585
# Build the 'environmentVariables' section in the new format
15841586
new_envs = []
1585-
for env_var in old_container.get(config.ACI_FIELD_CONTAINERS_ENVS) or []:
1587+
for env_var in case_insensitive_dict_get(old_container, config.ACI_FIELD_CONTAINERS_ENVS) or []:
15861588
# Decide if we need 'regex' or not, based on 'strategy' or your custom logic
15871589
# Here we'll assume "strategy"=="re2" means 'regex' = True
15881590
# If strategy is missing or 'string', omit 'regex' or set it to False
15891591
env_entry = {
1590-
config.ACI_FIELD_CONTAINERS_ENVS_NAME: env_var.get(config.ACI_FIELD_CONTAINERS_ENVS_NAME),
1591-
config.ACI_FIELD_CONTAINERS_ENVS_VALUE: env_var.get(config.ACI_FIELD_CONTAINERS_ENVS_VALUE, "")
1592+
config.ACI_FIELD_CONTAINERS_ENVS_NAME: case_insensitive_dict_get(
1593+
env_var, config.ACI_FIELD_CONTAINERS_ENVS_NAME
1594+
),
1595+
config.ACI_FIELD_CONTAINERS_ENVS_VALUE: case_insensitive_dict_get(
1596+
env_var, config.ACI_FIELD_CONTAINERS_ENVS_VALUE, ""
1597+
)
15921598
}
1593-
strategy = env_var.get(config.ACI_FIELD_CONTAINERS_ENVS_STRATEGY)
1599+
strategy = case_insensitive_dict_get(env_var, config.ACI_FIELD_CONTAINERS_ENVS_STRATEGY)
15941600
if strategy == "re2":
15951601
env_entry["regex"] = True
15961602

15971603
new_envs.append(env_entry)
15981604

15991605
# Build the 'execProcesses' from the old 'command'
16001606
exec_processes = []
1601-
old_command_list = old_container.get(config.ACI_FIELD_CONTAINERS_EXEC_PROCESSES, [])
1607+
old_command_list = case_insensitive_dict_get(old_container, config.ACI_FIELD_CONTAINERS_EXEC_PROCESSES, [])
16021608
if old_command_list:
16031609
exec_processes.append({config.ACI_FIELD_CONTAINERS_COMMAND: old_command_list})
16041610

1605-
command = old_container.get(config.ACI_FIELD_CONTAINERS_COMMAND)
1611+
command = case_insensitive_dict_get(old_container, config.ACI_FIELD_CONTAINERS_COMMAND)
16061612

16071613
# Liveness probe => exec process
1608-
liveness_probe = old_container.get(config.ACI_FIELD_CONTAINERS_LIVENESS_PROBE, {})
1609-
liveness_exec = liveness_probe.get(config.ACI_FIELD_CONTAINERS_PROBE_ACTION, {})
1610-
liveness_command = liveness_exec.get(config.ACI_FIELD_CONTAINERS_COMMAND, [])
1614+
liveness_probe = case_insensitive_dict_get(old_container, config.ACI_FIELD_CONTAINERS_LIVENESS_PROBE, {})
1615+
liveness_exec = case_insensitive_dict_get(liveness_probe, config.ACI_FIELD_CONTAINERS_PROBE_ACTION, {})
1616+
liveness_command = case_insensitive_dict_get(liveness_exec, config.ACI_FIELD_CONTAINERS_COMMAND, [])
16111617
if liveness_command:
16121618
exec_processes.append({
16131619
config.ACI_FIELD_CONTAINERS_COMMAND: liveness_command
16141620
})
16151621

16161622
# Readiness probe => exec process
1617-
readiness_probe = old_container.get(config.ACI_FIELD_CONTAINERS_READINESS_PROBE, {})
1618-
readiness_exec = readiness_probe.get(config.ACI_FIELD_CONTAINERS_PROBE_ACTION, {})
1619-
readiness_command = readiness_exec.get(config.ACI_FIELD_CONTAINERS_COMMAND, [])
1623+
readiness_probe = case_insensitive_dict_get(old_container, config.ACI_FIELD_CONTAINERS_READINESS_PROBE, {})
1624+
readiness_exec = case_insensitive_dict_get(readiness_probe, config.ACI_FIELD_CONTAINERS_PROBE_ACTION, {})
1625+
readiness_command = case_insensitive_dict_get(readiness_exec, config.ACI_FIELD_CONTAINERS_COMMAND, [])
16201626
if readiness_command:
16211627
exec_processes.append({
16221628
config.ACI_FIELD_CONTAINERS_COMMAND: readiness_command
16231629
})
16241630

16251631
# Build the 'volumeMounts' section
16261632
volume_mounts = []
1627-
for mount in old_container.get(config.ACI_FIELD_CONTAINERS_MOUNTS) or []:
1633+
for mount in case_insensitive_dict_get(old_container, config.ACI_FIELD_CONTAINERS_MOUNTS) or []:
16281634
# For 'name', we can take the mountType or generate something else:
16291635
# e.g. if mountType is "azureFile", name "azurefile"
1630-
mount_name = mount.get(config.ACI_FIELD_CONTAINERS_MOUNTS_TYPE, "defaultName").lower()
1636+
mount_name = case_insensitive_dict_get(
1637+
mount, config.ACI_FIELD_CONTAINERS_MOUNTS_TYPE, "defaultName"
1638+
).lower()
16311639
volume_mount = {
16321640
config.ACI_FIELD_CONTAINERS_ENVS_NAME: mount_name,
1633-
config.ACI_FIELD_TEMPLATE_MOUNTS_PATH: mount.get(config.ACI_FIELD_CONTAINERS_MOUNTS_PATH),
1634-
config.ACI_FIELD_TEMPLATE_MOUNTS_TYPE: mount.get(config.ACI_FIELD_CONTAINERS_MOUNTS_TYPE),
1635-
config.ACI_FIELD_TEMPLATE_MOUNTS_READONLY: mount.get(config.ACI_FIELD_CONTAINERS_MOUNTS_READONLY, True),
1641+
config.ACI_FIELD_TEMPLATE_MOUNTS_PATH: case_insensitive_dict_get(
1642+
mount, config.ACI_FIELD_CONTAINERS_MOUNTS_PATH
1643+
),
1644+
config.ACI_FIELD_TEMPLATE_MOUNTS_TYPE: case_insensitive_dict_get(
1645+
mount, config.ACI_FIELD_CONTAINERS_MOUNTS_TYPE
1646+
),
1647+
config.ACI_FIELD_TEMPLATE_MOUNTS_READONLY: case_insensitive_dict_get(
1648+
mount, config.ACI_FIELD_CONTAINERS_MOUNTS_READONLY, True
1649+
),
16361650
}
16371651
volume_mounts.append(volume_mount)
16381652

16391653
# Create the container's "properties" object
16401654
container_properties = {
1641-
config.ACI_FIELD_TEMPLATE_IMAGE: old_container.get(config.ACI_FIELD_CONTAINERS_CONTAINERIMAGE),
1655+
config.ACI_FIELD_TEMPLATE_IMAGE: case_insensitive_dict_get(
1656+
old_container, config.ACI_FIELD_CONTAINERS_CONTAINERIMAGE
1657+
),
16421658
config.ACI_FIELD_CONTAINERS_EXEC_PROCESSES: exec_processes,
16431659
config.ACI_FIELD_TEMPLATE_VOLUME_MOUNTS: volume_mounts,
16441660
config.ACI_FIELD_CONTAINERS_ENVS: new_envs,
16451661
config.ACI_FIELD_CONTAINERS_COMMAND: command,
16461662
}
16471663

1648-
if old_container.get(config.ACI_FIELD_TEMPLATE_SECURITY_CONTEXT) is not None:
1664+
if case_insensitive_dict_get(old_container, config.ACI_FIELD_TEMPLATE_SECURITY_CONTEXT) is not None:
16491665
container_properties[
16501666
config.ACI_FIELD_TEMPLATE_SECURITY_CONTEXT
16511667
] = old_container[config.ACI_FIELD_TEMPLATE_SECURITY_CONTEXT]
16521668

1653-
if old_container.get(config.ACI_FIELD_CONTAINERS_ALLOW_ELEVATED) is not None:
1669+
if case_insensitive_dict_get(old_container, config.ACI_FIELD_CONTAINERS_ALLOW_ELEVATED) is not None:
16541670
if config.ACI_FIELD_TEMPLATE_SECURITY_CONTEXT not in container_properties:
16551671
container_properties[config.ACI_FIELD_TEMPLATE_SECURITY_CONTEXT] = {}
16561672
container_properties[
16571673
config.ACI_FIELD_TEMPLATE_SECURITY_CONTEXT
1658-
][config.ACI_FIELD_CONTAINERS_PRIVILEGED] = old_container.get(config.ACI_FIELD_CONTAINERS_ALLOW_ELEVATED)
1674+
][config.ACI_FIELD_CONTAINERS_PRIVILEGED] = case_insensitive_dict_get(
1675+
old_container, config.ACI_FIELD_CONTAINERS_ALLOW_ELEVATED
1676+
)
16591677

1660-
if old_container.get(config.ACI_FIELD_CONTAINERS_WORKINGDIR) is not None:
1678+
if case_insensitive_dict_get(old_container, config.ACI_FIELD_CONTAINERS_WORKINGDIR) is not None:
16611679
container_properties[
16621680
config.ACI_FIELD_CONTAINERS_WORKINGDIR
1663-
] = old_container.get(config.ACI_FIELD_CONTAINERS_WORKINGDIR)
1681+
] = case_insensitive_dict_get(old_container, config.ACI_FIELD_CONTAINERS_WORKINGDIR)
16641682

16651683
# Finally, assemble the new container dict
16661684
new_container = {
1667-
config.ACI_FIELD_CONTAINERS_NAME: old_container.get(config.ACI_FIELD_CONTAINERS_NAME),
1685+
config.ACI_FIELD_CONTAINERS_NAME: case_insensitive_dict_get(
1686+
old_container, config.ACI_FIELD_CONTAINERS_NAME
1687+
),
16681688
config.ACI_FIELD_TEMPLATE_PROPERTIES: container_properties
16691689
}
16701690

@@ -1677,8 +1697,10 @@ def detect_old_format(old_data):
16771697
# we want to encourage customers to transition to the new format. The best way to check for the old format is
16781698
# to see if the json is flattened. This is an appropriate check since the image name is required
16791699
# and they are located in different places in the two formats
1680-
old_containers = old_data.get(config.ACI_FIELD_CONTAINERS, [])
1681-
if len(old_containers) > 0 and old_containers[0].get(config.ACI_FIELD_CONTAINERS_CONTAINERIMAGE) is not None:
1700+
old_containers = case_insensitive_dict_get(old_data, config.ACI_FIELD_CONTAINERS, [])
1701+
if len(old_containers) > 0 and case_insensitive_dict_get(
1702+
old_containers[0], config.ACI_FIELD_CONTAINERS_CONTAINERIMAGE
1703+
) is not None:
16821704
logger.warning(
16831705
"%s %s %s",
16841706
"(Deprecation Warning) The input format used is deprecated.",

src/confcom/azext_confcom/tests/latest/test_confcom_policy_conversion.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ def setUpClass(cls) -> None:
4848
"mountType": "azureFile",
4949
"mountPath": "/mnt/af",
5050
"readonly": true
51+
},
52+
{
53+
"mountType": "emptyDir",
54+
"mountPath": "/mnt/empty",
55+
"readOnly": false
5156
}]
5257
}]
5358
}
@@ -106,6 +111,13 @@ def test_volume_mount_basic_fields(self) -> None:
106111
self.assertEqual(vm[cfg.ACI_FIELD_TEMPLATE_MOUNTS_TYPE], "azureFile")
107112
self.assertTrue(vm[cfg.ACI_FIELD_TEMPLATE_MOUNTS_READONLY])
108113

114+
vm = props[cfg.ACI_FIELD_TEMPLATE_VOLUME_MOUNTS][1]
115+
116+
self.assertEqual(vm[cfg.ACI_FIELD_CONTAINERS_ENVS_NAME], "emptydir")
117+
self.assertEqual(vm[cfg.ACI_FIELD_TEMPLATE_MOUNTS_PATH], "/mnt/empty")
118+
self.assertEqual(vm[cfg.ACI_FIELD_TEMPLATE_MOUNTS_TYPE], "emptyDir")
119+
self.assertFalse(vm[cfg.ACI_FIELD_TEMPLATE_MOUNTS_READONLY])
120+
109121
def test_workingdir_and_allow_elevated_migrated(self) -> None:
110122
props = self._new_cfg[cfg.ACI_FIELD_CONTAINERS][0][
111123
cfg.ACI_FIELD_TEMPLATE_PROPERTIES

src/confcom/azext_confcom/tests/latest/test_confcom_scenario.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -586,9 +586,9 @@ def test_image_layers_python(self):
586586
aci_policy.populate_policy_content_for_all_images()
587587
layers = aci_policy.get_images()[0]._layers
588588
expected_layers = [
589-
"1824eb49720f59202136bd38681f32e57239676c9a423fb1e025aa210aaa22aa",
590-
"8d68e2b0c2c32fa7fab2a5543d94e0b70b5bea400ca7f89f4c925a02ae15f453",
591-
"44e8e0480dc3c0d04564ba87b3ba851cfab008717abdf6be83baf47963599614"
589+
"4b17d51a118cfa6405698048bbb9f258f70c44235cf54dab8977e689d4422c1d",
590+
"374b10f7af01a18c4408738ec38b302f4766ab62c033208c4b86eb7434ed8217",
591+
"c9d8b0df7e0ab9ff83672dd67f154f28fdee0ae0b62c82a3451a44c8e2e29838"
592592
]
593593
self.assertEqual(len(layers), len(expected_layers))
594594
for i in range(len(expected_layers)):

src/confcom/setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
logger.warn("Wheel is not available, disabling bdist_wheel hook")
2121

22-
VERSION = "1.2.5"
22+
VERSION = "1.2.6"
2323

2424
# The full list of classifiers is available at
2525
# https://pypi.python.org/pypi?%3Aaction=list_classifiers

0 commit comments

Comments
 (0)