forum.bitel.ru http://forum.bitel.ru/ |
|
Оптимизация конфига устройств http://forum.bitel.ru/viewtopic.php?f=44&t=7243 |
Страница 1 из 2 |
Автор: | Cromeshnic [ 24 сен 2012, 12:59 ] |
Заголовок сообщения: | Оптимизация конфига устройств |
Сейчас для radius-устройств соответствие "опция" -> "набор радиус-атрибутов" прописывается напрямую. Выглядит это примерно так: Вложение: options.png Соответственно, в конфиге типа устройства нужно будет прописывать однотипные атрибуты для каждого: Код: radius.inetOption.12.attributes=cisco-SSG-Account-Info=AINET478 radius.inetOption.55.attributes=cisco-SSG-Account-Info=AINET650 ...(несколько десятков строк)... ISG: Код: radius.inetOption.12.attributes=cisco-SSG-Service-Info=IINET478;{@accounting900.isgservice.attributes};{@internet.default.attributes};cisco-SSG-Service-Info=QU;;478000;;89625;;D;;478000;;89625 radius.inetOption.55.attributes=cisco-SSG-Service-Info=IINET650;{@accounting900.isgservice.attributes};{@internet.default.attributes};cisco-SSG-Service-Info=QU;;650000;;121875;;D;;65000;;121875 ...(несколько десятков строк)... Для redback: Код: radius.inetOption.12.attributes=Service-Name:3=RSE-BASIC-INET;Service-Options:3=1;Service-Parameter:3=Rate-Inet=478 Burst-Inet=59750 ExBurst-Inet=119500 radius.inetOption.55.attributes=Service-Name:3=RSE-BASIC-INET;Service-Options:3=1;Service-Parameter:3=Rate-Inet=650 Burst-Inet=81250 ExBurst-Inet=162500 ...(несколько десятков строк)... А ещё есть группа LOCAL и т.п. ... Удобнее было бы определить один шаблон для всех дочерних опций в группе "[INET]": Код: radius.inetOption.1.template=cisco-SSG-Account-Info=A<name> Код: radius.inetOption.1.template=cisco-SSG-Service-Info=I<name>;{@accounting900.isgservice.attributes};{@internet.default.attributes};cisco-SSG-Service-Info=QU;;<speed>000;;<cisco.burst>;;D;;<speed>000;;<cisco.burst> Код: radius.inetOption.1.template=Service-Name:3=RSE-BASIC-INET;Service-Options:3=1;Service-Parameter:3=Rate-Inet=<speed> Burst-Inet=<redback.burst> ExBurst-Inet=<redback.exburst> Где 1 - код опции-группы "[INET]". Параметры задавать в конфиге опции INET: Вложение: inet650.png План такой: В AbstractRadiusServiceActivator.init() : 1. подключаемся к mysql, выгребаем нужные конфиги опций. 2. запиливаем optionRadiusAttributesMap по шаблонам из конфига устройства "radius.inetOption.x.template" для всех дочерних опций опции x. 3. добавляем в optionRadiusAttributesMap явно определённые атрибуты из "radius.inetOption.y.attributes", если такие есть. Плюсы: + Скорости указываются в одном месте, наглядно. + Можно использовать один параметр опции для нескольких типов устройств (один и тот же speed по-разному трактовать для разных типов устройств например) + Сокращается размер конфига устройства/типа устройства. Минусы: - Ломается обработка в ISGPPPoEServiceActivator, где соответствие "опция->сервис ISG" выгребается из radius.inetOption.<y>.attributes. Но, имхо, это потому, что так выгребать изначально неправильно. Логичнее получать из optionRadiusAttributesMap например. Могу написать код, скажем, RadiusAttributeSet.newRadiusAttributeSetRealmMapByTemplate(...) Уже сделал нечто подобное для своего RedBack ServiceActivator-а, только более костыльно. Что скажут разработчики? ![]() |
Автор: | Cromeshnic [ 24 сен 2012, 13:04 ] |
Заголовок сообщения: | Re: Оптимизация конфига устройств |
Цитата: - Ломается обработка в ISGPPPoEServiceActivator, где соответствие "опция->сервис ISG" выгребается из radius.inetOption.<y>.attributes. У себя обошёл через создание "подставного" конфига устройства, в котором шаблон "radius.inetOption.x.template" превращён в набор "radius.inetOption.y.attributes": Код: ParameterMap newDeviceConfig = deviceConfig.inherit(pConf);
super.init( setup, moduleId, device, deviceType, newDeviceConfig ); |
Автор: | Cromeshnic [ 24 сен 2012, 13:06 ] |
Заголовок сообщения: | Re: Оптимизация конфига устройств |
Плюс, можно подумать и реализовать простенький калькулятор, чтобы burst брать не из конфига, а рассчитывать по формулам. |
Автор: | Cromeshnic [ 26 сен 2012, 12:54 ] |
Заголовок сообщения: | Re: Оптимизация конфига устройств |
Нет, ну правда! Картинка для привлечения внимания: ![]() |
Автор: | Cromeshnic [ 27 сен 2012, 14:50 ] |
Заголовок сообщения: | Re: Оптимизация конфига устройств |
![]() |
Автор: | snark [ 02 окт 2012, 21:50 ] |
Заголовок сообщения: | Re: Оптимизация конфига устройств |
![]() Ну ты понел ... |
Автор: | Phricker [ 03 окт 2012, 00:21 ] |
Заголовок сообщения: | Re: Оптимизация конфига устройств |
Вложение: 9598592.png Так лучше ![]() |
Автор: | Amir [ 03 окт 2012, 14:31 ] |
Заголовок сообщения: | Re: Оптимизация конфига устройств |
А для чего radius.inetOption.1.template, а не radius.inetOption.template, например? |
Автор: | Cromeshnic [ 04 окт 2012, 06:25 ] |
Заголовок сообщения: | Re: Оптимизация конфига устройств |
Цитата: Где 1 - код опции-группы "[INET]". разным группам опций - разные шаблоны |
Автор: | Cromeshnic [ 13 ноя 2012, 12:38 ] |
Заголовок сообщения: | Re: Оптимизация конфига устройств |
Запилил. Потестировал предварительно. На практике ещё не применял. Изменил бителовский dyn-класс AbstractRadiusServiceActivator Ещё нужно поправить ISGPPPoEServiceActivator, чтобы брал соответствие "опция"-"сервис ISG" не из конфига, а из optionRadiusAttributesMap. Поскольку при обновлении это всё перетрётся, то скорее всего сделаю свой AbstractRadiusServiceActivator, в своём package, и все стандартные активаторы скопирую туда. Короче, заведу себе отдельный branch. Может быть попозже выложу куда-нибудь. Так или иначе, всё равно буду переделывать активаторы под себя ведь. Можно конечно каждый раз просить разработчиков внедрять более-менее абстрактные фичи у себя, но это муторно и опасно для них. Возникает такой вопрос - как быть с копирайтом, если я скопипастил, скажем ru.bitel.bgbilling.modules.inet.dyn.device.radius.AbstractRadiusServiceActivator в ru.dsi.bgbilling.modules.inet.dyn.device.radius.AbstractRadiusServiceActivator, поменял там кой-чего и выложил здесь, или на github например? |
Автор: | Cromeshnic [ 13 ноя 2012, 12:40 ] |
Заголовок сообщения: | Re: Оптимизация конфига устройств |
diff: Код: 5,9c5,7
< import java.util.Arrays; < import java.util.HashSet; < import java.util.List; < import java.util.Map; < import java.util.Set; --- > import java.util.*; > import java.util.regex.Matcher; > import java.util.regex.Pattern; 14a13,14 > import ru.bitel.bgbilling.common.BGException; > import ru.bitel.bgbilling.kernel.container.managed.ServerContext; 28a29,30 > import ru.bitel.bgbilling.modules.inet.api.common.bean.InetOption; > import ru.bitel.bgbilling.modules.inet.api.server.bean.InetOptionDao; 31a34,35 > import ru.bitel.common.Preferences; > import ru.bitel.common.TreeUtils; 32a37 > import ru.bitel.common.worker.ThreadContext; 50a56,60 > /** > * id модуля > */ > protected int moduleId; > 157a168 > this.moduleId = moduleId; 185c196,204 < optionRadiusAttributesMap = RadiusAttributeSet.newRadiusAttributeSetRealmMap( deviceConfig, deviceConfig.get( "sa.radius.option.attributesPrefix", defaultOptionsPrefix ), "attributes" ); --- > String optionsPrefix = deviceConfig.get( "sa.radius.option.attributesPrefix", defaultOptionsPrefix ); > String param = "attributes"; > ParameterMap newDeviceConfig = deviceConfig; > try{ > newDeviceConfig = parseInetOptionRadiusAttributesTemplates(deviceConfig, optionsPrefix, "template", param); > }catch (BGException e){ > logger.error("Error parsing option radius attribute templates: ", e); > } > optionRadiusAttributesMap = RadiusAttributeSet.newRadiusAttributeSetRealmMap( newDeviceConfig, optionsPrefix, param ); 359a379,550 > > /** > * Функция обрабатывает конфиг устройства, находит в нём вхождения вида <prefix><option_id>.<param>=<template> или > * <prefix><option_id>.<realm>.<param>=<template> и добавляет соответствующие параметры в результирующий конфиг для всех > * дочерних опций sub_option_id опции option_id: > * <prefix><sub_option_id>.<targetParam>=<value> или <prefix><sub_option_id>.<realm>.<targetParam>=<value> > * значение параметра value получается из шаблона template подстановкой значений параметров из конфига опции. > * Например cisco-SSG-Service-Info=QU;;$(speed)000;;$(cisco.burst);;D;;$(speed)000;;$(cisco.burst) > * -> > * [ > * speed=100 > * cisco.burst=50000 > * ] > * -> > * cisco-SSG-Service-Info=QU;;100000;;50000;;D;;100000;;50000 > * При этом конфиги опций наследуются, начиная с родительской option_id > * Также при обработке дерева к конфигу опции добавляется параметр name=option.getTitle(), т.е. в шаблонах можно > * использовать параметр $(name) - имя опции > * > * @param deviceConfig - исходный конфиг устройства > * @param prefix - ex "radius.inetOption." > * @param param - ex "template" > * @param targetParam - ex "attributes" > * @return возвращает новый конфиг устройства, в который добавлены атрибуты опций, полученные по шалонам > * @see #insertVariablesValues(String, ru.bitel.common.ParameterMap) > * @see #processSubTree > */ > private ParameterMap parseInetOptionRadiusAttributesTemplates(ParameterMap deviceConfig, > String prefix, String param, String targetParam) throws BGException { > Map<String, String> conf = new HashMap<String, String>(); > ServerContext ctx = (ServerContext) ThreadContext.get(); > InetOptionDao inetOptionDao = new InetOptionDao(ctx.getConnectionSet().getSlaveConnection(), this.moduleId); > > //Список всех опций > List<InetOption> optionList = inetOptionDao.list(); > //Карта : id опции -> опция из optionList > Map<Integer, InetOption> optionMap = new HashMap<Integer, InetOption>(); > for (InetOption d : optionList) > { > optionMap.put(d.getId(), d); > } > //Строим полное дерево опций > InetOption root = new InetOption(); > root.setGroupIntersection(true); > root = TreeUtils.tree(optionList, root);//Теперь всем опциям из optionList назначены потомки > > // > //Можно было бы зайти с другой стороны - перебирать все параметры вида "prefix<id>.param", брать по id опцию и > //обрабатывать её поддерево, но тогда нарушается порядокобработки - если в дереве одной опции с шаблоном будет > //другой шаблон, то не факт, что последний перетрётся. В случае с рекурсивным перебором - всё ок > processTree(root,deviceConfig,conf,prefix,param,targetParam); > //перебираем все , например radius.inetOption.1.template > > inetOptionDao.recycle(); > > //Поверх полученных значений пишем значения из конфига, т.к. они более приоритетны, чем шаблоны. > //Т.е. если в deviceConfig задать шаблон radius.inetOption.10.template = xxx и > //radius.inetOption.12.attributes = yyy, где опция 12 лежит в субветке опции 10, > //то radius.inetOption.12.attributes будет приоритетнее > ParameterMap newConf = (new Preferences(conf)).inherit(deviceConfig); > > return newConf; > } > > /** > * Рекурсивная обработка всех опций модуля Inet - если для какой то опции в конфиге устройства deviceConfig найдётся > * параметр <prefix><option_id>.<param>=... или параметр <prefix><option_id>.<realmname>.<param>=... , > * то опять же рекурсивно обрабатываем субдерево для этой опции: см. processSubTree > * > * @param node > * @param deviceConfig > * @param conf > * @param prefix > * @param param > * @param targetParam > * > * @see #processSubTree(ru.bitel.bgbilling.modules.inet.api.common.bean.InetOption, java.util.Map, String, String, String, ru.bitel.common.ParameterMap) > */ > private void processTree(InetOption node, ParameterMap deviceConfig, Map<String, String> conf, String prefix, String param, String targetParam){ > ParameterMap sub = deviceConfig.sub(prefix+node.getId()+"."); > if(null==sub){return;} > String templateValue; > String targetParamLocal; > > for(Map.Entry<String, ParameterMap> e : sub.subKeyed("").entrySet()){ > targetParamLocal = targetParam; //"attributes" > if(param.equals(e.getKey())){//radius.inetOption.1.template=<templateValue> > templateValue=e.getValue().get("", null); > }else{//radius.inetOption.1.<realm>.template > templateValue=e.getValue().get(param, null); > targetParamLocal=e.getKey()+"."+targetParam; //"<realm>.attributes" > } > if(null!=templateValue){ > //рекурсивно обрабатываем поддерево > this.processSubTree(node, conf, prefix, targetParamLocal, templateValue, null); > } > } > > //рекурсия > if(node.getChildren()!=null){ > for (InetOption child : node.getChildren()){ > processTree(child, deviceConfig, conf, prefix, param, targetParam); > } > } > } > > /** > * Рекурсивно обрабатываем поддерево опций модуля Inet, пишем в конфиг conf параметры <prefix><node.id>.<param>=parseTemplate(templateValue) > * @param node - родительский узел, должен содержать потомков в getChildren() > * @param conf - итоговый конфиг, куда пишем результаты > * @param prefix - префикс параметра конфига, например "inetOption." > * @param param - суффикс параметра, например "attributes" > * @param templateValue - шаблон значения параметра. обрабатывается функцией insertVariablesValues > * @param parentNodeConf - значение родительский конфиг. Необходимо для наследования конфигов в пределах поддерева. Может быть null. > * @see #insertVariablesValues(String, ru.bitel.common.ParameterMap) > */ > private void processSubTree(InetOption node, Map<String, String> conf, String prefix, String param, String templateValue, ParameterMap parentNodeConf){ > ParameterMap nodeConf = new Preferences(node.getConfig(), "\n"); > //Добавляем в конфиг опции параметр name=<имя_опции> > ((Preferences)nodeConf).set("name", node.getTitle()); > //Конфиг для опций будет наследоваться внутри субветки > if(parentNodeConf!=null){ > nodeConf = parentNodeConf.inherit(nodeConf); > } > > //Обрабатываем шаблон, добавляем текущий узел в итоговый конфиг > //ex: radius.inetOption.<id>.attributes=blablabla;foo; > conf.put(prefix+node.getId()+"."+param, insertVariablesValues(templateValue, nodeConf)); > > //рекурсивно обрабатываем дочерние узлы > if(node.getChildren()!=null){ > for(InetOption child : node.getChildren()){ > processSubTree(child, conf, prefix, param, templateValue, nodeConf); > } > } > } > > /** > * Подстановка переменных из data в value по шаблону "blabla$(varibale.1.value)" -> "blabla123" > * @param value example: $(speed)000;;$(cisco.burst);;D;;$(speed)000;;$(cisco.burst) > * @param data соответствие значений, например: speed=100, cisco.burst=50000 > * @return > */ > private String insertVariablesValues(String value, ParameterMap data){ > > Matcher m = Pattern.compile("\\$\\(([\\w\\.]+)\\)").matcher(value); > if (m.find()){ > StringBuffer newValue = new StringBuffer(value.length() + 16); > String varName = m.group(1); > > String var = data.get(varName, null); > if (var != null){ > var = Matcher.quoteReplacement(var); > m.appendReplacement(newValue, var); > } > > while (m.find()){ > var = data.get(m.group(1), null); > if (var == null) > continue; > var = Matcher.quoteReplacement(var); > m.appendReplacement(newValue, var); > } > > m.appendTail(newValue); > > return newValue.toString(); > } > > return value; > } > |
Автор: | Cromeshnic [ 16 ноя 2012, 07:24 ] |
Заголовок сообщения: | Re: Оптимизация конфига устройств |
FAIL Опции конфигурации "radius.inetOption" читаются ещё и самим InetNas-ом, вне динамического кода. Итого, этот конфиг используется напрямую в 3 местах: - InetNas - AbstractRadiusServiceActivator - ISGPPPoEServiceActivator абстракция, my ass |
Автор: | Cromeshnic [ 16 ноя 2012, 08:34 ] |
Заголовок сообщения: | Re: Оптимизация конфига устройств |
Фактически, в таком виде опции опции модуля Inet ничем не отличаются от наборов радиус-атрибутов. Посмотрим, что даёт нам прямая привязка "опция"->"набор радиус атрибутов": - Выдача атрибутов radiusProcessor-ом при подключении (InetNas). - Выдача атрибутов serviceActivator-ом при подключении опции Но тут возникают вопросы: - что делать при отключении опции? - как быть, если логика устройства более сложная, чем прямое соответствие "опция"-"набор радиус-атрибутов"? Например, SmartEdge 100: Цитата: Допустим, к у клиента было 2 сервиса: inet (интернет) и dsiserv (доступ к нашим серверам в отдельную трубу). Если мы хотим поменять их параметры, то проблем нет - в зависимости от опций модуля посылаем CoA и радуемся. Но если мы захотим подключить третий сервис, скажем, local (локальный трафик в отдельную трубу), то придется сначала сменить ему набор разрешенных сервисов. Набор сервисов задаётся радиус-атрибутами QoS-Policing-Profile-Name и QoS-Metering-Profile-Name. Параметры конкретного сервиса - RSE-Service-Name. (с) внутренняя документацияТ.е. появляется ещё одна сущность - "пакет сервисов", который должен строиться на основе активных в данный момент опций. Эту логику можно реализовать в ServiceActivator-е, но только для смены сервисов. При первичной авторизации же отрабатывает стандартный RadiusProcessor. Т.о. логика работы устройства вынесена в ServiceActivator не полностью. Первичную авторизацию нужно тоже прогонять через ServiceActivator. |
Автор: | Cromeshnic [ 16 ноя 2012, 08:34 ] |
Заголовок сообщения: | Re: Оптимизация конфига устройств |
Это как сделать крутой MVC-веб-фреймворк, но захардкодить стартовую страницу. |
Автор: | Cromeshnic [ 16 ноя 2012, 12:12 ] |
Заголовок сообщения: | Re: Оптимизация конфига устройств |
Другой пример, когда на основе опций строится профиль для оборудования - Cisco SCE. Там на железке преконфигурируются packageId - id профиля, назначаемого абоненту. А индивидуально скорости на разные типы трафика например, или другие параметры, задать нельзя. |
Автор: | Amir [ 16 ноя 2012, 13:32 ] |
Заголовок сообщения: | Re: Оптимизация конфига устройств |
А какую логику лучше в ServiceActivator(тут скорее ProtocolHandler, по принципу вызовов методов он больше подходит), кроме выдачи атрибутов, вынести? Все-таки не хочется усложнять и весь InetRadiusProcessor туда переносить. |
Автор: | Cromeshnic [ 16 ноя 2012, 14:04 ] |
Заголовок сообщения: | Re: Оптимизация конфига устройств |
Хм, я подумаю. |
Автор: | Cromeshnic [ 19 ноя 2012, 10:33 ] |
Заголовок сообщения: | Re: Оптимизация конфига устройств |
Посмотрел класс InetRadiusProcessor. Вроде больше ничего не нужно выносить в активатор. Amir писал(а): тут скорее ProtocolHandler, по принципу вызовов методов он больше подходит ProtocolHandler на более низком уровне работает - обрабатывает радиус-пакеты и ничего не знает об опциях и InetConnection. Мне кажется, логично вынести из InetRadiusProcessor.authorization() логику назначения атрибутов по опциям: Код: nas.addRadiusAttributes(...) в ServiceActivator.onAuthAccept(...) При этом, если connection.start.fromAccept=1, то в метод можно сразу передавать и InetConnection, на всякий случай. Туда же попадает выдача атрибутов для disable realm-а. Старую логику сделать в виде затычки в ServiceActivatorAdapter. Что думаете? |
Автор: | Amir [ 19 ноя 2012, 14:11 ] |
Заголовок сообщения: | Re: Оптимизация конфига устройств |
Цитата: ProtocolHandler на более низком уровне работает - обрабатывает радиус-пакеты и ничего не знает об опциях и InetConnection. В этом согласен, но проблема в том, что этот метод будет вызываться не так, как connectionModify - без предварительных вызовов connect и последующем disconnect, к тому же вообще в других(сразу многих) потоках - т.е. так же, как сейчас происходит вызов в ProtocolHander.Как бы не привело к путанице (например, использовании одного и того же java.sql.Connection в connectionModify и onAuthAccept). |
Автор: | Cromeshnic [ 19 ноя 2012, 14:36 ] |
Заголовок сообщения: | Re: Оптимизация конфига устройств |
Хм, ну да, тогда получается ближе к предобработке. Тогда и InetConnection не нужно передавать. |
Автор: | Cromeshnic [ 19 ноя 2012, 15:24 ] |
Заголовок сообщения: | Re: Оптимизация конфига устройств |
Завтра посмотрю, как радиус-атрибуты для InetNas можно причесать. Получается, атрибуты выдаются и Nas-ом стандартно, и ServiceActivator-ом. Надо подумать, как это можно объединить и абстрагировать. |
Автор: | Cromeshnic [ 20 ноя 2012, 08:13 ] |
Заголовок сообщения: | Re: Оптимизация конфига устройств |
Получается, логика работы с радиус-атрибутами размазана по классам: InetNas ProtocolHandler ServiceActivator Это: - выдача атрибутов для reaml-а - атрибуты сервиса - disable-атрибуты - атрибуты на основе опций При этом многие вещи дублируются, например проверка состояния сессии по наличию определённых атрибутов (disablePatternAttributes) есть в AbstractRadiusProtocolHandler и в InetNas. Мне кажется, логично было бы сделать отдельный класс, наподобие ProtocolHandler-а, который бы занимался работой с радиус-атрибутами, и был доступен из InetNas, ProtocolHandler, ServiceActivator. Или добавить соответствующие методы в ProtocolHandler (правда как его получить из активатора?). Плюс возможность его реализации в динамическом коде. Конкретно мне это нужно для двух вещей: - собственный способ задания соответствия "опция -> набор радиус-атрибутов" (оптимизация конфига устройств) - сложная логика задания атрибутов на основе опций для SE 100 |
Автор: | Cromeshnic [ 20 ноя 2012, 14:32 ] |
Заголовок сообщения: | Re: Оптимизация конфига устройств |
Имеет смысл надеяться на доработку, или придётся прописывать 100500 строчек "radius.inetOption."? |
Автор: | Amir [ 20 ноя 2012, 14:49 ] |
Заголовок сообщения: | Re: Оптимизация конфига устройств |
Имеет ![]() |
Автор: | Cromeshnic [ 22 ноя 2012, 15:02 ] |
Заголовок сообщения: | Re: Оптимизация конфига устройств |
А когда? Хочу внедрять Inet уже наконец ![]() |
Автор: | Cromeshnic [ 27 ноя 2012, 10:09 ] |
Заголовок сообщения: | Re: Оптимизация конфига устройств |
up |
Автор: | Amir [ 27 ноя 2012, 13:36 ] |
Заголовок сообщения: | Re: Оптимизация конфига устройств |
Уже почти ![]() По поводу конфига, будет поддержка Опции: Код: - 1 - Опция 1 В конфигурации устройства: -- 2 - Опция 2 [speed=100] -- 3 - Опция 3 [speed=200] Код: radius.inetOption.1.template=Speed=$speed
|
Автор: | Cromeshnic [ 27 ноя 2012, 13:49 ] |
Заголовок сообщения: | Re: Оптимизация конфига устройств |
Круто! Тогда сразу 2 фичреквеста туда: - встроенный параметр $name - title опции (или $title, неважно) - наследование конфигов в дереве опций У меня это сделано так: Код: ParameterMap nodeConf = new Preferences(node.getConfig(), "\n");
//Добавляем в конфиг опции параметр name=<имя_опции> if(node.getTitle()!=null){ ((Preferences)nodeConf).set("name", node.getTitle()); } //Конфиг для опций будет наследоваться глобально if(parentNodeConf!=null){ nodeConf = parentNodeConf.inherit(nodeConf); } |
Автор: | Cromeshnic [ 27 ноя 2012, 13:51 ] |
Заголовок сообщения: | Re: Оптимизация конфига устройств |
Олсо, вот глобальный скрипт, который по шаблону генерирует строки radius.inetOption: Код: package ru.dsi.bgbilling.kernel.scripts.global;
import ru.bitel.bgbilling.kernel.script.server.dev.GlobalScriptBase; import ru.bitel.bgbilling.modules.inet.api.common.bean.InetOption; import ru.bitel.bgbilling.modules.inet.api.server.bean.InetOptionDao; import ru.bitel.bgbilling.server.util.Setup; import ru.bitel.common.ParameterMap; import ru.bitel.common.Preferences; import ru.bitel.common.TreeUtils; import ru.bitel.common.sql.ConnectionSet; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; public class GenerateInetDeviceConf extends GlobalScriptBase { /** * Шаблон поиска подстановок для значений опций. */ private Pattern optionValuePattern; protected Map<Integer, ParameterMap> optionValues; protected Map<String, ParameterMap> featureConfig; @Override public void execute( Setup setup, ConnectionSet connectionSet ) throws Exception { int mid=28; ParameterMap deviceConfig = new Preferences( "# INET\n" + "sa.feature.inet.id=1\n" + "sa.feature.inet.values.attributes=cisco-SSG-Account-Info=A$(name)","\n"); this.featureConfig = new HashMap<String, ParameterMap>(); this.optionValues = new TreeMap<Integer, ParameterMap>(); this.optionValuePattern = Pattern.compile("\\$\\(([\\w\\.]+)\\)"); InetOptionDao inetOptionDao = new InetOptionDao(connectionSet.getSlaveConnection(), mid); //Список всех опций List<InetOption> optionList = inetOptionDao.list(); //Строим полное дерево опций InetOption root = new InetOption(); root.setGroupIntersection(true); root.setId(0); root = TreeUtils.tree(optionList, root);//Теперь всем опциям из optionList назначены потомки int featureId; //Временная карта root_option_id -> feature. Обратная к featureToRootOptionMap. Map<Integer, String> rootOptionToFeatureMap = new TreeMap<Integer, String>(); //Берём конфиги признаков (фич) //sa.feature.<featureName>.id=<root_option_id> //sa.feature.<featureName>.values.<something1>=<...> //sa.feature.<featureName>.values.<something2>=<...> for(Map.Entry<String, ParameterMap> e : deviceConfig.subKeyed( "sa.feature.").entrySet()){ featureId = e.getValue().getInt("id", -1); if(featureId==-1){ print("No root option id found for feature " + e.getKey() + ". 'sa.feature." + e.getKey() + ".id=<inet_root_option_id>' must be defined"); continue; } this.featureConfig.put(e.getKey(),e.getValue()); //featureToRootOptionMap.put(e.getKey(),featureId); rootOptionToFeatureMap.put(featureId, e.getKey()); } //Рекурсивно обходим опции модуля Inet, заполняем optionValues и optionToFeatureMap processTree(root, deviceConfig, rootOptionToFeatureMap, null, null); print("\n\n\n"); //генерируем конфиг: for(Map.Entry<Integer,ParameterMap> e : optionValues.entrySet()){ print("#"+inetOptionDao.get(e.getKey()).getTitle()); for(Map.Entry<String, String> p : e.getValue().entrySet()){ print("radius.inetOption."+e.getKey()+"."+p.getKey()+"="+p.getValue()); } } inetOptionDao.recycle(); } /** * Рекурсивно обрабатываем дерево тарифных опций, заполняем optionValues и optionToFeatureMap по конфигурации * фич featureToRootOptionMap и featureConfig * При этом конфиги опций наследуются, а значения опций в optionValues собираются по шаблону из * featureConfig.sub("values.") подстановкой параметров из конфига опции по шаблону optionValuePattern * * @param node - текущий узел дерева для рекурсии * @param rootOptionToFeatureMap - соответствие "корневая опция фичи" -> "фича" * @param currentFeature - текущая фича, в поддереве которой мы находимся. null - если нет * @param parentNodeConf - конфиг родительского узла */ private void processTree(InetOption node, ParameterMap deviceConfig, Map<Integer, String> rootOptionToFeatureMap, String currentFeature, ParameterMap parentNodeConf){ ParameterMap nodeConf = new Preferences(node.getConfig(), "\n"); //Добавляем в конфиг опции параметр name=<имя_опции> if(node.getTitle()!=null){ ((Preferences)nodeConf).set("name", node.getTitle()); } //Конфиг для опций будет наследоваться глобально if(parentNodeConf!=null){ nodeConf = parentNodeConf.inherit(nodeConf); } //Если текущая ветка является рутом для какой-то фичи, то устанавливаем текущую фичу if(rootOptionToFeatureMap.containsKey(node.getId())){ currentFeature = rootOptionToFeatureMap.get(node.getId()); } //обрабатываем фичу, если мы внутри её дерева if(currentFeature!=null){ //this.optionToFeatureMap.put(node.getId(), currentFeature); parseOptionValues(node.getId(), currentFeature, nodeConf); } //Ищем индивидуальный конфиг для опции, если есть //sa.option.<id>.values.* //перетирает values для фичи Preferences optValues = new Preferences(); String value; for(Map.Entry<String, String> e : deviceConfig.sub("sa.option."+node.getId()+".values.").entrySet()){ value = this.parseTemplate(e.getValue(), nodeConf); if(null!=value){ optValues.set(e.getKey(),value); } } if(optValues.entrySet().size()>0){ //this.optionValues.put(node.getId(),optValues); ParameterMap map = this.optionValues.get(node.getId()); if(map!=null){//Если для опции уже что-то определено, то добавляем к этому и переопределяем при необходимости map = map.inherit(optValues);//переопределяем map значениями из optValues this.optionValues.put(node.getId(), map); }else{//раньше у опции не было значений - просто берём наши this.optionValues.put(node.getId(), optValues); } } //Также пишем в лог if(this.optionValues.containsKey(node.getId())){ print("option values for id=" + node.getId() + " (" + node.getTitle() + ") :\n" + this.optionValues.get(node.getId()).toString()); } //рекурсивно обрабатываем дочерние узлы if(node.getChildren()!=null){ for(InetOption child : node.getChildren()){ processTree(child, deviceConfig, rootOptionToFeatureMap, currentFeature, nodeConf); } } } /** * Задаём значения параметров опции на остнове параметров фичи по шаблону * @param id - id опции * @param feature - фича, к которой относится эта опция * @param nodeConf - конфиг опции */ private void parseOptionValues(int id, String feature, ParameterMap nodeConf) { //Берём все параметры фич из sa.feature.<feature>.values.* и обрабатываем их через подстановки //Результат помещаем в optionValues Preferences params; String v; if(this.featureConfig.containsKey(feature)){ params = new Preferences(); for(Map.Entry<String,String> e : this.featureConfig.get(feature).sub("values.").entrySet()){ v = parseTemplate(e.getValue(), nodeConf); if(v!=null){ params.set(e.getKey(), v); } } optionValues.put(id, params); } } /** * * @param template * @param conf * @return */ private String parseTemplate(String template, ParameterMap conf){ String result = null; Matcher m = optionValuePattern.matcher(template); if (m.find()){ StringBuffer newValue = new StringBuffer(template.length() + 16); String varName = m.group(1); String var = conf.get(varName, null); if (var != null){ var = Matcher.quoteReplacement(var); m.appendReplacement(newValue, var); } while (m.find()){ var = conf.get(m.group(1), null); if (var == null) continue; var = Matcher.quoteReplacement(var); m.appendReplacement(newValue, var); } m.appendTail(newValue); result = newValue.toString(); } return result; } } |
Автор: | Cromeshnic [ 27 ноя 2012, 14:35 ] |
Заголовок сообщения: | Re: Оптимизация конфига устройств |
Теперь расскажу, как я представляю себе определение профилей на основе наборов опций. Например, есть Сisco SCE. Каждому сабскрайберу (сервису Inet) назначается packageId - числовой идентификатор профиля. Профили конфигурируются заранее на SCE. В биллинге мы хотим задавать следующие параметры профиля: - скорость - класс сервиса клиента (приоритет трафика на уровне сабскрайбера) - запретить торрент-трафик (да/нет) - запретить доступ к соц сетям (да/нет) - (могут появиться новые) Последние 2 услуги рулятся с помощью тарифных опций. Скорость тоже может меняться от тарифной опции (турбокнопка) Если делать прямое соответствие 'опция Inet' -> 'package_id', то придётся все возможные варианты комбинаций ветвить в тарифе. У нас так сейчас сделано в dialup (не спрашивайте, как ![]() Долго думал, сняв очки, как сопоставить опции и профили. Получается такая схема: опции -> фичи -> профили feature (фича) - это группировка опций по типам. Например: inet - скорость в интернет local - скорость локального трафика flow (on/off) - включен ли netflow на интерфейсе (тоже рулится тарифной опцией) notorrent (on/off) - закрыт ли торрент-трафик у клиента nosocial (on/off) - закрыты ли соц. сети у клиента На первом этапе ServiceActivator, или кто у нас будет определять профиль (packageId в случае SCE), определяет по набору опций значения фич: inet = <inet_option_id> local = <local_option_id> итд фича может быть не определена Затем на основе фич подбираем подходящий packageId. Например, можно сконфигурировать все packageId в виде: [packageId=101] inet = 123, 124 (Id опций через запятую) notorrent = - (не указано) nosocial = - (не указано) [packageId=102] (101, но с закрытыми торрентами) inet = 123, 124 notorrent = 10 (id опции) nosocial = - (не указано) Потом перебирать их и подбирать первый подходящий. Как-то так. Ну или можно использовать не id опций, а значения (скорости, true/false) Воот. Т.о. группировка опций по типам - довольно естественная вещь и может пригодиться в будущем. |
Страница 1 из 2 | Часовой пояс: UTC + 5 часов [ Летнее время ] |
Powered by phpBB® Forum Software © phpBB Group http://www.phpbb.com/ |