CLI на питоне. Пускаем пользователя на сервер

от автора

Я системный администратор по роду деятельности. Поддерживаю удаленно сервера разных клиентов. Нередко приходится слышать от клиента просьбу дать доступ на сервер. С одной стороны просьба вполне обоснованная: сервер не мой, да и доступ клиенту нужен, чтоб меня же не дергать по пустякам (скажем, посмотреть, не закончилось ли место на диске или все ли процессы запущены). С другой стороны клиент зачастую практически не имеет опыта работы в unix, и нет никакой гарантии, что я смогу все исправить после того, как клиент по незнанию сотрет что-нибудь с диска или заблочит мне доступ, удалив правила фаервола. Зачастую клиенты и сами это понимают, но настаивают на предоставлении им доступа, не видя другого выхода.

Казалось бы, можно дать клиенту урезанный шелл и контролировать исполнение «опасных» команд при помощи sudo. Однако даже если с точки зрения безопасности удается все удачно «разрулить», это не решает всех проблем. Клиента приходится учить основам работы в командной строке, отвечать на шквал вопросов и разбираться, что и почему у него не получается. Время, затрачиваемое на поддержку, увеличивается значительно.

Пытаясь найти решение я наткнулся на описание модуля Cmd для Python. Данный модуль позволяет с минимальными затратами написать подобие интерфейса командной строки c необходимым набором команд.

Начнем с небольшого скрипта-каркаса, который можно будет дополнять командами по мере необходимости. Вот он. Всего 25 строчек. Даже под спойлер прятать не надо.

#!/usr/bin/env python # -*- coding: utf-8 -*- import cmd  class Cli(cmd.Cmd):      def __init__(self):         cmd.Cmd.__init__(self)         self.prompt = "> "         self.intro  = "Добро пожаловать\nДля справки наберите 'help'"         self.doc_header ="Доступные команды (для справки по конкретной команде наберите 'help _команда_')"      def do_hello(self, args):         """hello - выводит 'hello world' на экран"""         print "hello world"      def default(self, line):         print "Несуществующая команда"  if __name__ == "__main__":     cli = Cli()     try:         cli.cmdloop()     except KeyboardInterrupt:         print "завершение сеанса..." 

Cохраним файл как cli.py и запустим. Скрипт бодро поприветсвует нас и выдаст приглашение командной строки. Вот пример его работы:

$ ./cli.py  Добро пожаловать Для справки наберите 'help' > help  Доступные команды (для справки по конкретной команде наберите 'help _команда_') =========================================================================== hello  help  > help hello hello - выводит 'hello world' на экран > hello hello world > завершение сеанса... 

Вернемся к коду. Мы унаследовали класс Cli от Сmd, переопределили несколько свойств для вывода приветствия и начальной справки на родном языке. А так же дописали два метода — default и do_hello. Метод default определяет поведение командной строки в случае, если набранная пользователем команда не существует. На методе do_hello остановимся подробней.

Метод do_hello описывает единственную команду нашего cli (ну, кроме доступной по умолчанию help) — hello. Модуль cmd следует соглашению, по которому методы вида do_command преобразуются в команды command в cli. Комментарий в тройных кавычках, идущий первой строкой в теле метода преобразуется в справку по этой команде. В аргументе args в метод передается строка пользовательских аргументов. Например, если пользователь в консоли набрал «hello everyone» переменная args будет содержать строку «everyone». В данном случае мы просто игнорируем аргументы командной строки.

По умолчанию доступно автодополнение (по табуляции) и история команд (стрелочка вверх). Так же доступна встроенная команда «help» (она же — "?"), которая при помощи обильной дозы магии преобразует комментарии в коде скрипта в справку по командам.

Имея данный скрипт-каркас, мы можем расширять функциональность нашего интерфейса командной строки, добавляя в код нужные методы вида do_cmd. Например, удалим не несущую полезной нагрузки команду hello и добавим несколько полезных команд для мониторинга системы.

показать

#!/usr/bin/env python # -*- coding: utf-8 -*- import cmd import os  class Cli(cmd.Cmd):      def __init__(self):         cmd.Cmd.__init__(self)         self.prompt = "> "         self.intro  = "Добро пожаловать\nДля справки наберите 'help'"         self.doc_header ="Доступные команды (для справки по конкретной команде наберите 'help _команда_')"      def do_show_cpu(self, args):         """show_cpu - нагрузка на процессоры"""         os.system("sar 2")      def do_show_mem(self, args):         """show_mem - использование RAM"""         os.system("free")      def do_show_disk(self, args):         """show_disk - свободное место на диске"""         os.system("df -h")      def do_show_net(self, args):         """show_net - сетевые параметры"""         os.system("/sbin/ifconfig")         os.system("/sbin/route -n")      def do_show_log(self, args):         """show_log - системный журнал"""         os.system("sudo tail -f /var/log/messages")      def default(self, line):         print "Несуществующая команда"      def emptyline(self):         pass  if __name__ == "__main__":     cli = Cli()     try:         cli.cmdloop()     except KeyboardInterrupt:         print "завершение сеанса..." 

Наш новоиспеченный шелл готов. Переместим его в место, доступное для чтения всем пользователям системы. Например в /usr/local/bin/. Возможно, путь к нашему скрипту нужно будет прописать в /etc/shells.

Добавляем пользователя с нашим шеллом и пробуем:

# adduser user --shell /usr/local/bin/cli.py  ... root@laptop:~# su - user Добро пожаловать Для справки наберите 'help' > ?  Доступные команды (для справки по конкретной команде наберите 'help _команда_') =========================================================================== help  show_cpu  show_disk  show_log  show_mem  show_net  > show_cpu Linux 3.5.0-17-generic (dima-laptop)    04/03/2013      _x86_64_        (4 CPU)  02:38:03 PM     CPU     %user     %nice   %system   %iowait    %steal     %idle 02:38:05 PM     all      0.63      0.00      0.25      0.13      0.00     98.99 02:38:07 PM     all      1.00      0.00      0.25      0.25      0.00     98.50 ^C> show_mem              total       used       free     shared    buffers     cached Mem:       3911236    2123408    1787828          0     124156     994752 -/+ buffers/cache:    1004500    2906736 Swap:      4393980          0    4393980 >   

ссылка на оригинал статьи http://habrahabr.ru/post/175321/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *