В настоящее время все больше и больше продуктов содержат API для интеграции с другими продуктами. Хорошие разработчики делают этот API – RESTful, то есть разработанный по принципам REST. Что бы работать с подобными сервисами в PoweShell 3.0 ввели cmdlet Invoke-RESTMethod. Данный cmdlet позволяет легко делать как привычные HTTP (GET-POST) запросы, так и запросы по паттерну CRUD (POST-GET-PUT-DELETE), а также другие WebRequestMethod. Я уже пользовался данным cmdlet’ом в статье о интеграции DPM с системой ServiceDesk, а сейчас хотел бы показать как можно пользоваться данным cmdlet’ом более полно, получая от него данные и пользуясь этими данными. Мои статьи рассчитаны на таких же неискушенных в PowerShell администраторов как и я, потому не следует ждать тут каких либо откровений для опытных скриптописателей.
Так как давать абстрактный пример не хочется (не люблю абстрактных примеров), я буду реализовывать задачу из заголовка – ротацию логов для ELK. В статье о ELK и сборе логов я упустил этот момент и вот сейчас готов его восполнить. Хранить огромное количество логов за продолжительный промежуток времени я считаю довольно бессмысленным (какова актуальность логов двухнедельной давности?). По этому логи старше N дней нужно удалять из Elacticsearch. Изучив документацию по Elasticsearch я убедился, что он вполне себе RESTful и в наличии есть все необходимые методы для управления индексами поискового движка.
Для того чтобы получить список всех индексов Elasticsearch, необходимо выполнить GET запрос по адресу:
http://{you elasicsearech server}:9200/_cat/indices?v
Попробуем воспользоваться cmdlet’ом Invoke-RESTMethod:
$result = Invoke-RestMethod -Method Get -Uri "http://{you elasicsearech server}:9200/_cat/indices?v"
Получаем примерно такой вывод:
PS C:\Windows\system32> $result health index pri rep docs.count docs.deleted store.size pri.store.size green logstash-2014.10.13 5 0 13569640 0 16.7gb 16.7gb green logstash-2014.10.14 5 0 4348141 0 5.5gb 5.5gb green .marvel-kibana 5 0 1 1 3.5kb 3.5kb
Однако работать с таким $result неудобно, потому как это просто строка, в чем мы можем убедиться воспользовавшись методом GetType()
PS C:\Users\nikitin.ae\Documents> $result.GetType() IsPublic IsSerial Name BaseType
-------- -------- ---- -------- True True String System.Object
Для того чтобы получить от сервера массив, мы добавим cmdlet’у параметр ContentType в котором укажем MIME тип application/json. В результате сервер отдаст нам ответ в формате JSON, который Powershell автоматически приведет к массиву объектов PSCustomObject.
Итак наш новый запрос будет выглядеть так:
$result = Invoke-RestMethod -Method Get -Uri "http://{you elasicsearech server}:9200/_cat/indices?v" -ContentType 'application/json'
А результат можно увидеть воспользовавшись методом любого объекта Powershell GetType()
PS C:\Users\nikitin.ae\Documents> $result.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
Тип PSCustomObject очень похож на Hashtable, и по имени свойства объекта мы можем получить доступ к данным.
Для обхода всего массива мы можем воспользоваться foreach. Так как нас интересуют только индексы с именем, начинающимся на “logstash-” то будет уместным отфильтровать индексы, которые имеют отличное от этого имя. Ну и наконец в имени индекса, которое создает logstash содержится дата, нам нужно ее распознать и привести к типу datetime, чтобы потом можно было бы сравнить с текущим и получить разницу в днях.
Как итог у меня получился вот такой скрипт:
$result = Invoke-RestMethod -Method Get -Uri "http://{your elasticsearch server}:9200/_cat/indices?v" -ContentType 'application/json' $today = [datetime]::Today foreach($r in $result){ if($r.index.StartsWith('logstash-') -eq $true){ $date = [datetime]::Parse($r.index.SubString(9)) if(($today-$date).Days -gt 3) { $delindex = $r.index $uri = "http://{your elasticsearch server}:9200/"+$delindex+"?pretty" Invoke-RestMethod -Method Delete -Uri $uri -ContentType 'application/json' } } }
В переменной $today сохраняется текущая дата (без времени). А в строке if(($today-$date).Days –gt 3) разница разница в днях сравнивается со значением 3 (вы можете использовать удобное вам значение дней) и удаляются только те индексы, которые старше 3 дней. Удаление производится все тем же cmdlet’ом Invoke-RESTMethod, однако метод называется Delete (один из методов CRUD) который корректно обрабатывается сервером Elasticsearch и вызывает удаление индекса, который мы указываем в параметре Uri.
Сохранив данный скрипт, вы можете вызывать его по расписанию каждый день с помощью Task Schelduler или, например, с помощью System Center Orchestrator, как это сделал я.
Невозможно вызвать метод для выражения со значением NULL.
строка:4 знак:8
+ if($r.index.StartsWith('logstash-') -eq $true){
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull