Нечасто, но случается необходимость заглянуть внутрь openssl-сертификата, сгенерировать или подписать новый, сконвертировать из одного формата в другой. Отличная подборка самых частых команд.
5 дек. 2017 г.
20 нояб. 2017 г.
yum: a lot of duplicate packages
Пришел сегодня коллега с проблемой: в процессе обновления завис yum, а после рестарта виртуалки случился kernel panic на старте. И если рабочую систему мы получили, просто загрузившись с предыдушей версии ядра, то проблемы с менеджером пакетов решали еще некоторое время. А проблема оказалась такая: при попытке совершить любые действия с пакетами yum находил вагон и маленькую тележку пакетов в состоянии duplicate. Аналогичный результат выдавал и yum check. Выискивать и удалять полторы сотни дубликатов руками - не вариант.
После некоторого количества изысканий пришли к следующему решению:
# package-cleanup --cleandupes --skip-broken
# yum clean all
# yum update
27 окт. 2017 г.
16 окт. 2017 г.
YUM: установка пакета конкретной версии
Посмотреть доступные версии пакета, причем с выводом в том виде, который скушает yum:
[root@git03 gitlab]# repoquery --show-duplicates gitlab-ce | grep 9.5
gitlab-ce-0:8.9.5-ce.0.el7.x86_64
gitlab-ce-0:9.5.0-ce.0.el7.x86_64
gitlab-ce-0:9.5.1-ce.0.el7.x86_64
gitlab-ce-0:9.5.2-ce.0.el7.x86_64
gitlab-ce-0:9.5.3-ce.0.el7.x86_64
gitlab-ce-0:9.5.4-ce.0.el7.x86_64
gitlab-ce-0:9.5.5-ce.0.el7.x86_64
gitlab-ce-0:9.5.6-ce.0.el7.x86_64
gitlab-ce-0:9.5.7-ce.0.el7.x86_64
gitlab-ce-0:9.5.8-ce.0.el7.x86_64
Сам бы ни в жизнь не догадался так записать О_о, тем более что установленный пакет выглядит так:
[root@dpro-git03 gitlab]# yum -q list installed gitlab-ce
Installed Packages
gitlab-ce.x86_64 9.5.5-ce.0.el7 @gitlab_gitlab-ce
12 окт. 2017 г.
15 сент. 2017 г.
Equivalent of update-grub for RHEL/Fedora/CentOS
Неведомо почему, но в RedHat-based дистрибутивах нет команды grub-update (update-grub). Приходится для регенерации конфигурационного файла загрузчика помнить вот такое:
grub2-mkconfig -o "$(readlink /etc/grub2.cfg)"
7 авг. 2017 г.
5 авг. 2017 г.
vCenter Web Client fails to start
После установки очередного пакета обновлений ОС на одном из vCenter появилась проблема доступа к интерфейсу vSphere. Практически сразу стало ясно, что проблема в незапущенной службе Web Client. Ручной перезапуск службы работоспособность системы восстанавливал, но до первой перезагрузки.
Оказалось, что "это не бага, это фича"(с). Описание и решение нашлось тут. Если кратко, то служба стартовала слишком рано, поэтому останавливалась с ошибкой. Решение - изменить свойства запуска на Automatic (Delayed Start) и увеличить с помощью ключа в реестре время задержки с умолчальных 120 до 300 секунд.
Create a new key 'AutoStartDelay' (DWORD (32-bit) under HKLM\SYSTEM\CurrentControlSet\services\vspherewebclientsvc and set it to decimal 300. Default delay is 120 seconds. Oh and you should check the key 'DelayedAutostart' that it is set to 1.
21 июн. 2017 г.
Lookaround assertions in Python
Приходится по рабочим задачкам ковыряться в регулярках на питоне. И очень плохо в голову складывалась такая удобная штука как Lookahead\Lookbehind assertions. Ясности сильно добавила вот эта статья, где с примерами и пояснениями разложена как сама концепция, так и особенности практического применения.
Тэги:
lookarounds,
python
15 мая 2017 г.
ansible host_vars
Оказался в моем inventory старый-старый хост, при работе с которым даже ping падал.
˜# ansible -m ping old.example.com -e ansible_user=ansible
[WARNING]: Module invocation had junk after the JSON data: usage: sudo -e [-S] [-p prompt] [-u username|#uid] file ...
old.example.com | FAILED! => {
"changed": false,
"failed": true,
"module_stderr": "Shared connection to 192.168.0.1 closed.\r\n",
"module_stdout": "sudo: illegal option `-n'\r\nusage: sudo -h | -K | -k | -L | -l | -V | -v\r\nusage: sudo [-bEHPS] [-p prompt] [-u username|#uid] [VAR=value]\r\n {-i | -s |}\r\nusage: sudo -e [-S] [-p prompt] [-u username|#uid] file ...\r\n",
"msg": "MODULE FAILURE",
"rc": 1
Дело оказалось в том, что со второй версии изменился набор опций для вызова sudo: добавился параметр -n, которого "старые" sudo могут не знать. Так как подобных хостов у меня пара штук, менять ради них настройки по умолчанию неинтересно. Вместо этого воспользуемся функционалом Host Variables. Идея простая, нам нужно чтобы переменная окружения ansible_sudo_flags не содержала в себе -n для хоста old.example.com. Решение:
# cat /data/ansible/inventory/host_vars/old.example.com.ymlПочитать о том, какая переменная и откуда важнее при выполнении заданий, можно тут.
---
## fix ansible regression for old distros (no -n option with sudo)
##
ansible_sudo_flags: "-H"
3 мая 2017 г.
ansible + cmdbuild
Как известно, любые задачи вокруг ansible начинаются с перечня ресурсов, управление которыми требуется. Основным способом инвентаризации является обычный текстовый файл (по умолчанию /hosts) c перечнем имен или адресов серверов. Многие знают, что при указании в качестве пути директории ansible будет использовать все находящиеся внутри оной файлы как источники данных о хостах.
Однако при количестве хостов более пары десятков файлы становится трудно поддерживать в актуальном состоянии, и тогда на помощь приходят различные системы инвентаризации и управления активами. В случае с виртуальными средами такой системой в первом приближении является гипервизор (или вышестоящее ПО, типа vsphere, proxmox, etc). При наличии подобной базы данных единственно правильным и удобным решением является или автоматизация процесса синхронизации локальных inventory-файлов ansible с данными этой базы, или прямое использование данных базы во время выполнения плейбука - dynamic inventory. Для многих случаев существуют готовые скрипты, реализующие функционал динамического построения списка хостов. Также есть страничка, где описываются основные моменты, необходимые для написания собственного решения.
Но вот с программированием (да, даже на питоне :\) у меня никак, поэтому пришлось обходиться средствами самого ansible, а именно: для взаимодействия с CMDBuild пришлось написать плейбук, который актуализирует локальный inventory-файл.
Далее я хочу сохранить для истории все тонкости и интересные с точки зрения изучения продукта моменты, возникшие в процессе разработки этого решения.
Итак, в качестве средства инвентаризации и хранения данных об информационных ресурсах используется CMDBuild. Для автоматизированного общения с базой данных доступен REST API, познакомиться с которым можно вот тут.
Так как неавторизованным пользователям доступ не предоставляется (401 при любом запросе), первая задача: пройти аутентификацию. Замечание: как выяснилось в процессе отладки, сервисные учетные записи (в отличие от учетных записей пользователей) не могут быть использованы в веб-интерфейсе, только через API.
Здесь и далее для работы с http-запросами используется ansible-модуль uri. Как обычно, документация к модулю достаточно полна и снабжена примерами, чтобы разобраться в его использовании.
- name: Get ID and open session with CMDBuild API
uri:
url: "{{cmdb_url}}/sessions"
validate_certs: no
method: POST
body: "{\"username\" : \"{{cmdb_user}}\" , \"password\" : \"{{cmdb_pass}}\"}"
body_format: json
status_code: 200
headers:
Content-Type: application/json
register: auth_result
Стоит указать, что значение {{cmdb_url}} стоит подсмотреть в документации, в моем случае он выглядит примерно так: "https://cmdb.example.com/cmdbuild/services/rest/v2" , а учетные данные ({{cmdb_user}} и {{cmdb_pass}}) не следует держать в открытом виде. В случае ansible 2.3+ наиболее удобным способом будет использование in-place vault:
cmdb_user: !vault |
$ANSIBLE_VAULT;1.1;AES256
666239373962396262623031663239613432663366383435393634653436366133326339373735373063306464626631613765326331343364356337313432330a386164303261623339326435613862323433386361343262383432326439653235333665313666623431343532616437376163666561613737343535336533610a6234343263376465626264333630306639626137616165373066643034336262
Для более ранних версий - отдельный vault-файл, который следует подгрузить через include_vars. Подробнее о хранилище ansible-vault и методах работы с ним тут.
Итак, задание выше отправляет POST по адресу url c учетными данными в json-формате, считается выполненным при получении http-кода 200 и записывает результат выполнения (тоже json) в переменную {{auth_result}}.
Результатом этого запроса будет открытая на сервере сессия с идентификатором {{auth_result.json.data._id}}, который далее необходимо вкладывать в заголовок каждого запроса.
Далее, имея доступ к дереву ресурсов (в рамках прав учетной записи), можно запросить требуемые нам данные. В CMDBuild есть свои встроенные фильтры, которые можно передавать через http в виде параметра ?filter=, а также свой sql-подобный язык запросов CQL, передающийся через параметр ?cql=. Мои потребности полностью покрывались фильтрами, поэтому cql-запросы не рассматривались.
Однако с фильтрами тоже все непросто. В текущей версии документации эта тема практически не затронута. Где-то на форумах нашлось описание конструкции фильтра:
'{"filter": {"attribute": "Description","operator":"contain","value":["SomeValue"],"parameterType":"fixed" }}'
Там же поступило предложение настраивать фильтр в веб-интерфейсе и подглядывать за передаваемыми http-параметрами в окне консоли браузера. Иных способов пока, к сожалению, нет. В общем, неким магическим для меня образом было получено несколько фильтров, с каждым из которых был создан запрос. Вот пример одного из них:
## filter_prod: Description
## Status: Production,[03]
filter_prod: "?filter=%7B%22attribute%22%3A%7B%22simple%22%3A%7B%22attribute%22%3A%22Status%22%2C%22operator%22%3A%22equal%22%2C%22value%22%3A%5B03%5D%2C%22parameterType%22%3A%22fixed%22%7D%7D%7D"
- name: Query hosts with "Production" status (filter_prod)
uri:
url: "{{cmdb_url}}/classes/Server/cards{{filter_prod}}"
validate_certs: no
method: GET
status_code: 200
headers:
CMDBuild-Authorization: "{{auth_result.json.data._id}}"
Content-Type: application/json
when: auth_result.json.data._id is defined
register: prod_result
no_log: yes
Большая часть из описания задания совпадает с вышесказанным. Из особенностей: добавлен дополнительный параметр headers, где передается токен авторизации - CMDBuild-Authorization (название которого тоже, как и в случае с фильтрами, не освещено в документации). Результат выполнения GET запроса - JSON с описанием карточек всех ресурсов класса "Server", подходящих под фильтр {{filter_prod}}. Так как вывод идет в stdout, количество выпавшей в консоль информации может удивить, поэтому добавлен параметр no_log: yes, запрещающий любой вывод результатов этого задания вне зависимости от уровня журналирования.
Также добавлено условие выполнения задания: when: auth_result.json.data._id is defined. В случае неуспешной аутентификации плейбук не будет сыпать ошибками, а просто завершится без выполнения запросов.
После выполнения всех запросов хорошим тоном будет закрыть сессию:
- name: Close session with CMDBuild API
uri:
url: "{{cmdb_url}}/sessions/{{auth_result.json.data._id}}"
validate_certs: no
method: DELETE
status_code: 204
headers:
CMDBuild-Authorization: "{{auth_result.json.data._id}}"
Отмечу лишь, что успешный код выполнения этого запроса: 204.
Для удобства дальнейшего использования полученные списки хостов следует прогруппировать, для этого запишем названия необходимых групп в inventory-файл:
- name: Create ansible groups
lineinfile:
state: present
dest: "{{cmdb_inventory}}"
regexp: '^{{ item|replace("[", "\[")|replace("]", "\]") }}'
line: '{{ item }}'
insertbefore: BOF
create: yes
with_items:
- '[cmdb-prod]'
Из особенностей здесь описание регулярки: помимо обычного указания элемента здесь последовательно используется два фильтра replace, подставляющих символ экранирования для квадратных скобок. Без этого изменения мы получаем не выражение для поиска, а диапазон символов, и поиск не срабатывает. За подсказку по проблеме спасибо автору этого поста.
Наконец, осталось лишь записать выгруженные хосты в файл.
- name: Write '[cmdb-prod]' hosts to inventory file
lineinfile:
state: present
dest: "{{cmdb_inventory}}"
line: "{{item}}"
insertafter: '^\[cmdb-prod\]'
with_items: "{{ prod_result.json.data | map(attribute='HostName') | list | sort(reverse = True) }}"
Стоит пояснить происходящее внутри параметра with_items. Если содержимое переменной в Ansible - JSON, то к ее элементам можно получить доступ через var_name.json. В выводе CMDBuild присуствуют массивы meta и data, содержимое последнего нас и интересует. Далее используется фильтр map, который показывает только содержимое атрибута HostName внутри prod_result.json.data. Однако вывод остается в формате JSON, поэтому используется фильтр list, делающий из него plaintext. Сортировка по убыванию используется потому, что каждый {{item}} вставляется после [cmdb-prod], и таким образом мы получаем в итоге сортированный в алфавитном порядке список.
В процессе разработки плейбука запросы приходилось делать множество раз, поэтому очень полезным оказался проект resty. Это обертка над curl, которая встраивается в текущий шелл и позволяет более просто делать различные http-запросы.
:
27 апр. 2017 г.
dnsmasq on macos
Потихоньку превращаю сайтик в link-блог, ну да нестрашно.
Потребовалось на скорую руку поднять локальный dnsmasq на макбуке. Если с конфигом все ясно: brew подсказывает, где его взять и куда положить, а что писать внутри, мы и сами с усами, то как запускать и автостартовать демона, сходу неясно. Вот тут поясняют, спасибо.
Краткая выжимка про запуск:
- положить скрипт инициализации в ожидаемое ОС место для автозагрузки:
sudo cp -v $(brew --prefix dnsmasq)/homebrew.mxcl.dnsmasq.plist /Library/LaunchDaemons
- запустить вот прямо сейчас:
sudo launchctl load -w /Library/LaunchDaemons/homebrew.mxcl.dnsmasq.plist
25 апр. 2017 г.
Bash. Подводные камни
Прилетела в одном из чатиков ранее не замеченная статья про bash. Очень рекомендуется к прочтению.
13 апр. 2017 г.
Ansible -vvv reveals sensitive data
В процессе дебага плейбуков заметил очень неприятную особенность: при увеличении уровня verbose в лог (на экран и в файл) попадают те данные в открытом виде, что скрыты в vault-файле. В том случае, когда это критично (компрометация в логе закрытых ключей, паролей, и так далее), следует добавлять к заданиям параметр no_log. При его включении весь вывод команды заменяется на подавляется вне зависимости от количества -v.
- name: create user accountsВыглядит это так:
user:
state: present
name: "{{ item.username }}"
shell: "{{ item.shell | default(default_shell) }}"
groups: "{{ item.groups | default(omit) }}"
comment: "{{ item.name }} ({{ item.comment | default(omit) }})"
password: "{{ item.password | default(dis_default_pass) }}"
append: yes
update_password: on_create
with_items: "{{regular_users}} + {{vip_users}}"
no_log: yes
TASK [user-mgmt : create user accounts] ****************************************По этому поводу есть тикет в github, в котором также рекомендуется использовать no_log.
ok: [01.example.com] => (item=(censored due to no_log)) => {"censored": "the output has been hidden due to the fact that 'no_log: true' was specified for this result"}
Тэги:
ansible
10 апр. 2017 г.
ansible-playbook: exclude host
Если нужно исключить из списка хостов только один-два-несколько позиций, а на остальных плейбук проиграть, то делай так:
ansible-playbook --limit 'all:!bad_host' playbook.ymlВзято отсюда.
Тэги:
ansible
6 апр. 2017 г.
yum + linux kernel
В CentOS (и, полагаю, во всех его "родственниках") довольно удобно удалять старые ядра:
package-cleanup --oldkernels --count=2В результате останется текущее ядро и предыдущее.
Если команда не найдена, нужно доустановить пакет yum-utils.
28 февр. 2017 г.
ansible: запрос значения переменных
В некоторых случаях требуется ручной ввод переменных. Это можно сделать с помощью параметра vars_prompt.
- name: get host info
hosts: localhost
vars_prompt:
- name: remote_host
prompt: "Where to go? Enter DNS/IP"
private: no
default: localhost
- name: remote_user
prompt: "Enter remote username"
private: no
default: root
- name: remote_user_pass
prompt: "Enter password"
private: yes
Описание довольно очевидно, из интересностей: private: yes скрывает вводимые символы в консоли (аналогично поведению при вводе пароля при логине); значение default подставляется в случае, если ввод был пустым (также оно отображается в скобках при запросе значения).
В качестве примера использования можно предложить такое задание:
tasks:
- name: create dynamic inventory
add_host:
name: "{{ remote_host }}"
groups: temp_hosts
ansible_user: "{{ remote_user }}"
ansible_become: yes
ansible_ssh_pass: "{{ remote_user_pass }}"
ansible_sudo_pass: "{{ remote_user_pass }}"
Тэги:
ansible
21 февр. 2017 г.
ansible: list of facts to file
В последнее время активно работаю с системой управления конфигурациями Ansible, поэтому есть что записать.
Одна из последних задач: получить список хостов, удовлетворяющий заданному условию. В моем случае нужно было отобрать серверы, у которых в перечне используемых файловых систем есть устаревшая ext2. Информация о смонтированных файловых системах есть в автоматически собираемых фактах (gather_facts: yes в ansible.cfg или описании плейбука), поэтому каких-то дополнительных действий на хосте собирать не нужно.
Чуть усложнило ситуацию то, что элемент ansible_mounts представляет собой не словарь, как большинство элементов, возвращаемых модулем setup, а массив. Таким образом, для получения, к примеру, точки монтирования, требуется использовать не ansible_mounts.fstype, а ansible_mounts[0].fstype, причем количество элементов этого массива будет уникальным для каждого хоста.
Решением такой задачи будет плейбук следующего вида:
- name: Check hosts for ext2fs availableЕсли исключить атрибут when: , в файл будут записаны все найденные точки монтирования.
hosts: all
gather_facts: yes
tasks:
- name: create list of files with ext2fs partitions
shell: "echo {{ansible_fqdn|quote}},{{item.mount|quote}},{{item.fstype|quote}}, >> ./ext2fs_list_`date +%s`.csv"
args:
chdir: /tmp/
delegate_to: localhost
with_items: "{{ ansible_mounts }}"
when: item.fstype == "ext2"
Тэги:
ansible
17 февр. 2017 г.
usermod -p
Для тестовых целей может потребоваться образ linux-а с предустановленным паролем root. При создании такого образа (через Docker, Vagrant, установочные скрипты) можно воспользоваться командой
# usemod -p encrypted_password rootЧтобы получить шифрованное значение пароля
# openssl passwd my_pass
26 янв. 2017 г.
Создание (регистрация) службы Windows
Если нужно сделать из исполняемого файла службу Windows, которая будет доступна в оснастке services.msc и вести себя как другие службы, следует обратиться к странице документации тут.
Подписаться на:
Сообщения (Atom)