Внедрение вредоносной команды интерпретатора (ABAP)

Эффект старой плёнки.

Есть в SAP HCM стандартная транзакция PAR1 (Гибкие данные сотрудников). Но при внедрении у пользователей были хотелки, которые в стандарте невозможны. Скопировали транзакцию в Z-область. Допилили её так, как хотелось пользователям. Добавили инфотипы, ещё кое-что по мелочи. Дело нехитрое.

Затемнение.

Прошло десять лет.

(далее…)

Про Shared Memory Objects и немного про память, SHMA, SHMM

В обычной жизни мы не паримся с памятью в ABAP, сборщика мусора как бы нет, глобальной памяти нет.

В самом простом случае у нас есть то, что называется транзакцией (не путать с транзакцией базы данных), что можно определить как «приложение» на нашем собственно говоря сервере приложений. Транзакция всегда ассоциирована с определённой именованной программой.

И вот пока приложение работает, оно потребляет память в виде переменных, экземпляров классов, массивов (также известных как «внутренние таблицы»). И если посмотреть на стек вызовов, то он упирается во входную точку начала этой программы. Ничего ABAPовского за пределами этой точки не существует. Одно приложение не может получить доступ к данным другого приложения, только через какие-то обходные манёвры, например: через постоянное хранилище (СУБД), через взаимные блокировки и прочие костыли. Как только приложение завершает работу, вся его память высвобождается. А приложения долго не работают, потому что они уже в некоторой степени атомарны (то есть как бы уже не монолит, но ещё не микросервисы).

Есть уже случае чуть посложнее, например: есть веб-сервис, слушающий входящие соединения, или одно «приложение» вызывает другое «приложение» через SUBMIT REPORT . Но подход вы уже уловили, это и называется SAP LUW, то есть Logical Unit of Work. Получается, что стек вызовов и контекст существуют неразрывно только внутри него.

И как обычно бывает, изредка появляется необходимость перепрыгнуть заборы.

Один из известных костылей -оператор IMPORT/EXPORT MEMORY ID,  который позволяет перебрасывать переменные (структуры, массивы) между приложениями, но только если они существуют в одной пользовательской сессии. Например Приложение-А вызывает Приложение-Б, Приложение-Б генерирует данные, закидывает их в ячейку памяти X, после чего завершает работу, управление возвращается в Приложение-А, которое считывает данные из ячейки памяти X, профит!

Разговор был бы не так интересен, если бы мы остановились на этом. Но перепрыгнув забор, мы обнаруживаем ещё один забор!

А если мы хотим перебросить данные между разными пользовательскими сессиями?

Для примера кейс будет таким: есть чистый слушающий HTTP-сервис, в котором мы хотим организовать что-то вроде сессии.

HTTP-сессии в ABAP могут быть как stateless, так и stateful. По сути их отличие в том, что этот пресловутый SAP LUW растягивается на всю пользовательскую сессию (stateful) или только на один http-вызов (stateless). В stateful-режиме сервис работает со своими причудами, например: обновлённый код сервиса не подхватывается на лету, чтобы изменения в сервисе вступили в силу нужно завершить сессию. Так же и в обычном ABAPe: пока запущена программа со всеми диалоговыми шагами обновлённый код не подхватывается — необходимо перезайти в транзакцию. Получается в рамках HTTP необходимо сделать log-off, что очень редко случается целенаправленно в жизненных реалиях, гораздо чаще сессия умирает по таймауту.

И вот кривая дорожка сомнительных архитектурных решений привела нас к небольшому челенджу — организовать хранение данных сессии при stateless-сессии HTTP.

Окей, вызов принят. Представим типичный сценарий:

  • Пользователь первый раз заходит на страницу => нет куки сессии => выставляем новый случайный куки (надо его куда-то записать) => рендерим страницу с формой для пользователя => Всё закончилось и очистилось, развязка сезона
  • Ура новый сезон => Пользователь что-то сабмитит => открывается другая страница => есть куки сессии => (надо значения сессии достать) => проверить что пользователь насабмиттил => (положить насабмитенное в сессию) => отрендерить страницу для пользователя, что насабмитилось успешно => снова апокалипсис, миру конец
  • Пользователь чего-то тыкнул => ещё одна страница => есть куки сессии => (надо значения сессии достать) => отрендерить значения на странице => и непонятно, продлит ли пользователь этот бесконечный сериал на следующий сезон или нет

Обыкновенным ABAPом красные места можно тупо реализовать через БД или другой как-мы говорим-у нас-в-деревне «персистент сторэдж», мы же это умеем. Но мы же дошли досюда не за простыми решениями.

Существует возможность создать экземпляр объекта и положить его в какую-то суперглобальную область памяти, существующую вечно внутри сервера приложений. Соответственно, в любой момент можно попробовать взять этот объект во временное пользование (на чтение или на изменение). И это будет тот-же-самый-объект со всеми его атрибутами. Он будет существовать до перезагрузки сервера или до его ручного уничтожения через кнопку в админке (SHMM). Вот вкратце история. А под катом немного подробностей.

(далее…)

Немного NoSQL или что-то взамен SM30

При разработке часто бывает необходимость вести некоторые настройки или конфигурации.

На первом уровне это хардкод внутри программы:

  • написанный напрямую в тексте программы;
  • вынесенный в константы или блок инициализации;
  • оформленный в виде статического атрибута глобального класса.

Хардкод вполне оправдан, если:

  • в течении всего жизненного цикла эти настройки не будут меняться;
  • не будет кейсов, когда именение настройки может быть сделано без изменения связанного исходного кода.

Вторым уровнем может возникнуть классическая настроечная таблица + сгенерированное ведение в транзакции SM30. Впрочем тут тоже можно сделать шаг вправо и влево:

  • кучу таблиц можно объединить в кластер SM34;
  • ведение можно привязать к коду транзакции;
  • ведение можно добавить в SPRO;
  • таблицы могут быть зависимые/независимые от манданта;
  • таблицы могут быть частью настройки или вестить непосредственно в продуктивной системе.

Такие настройки уже вполне можно передать в руки настройщиков и пользователей.

Доходит иногда до смешного, даже в стандарте можно наблюдать целые настроечные таблицы в виде одной колонки («Активировать»), соответственно в таблице только одна строка со значеним — флажок стоит или нет.

Третьим уровнем могут часто возникать разные велосипеды для организации небольших настроек.

Часто можно заметить, что в системе есть много разных стандартных узкоспециализированных хранилищ, которые можно использовать в собственных корыстных целях, например:

  • глобальные переменные STVARV;
  • рабочие списки (OB55 и похожие);
  • версии баланса (почему бы и не);
  • деривация (ну если уж так);
  • кастомные атрибуты объектов, если позволено.

Но некоторые приходят к мысли, что следует разработать некоторое универсальное хранилище настроек (Z-разработка), вроде большой таблицы в стиле ключ-значение или даже нечто похожего на реестр Windows, навскидку:

Добро пожаловать под кат, представляю вам свой велосипед, там есть пара занятных моментов. Почему свой? Да потому что у остальных есть фатальный недостаток, очевидно. (далее…)

LOOP AT SCREEN, работа с экраном — новая идея

Устав от простыней в стиле:

я решил обкатать новый подход.

Первым делом декларативное определение, например:

Применение на практике сводится к следующему:

Пробую пока покатать-проверить, насколько такой подход применим в условиях, приближенным к боевым. Нужно больше мест применения, чтобы определить какой подход даст лучшую читаемость, компактность и проверяемость. И потихотньку можно добавить мяса.

(далее…)

Телега впереди лошади

Простая иллюстрация подхода при передаче параметра  в виде ссылки:

Чего можно таким добиться?

Например: это маленькое ухищрение позволяет однократно указывать обрабатываемую таблицу. Это делает код чуть менее многословным. Альтернатива:

Насколько это красиво? Чисто и просто… Впрочем, есть тут некоторая неочевидность. Мы запускаем метод в классе без указния локальной переменной в качестве параметра, а эта локальная переменная меняется.

Если собирать ошибки внутри вспомогательного класса, а потом их получать вместе, то становится сложнее прекратить обработку немедленно. Выглядит как-то корявенько:

Пример реализации:

(далее…)

Достигая невозможного, пьеса

Все события и герои вымышлены. Любые совпадения с реальными личностями случайны.

Акт первый

Консультант: Нам нужно массово списать материалы, но так чтобы в оборотах это было отражено в особом периоде.

Старый фрилансер: Ну дело житейское, разработчика своего попросите.

Консультант: Мы спрашивали, но он сказал, что это невозможно.

Старый фрилансер: Поверь мне, милая, если разработчик говорит, что нечто невозможно, то это значит, что он ленивая жопа.

Консультант: Посмотри, пожалуйста!

Старый фрилансер: Не вопрос, но задачку-то поставь. (далее…)

Быстрый способ получить данные из XML-файла

Как это часто бывает, есть много разных способов решить одну и ту же задачу. И на этот счет тоже есть варианты:

  • Разбирать текст руками или регулярными выражениями:  плохой подход сходу, не обсуждается
  • CL_XML_DOCUMENT: классический подход, но несколько муторный на мой вкус
  • CALL TRANSFORMATION: стандартный подход, но меня всегда смущает небходимость наличия отдельного артефакта. Кроме того, если работать с этим раз в год, то синтаксис трансформаций выпадает из памяти и необходимо снова обращаться к примерам и/или документации

Новый для меня способ — использовать функциональный модуль SMUM_XML_PARSE, у которого очень простой синтаксис: (далее…)

Грязные трюки при работе с ALV

Дано: есть вывод отчета в ALV, в котором стандартными средствами включен расчет среднего значения.

Итоговое среднее значение стандартно расчитывается так:

( 30 + 40 + 50 + 0 ) / 4 = 30

Предположим для примера, что в четвёртой строке нулевое значение связано не с нулевым значением, а с его отсутствием.

Соответственно от заказчика есть задание: требуется выводить среднее значение, не учитывающее пустые (нулевые) значения:

Один из способов решения задачи — грязно вторгнуться во внутреннюю кухню ALV. Приступим?

(далее…)

RTCM, UPL, SQLM и всё такое про мониторинг ABAP-систем

Обнаружил за последнее время несколько вещиц разной степени полезности.

RTCM

Транзакция SRTCM — Runtime Check Monitor.

Тут можно активировать пару проверок, которые можно упустить в статических проверках ATC (ABAP Test Cockpit). Одна из них — пустая таблица в FOR ALL ENTRIES.

Пишут, что оверхед не такой большой и можно оставить на несколько недель в продуктивной среде.

Мало ли, вдруг иногда бывает, но никто не знает. А быть такого не должно в обычной жизни.

UPL

Usage & Procedure Logging. Такая штука, которая должна по-хорошему работать через Solution Manager и SAP Custom Code Management. Там много данных и без BW-обвеса, который связан с SM, данные непросто анализировать, особенно не нагружая продуктивную систему.

Однако, при некотором желании его можно подёргать напрямую в системе. Но только в тестовых церях на свой страх и риск. Для этого необходимо запустить программу  /SDF/UPL_CONTROL. Транзакции, видимо, не предусмотрено в виду означенных выше обстоятельств.

Затем требуется подождать какое-то время и вам выпадет ошеломляющее количество инфромации:

Все ходы записаны, например: можно проследить, сколько кастомного кода реально работает в каких-то обозначенных ситуациях. И это не совсем то же самое что и ST03N.

SQLM

Насчет мониторинга SQL-запросов тоже есть полезные штуки. Прямо так и называется транзакция SQLM, то есть SQL Monitor, легко запомнить.

И если её оставить на какое-то время, то можно получить много полезной информации:

SFW5

В переключателях бизнес-функций SFW5 можно найти кроме всего прочего:

  • /SDF/WS_MON (Web Service Monitoring) — может и полезно будет когда-нибудь, но пока не буду активировать, ибо отключить потом нельзя, так как Non-Reversible
  • SRIS_SOURCE_SEARCH (ABAP Source Search) — пишут, что активирует построение полнотекстового индекса для исходного кода, однако работает только на HANA. Кроме того, запускать в рабочее время нежелательно, так что на заметку берём, но пока хватит старых инструментов.

PS.

SWLT

SQL Performance Tuning Worklist. А это уже маленькая вишенка на торте, в которой пытаются свести все концы с концами, а именно сопоставляют данные ATC и SQLM. Поэтому новых тайных знаний вы там не найдете, но есть небольшой шанс подхватить инсайт при сопоставлении.

Ещё одно место для хранения файлов — SBWP

Навеяно предыдущей записью. Не все ещё места хранения файлов исследованы. Например, вполне возможно хранить Excel-файлы в так называемом Business Workplace (транзакция SBWP, доступная всем с главного экрана).

Сохранённый файл можно прочитать из программы примерно таким кодом: (далее…)