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

в 14:26, , рубрики: cli, cmd, python, shell, системное администрирование, метки: , , , ,

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
> 

Автор: facha

Источник

Поделиться

* - обязательные к заполнению поля