mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
ACS-6329 Move generate-hazelcast-config.py to community-repo (#2328)
This commit is contained in:
141
repository/scripts/hazelcast-init/generate-hazelcast-config.py
Executable file
141
repository/scripts/hazelcast-init/generate-hazelcast-config.py
Executable file
@@ -0,0 +1,141 @@
|
||||
#!/usr/bin/env python
|
||||
"""Python script to convert Hazelcast cache definitions from Java properties to XML"""
|
||||
__author__="Domenico Sibilio"
|
||||
|
||||
import collections
|
||||
import configparser
|
||||
import xml.etree.ElementTree as ET
|
||||
from xml.dom import minidom
|
||||
from typing import List
|
||||
from pathlib import Path
|
||||
import argparse
|
||||
|
||||
ROOT_PATH = Path(__file__).parent
|
||||
CONFIG_PATH = ROOT_PATH / 'ci-caches.properties'
|
||||
OUTPUT_PATH = ROOT_PATH / 'alfresco-hazelcast-config.xml'
|
||||
TEMPLATE_PATH = ROOT_PATH / 'alfresco-hazelcast-template.xml'
|
||||
TEMPLATE_PLACEHOLDER = '<!-- CACHES DEFINITION (DO NOT REMOVE THIS PLACEHOLDER) -->'
|
||||
PROPS_TO_XML = {
|
||||
# time-to-live-seconds with value = x
|
||||
'timeToLiveSeconds': 'time-to-live-seconds',
|
||||
# max-idle-seconds with value = x
|
||||
'maxIdleSeconds': 'max-idle-seconds',
|
||||
# backup-count with value = x
|
||||
'backup-count': 'backup-count',
|
||||
# read-backup-data with value = x
|
||||
'readBackupData': 'read-backup-data',
|
||||
# merge-policy with value = x
|
||||
'merge-policy': 'merge-policy',
|
||||
# eviction with eviction-policy=x and max-size-policy=PER_NODE and size=${maxItems}
|
||||
'eviction-policy': 'eviction',
|
||||
# near-cache.eviction max-size-policy=ENTRY_COUNT, eviction-policy=LRU and size = x
|
||||
'nearCache.maxSize': 'size',
|
||||
# near-cache.max-idle-seconds with value = x
|
||||
'nearCache.maxIdleSeconds': 'max-idle-seconds',
|
||||
# near-cache.time-to-live-seconds with value = x
|
||||
'nearCache.timeToLiveSeconds': 'time-to-live-seconds',
|
||||
}
|
||||
|
||||
|
||||
def get_prop(prop_key: str):
|
||||
# shortcut to get the property within the default section
|
||||
return config.get('default', prop_key)
|
||||
|
||||
|
||||
def get_cache_name(sections: List[str]):
|
||||
# get the cache name given the full property string split by '.'
|
||||
return '.'.join(sections[0:get_cache_name_index(sections)+1])
|
||||
|
||||
|
||||
def get_cache_name_index(sections: List[str]):
|
||||
# returns the index where the cache name ends
|
||||
# given the full property string split by '.'
|
||||
for i, e in enumerate(sections):
|
||||
if e.endswith('Cache'):
|
||||
return i
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
def get_key(sections: List[str]):
|
||||
# get the property key name given the full property string split by '.'
|
||||
cn_index = get_cache_name_index(sections)
|
||||
key_sections = sections[cn_index+1::]
|
||||
return '.'.join(key_sections)
|
||||
|
||||
|
||||
def prettify(xml_string: str):
|
||||
# format and indent an xml string
|
||||
prettified_xml = minidom.parseString(xml_string).toprettyxml(indent=' ')
|
||||
return '\n'.join([line for line in prettified_xml.splitlines() if line.strip()])
|
||||
|
||||
|
||||
# entrypoint
|
||||
parser = argparse.ArgumentParser(description='A Python script to generate XML Hazelcast cache definitions starting from Java properties.')
|
||||
parser.add_argument('-s', '--source', default=CONFIG_PATH, help='path to the Java properties file to convert')
|
||||
args = parser.parse_args()
|
||||
|
||||
source_path = args.source
|
||||
|
||||
# add dummy section to properties
|
||||
with open(source_path, 'r') as f:
|
||||
cache_props = '[default]\n' + f.read()
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
# preserve property case
|
||||
config.optionxform = str
|
||||
# parse config file
|
||||
config.read_string(cache_props)
|
||||
|
||||
# group properties by cache name
|
||||
props_by_cache = collections.defaultdict(list)
|
||||
for item in config.items('default'):
|
||||
sections = item[0].split('.')
|
||||
if sections[0] == 'cache':
|
||||
cache_name = get_cache_name(sections)
|
||||
key = get_key(sections)
|
||||
value = item[1]
|
||||
props_by_cache[cache_name].append((key, value))
|
||||
|
||||
# read template file
|
||||
with open(TEMPLATE_PATH, 'r') as input:
|
||||
template = input.read()
|
||||
|
||||
# perform template substitutions to apply the caches.properties configuration
|
||||
map_configs = ''
|
||||
for cache, props in props_by_cache.items():
|
||||
props = dict(props)
|
||||
if(props.get('cluster.type') == 'fully-distributed'):
|
||||
map = ET.Element('map', name=cache)
|
||||
near_cache = None
|
||||
for prop, value in props.items():
|
||||
xml_prop = PROPS_TO_XML.get(prop)
|
||||
# handle eviction configuration
|
||||
if prop == 'eviction-policy':
|
||||
ET.SubElement(map, xml_prop,
|
||||
{'eviction-policy': value,
|
||||
'max-size-policy': 'PER_NODE',
|
||||
'size': props.get('maxItems') if props.get('maxItems') else '0'})
|
||||
# handle near-cache configuration
|
||||
elif prop.startswith('nearCache'):
|
||||
if near_cache is None:
|
||||
near_cache = ET.SubElement(map, 'near-cache')
|
||||
if prop.split('.')[1] == 'maxSize':
|
||||
ET.SubElement(near_cache, 'eviction',
|
||||
{'max-size-policy': 'ENTRY_COUNT',
|
||||
'eviction-policy': 'LRU',
|
||||
xml_prop: value})
|
||||
else:
|
||||
ET.SubElement(near_cache, xml_prop).text = value
|
||||
# handle basic map configuration
|
||||
elif xml_prop:
|
||||
ET.SubElement(map, xml_prop).text = value
|
||||
ET.SubElement(map, 'per-entry-stats-enabled').text = 'true'
|
||||
map_configs += minidom.parseString(ET.tostring(map)).childNodes[0].toprettyxml(indent=' ')
|
||||
|
||||
template = template.replace(TEMPLATE_PLACEHOLDER, map_configs)
|
||||
|
||||
# produce actual Hazelcast config file
|
||||
with open(OUTPUT_PATH, 'w') as output:
|
||||
output.write(prettify(template))
|
||||
print(f"Generated XML Hazelcast config: {OUTPUT_PATH}")
|
Reference in New Issue
Block a user