Поиск групп ресурсов при отсутствии ресурсов

У меня много ресурсов и много подписок Azure, и в результате я часто обнаруживаю, что забываю, для чего все используется. Конечно, я стараюсь назвать группы ресурсов как-нибудь полезно, добавляю теги и тому подобное, но даже в этом случае все быстро выходит из-под контроля. Например, сейчас у меня 47 групп ресурсов в моей основной подписке (не говоря уже о второй и третичной).

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

Но как их найти, если не кликать по порталу?

Что ж, давайте начнем с shell.azure.com и начнем писать сценарии.

Для выполнения этой задачи нам понадобятся две части информации: имена всех групп ресурсов и количество элементов в этих группах ресурсов.

Получить имена всех групп ресурсов очень просто:

az group list | jq 'map(.name)'
Войдите в полноэкранный режим Выйдите из полноэкранного режима

Это приведет к следующему результату:

[
  "aaron-cloud-cli",
  "dddsydney",
  "httpstatus",
  "personal-website",
  "restream-streamdeck",
  "NetworkWatcherRG",
  "stardust-codespace"
]
Войти в полноэкранный режим Выйти из полноэкранного режима

К сожалению, это не скажет вам, сколько ресурсов находится в группе (да, мы получаем только свойство name, но весь JSON не содержит его). На самом деле, вы не можете получить это с помощью az group, даже az group show --name <name> не даст вам этого, нам придется решать эту проблему по-другому, вместо этого мы получим все ресурсы и сгруппируем их по их группе ресурсов, что мы можем сделать с помощью az resource list:

az resource list | jq 'map(.resourceGroup) | group_by(.) | map({ name: .[0], length: length }) | sort_by(.length) | reverse'
Войти в полноэкранный режим Выйти из полноэкранного режима

Эта команда jq немного сложна, но если разбить ее на части, то первое, что мы делаем, это выбираем имя группы ресурсов из каждого ресурса с помощью map(.resourceGroup), чтобы получить массив имен групп ресурсов. Затем мы используем group_by(.), чтобы сгруппировать их вместе и передать в другую функцию map, которая создает объект с именем группы ресурсов (полученным из первого элемента индекса) и длиной (сколько ресурсов находится в группе ресурсов). Наконец, он просто сортирует и упорядочивает его с помощью sort_by и reverse, давая нам такой результат:

[
  {
    "name": "httpstatus",
    "length": 11
  },
  {
    "name": "personal-website",
    "length": 3
  },
  {
    "name": "stardust-codespace",
    "length": 1
  },
  {
    "name": "restream-streamdeck",
    "length": 1
  },
  {
    "name": "dddsydney",
    "length": 1
  },
  {
    "name": "aaron-cloud-cli",
    "length": 1
  }
]
Вход в полноэкранный режим Выход из полноэкранного режима

Отлично! Вот только… он содержит только группы ресурсов, у которых есть ресурсы, то есть мы знаем, у каких групп ресурсов есть предметы, а когда нам нужен обратный запрос, нам нужны те, у которых нет предметов.

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

Начните с записи всех групп ресурсов с элементами в переменную bash:

RG_NAMES=$(az resource list | jq -r 'map(.resourceGroup) | group_by(.) | map(.[0])')
Войти в полноэкранный режим Выйти из полноэкранного режима

Далее мы используем $RG_NAMES в качестве подстановки в запрос к az group list:

az group list | jq -r "map(.name) | map(select(. as $NAME | $RG_NAMES | any(. == $NAME) | not)) | sort"
Войдите в полноэкранный режим Выход из полноэкранного режима

Давайте снова разберем этот более сложный оператор jq. Мы начинаем с получения имен групп ресурсов (поскольку это все, что нам нужно) с помощью map(.name). Затем это передается в вызов map, чтобы мы могли работать с каждым элементом массива. Во втором map мы используем присвоение элемента переменной $NAME (которую мы экранировали, так как делаем подстановку с помощью переменной окружения $RG_NAMES), передать переменную $RG_NAMES, чтобы мы могли передать ее в any и посмотреть, совпадает ли любой элемент в $RG_NAMES с $NAME. Результат any инвертируется путем передачи через not, и результат предоставляется select для фильтрации имен групп ресурсов только тех, которые не имеют ресурсов!

["NetworkWatcherRG"]
Вход в полноэкранный режим Выход из полноэкранного режима

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

Резюме

Вот снова эти две строки:

RG_NAMES=$(az resource list | jq -r 'map(.resourceGroup) | group_by(.) | map(.[0])')
az group list | jq -r "map(.name) | map(select(. as $NAME | $RG_NAMES | any(. == $NAME) | not)) | sort"
Войти в полноэкранный режим Выйти из полноэкранного режима

Да, jq может выглядеть немного устрашающе, особенно учитывая, сколько труб они выполняют, но в целом, он делает то, что рекламируется, возвращает список групп ресурсов, которые не содержат элементов.

И да, возможно, я потратил больше времени на то, чтобы разобраться в этом, чем на то, чтобы просмотреть их все, но эй, по крайней мере, у меня есть готовый вариант на следующий раз! 🤣

Оцените статью
devanswers.ru
Добавить комментарий