📜 ⬆️ ⬇️

CLI on python. We let the user to the server

I am a system administrator by occupation. I support servers of different clients remotely. Often you have to hear from the client a request to give shell access to the server. On the one hand, the request is quite reasonable: the server is not mine, and the client needs access, so as not to twitch me over trifles (say, see if the disk space has run out or whether all processes are running). On the other hand, the client often has practically no experience in unix, and there is no guarantee that I can fix everything after the client unknowingly erases something from the disk or blocks my access by removing the firewall rules. Often, clients themselves understand this, but insist on granting them access without seeing any other way out.

It would seem that you can give the client a trimmed shell and control the execution of “dangerous” commands with sudo. However, even if, from a security point of view, everything succeeds in successfully “settling”, this does not solve all the problems. The client has to learn the basics of working on the command line, respond to a flurry of questions and figure out what and why he cannot do it. The time spent on support increases significantly.

Trying to find a solution, I came across the description of the Cmd module for Python. This module allows you to write with a minimal cost the similarity of the command line interface with the necessary set of commands.
')
Let's start with a small framework script that can be supplemented with commands as needed. Here he is. Only 25 lines. Even under the spoiler hiding is not necessary.
#!/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 " ..." 


Save the file as cli.py and run. The script will cheerfully greet us and issue a command line prompt. Here is an example of his work:
 $ ./cli.py      'help' > help   (      'help __') =========================================================================== hello help > help hello hello -  'hello world'   > hello hello world >  ... 

Let's go back to the code. We inherited the Cli class from Cmd, redefined several properties to display the greeting and initial help in the native language. As well as added two methods - default and do_hello. The default method defines the behavior of the command line if the command typed by the user does not exist. On the method do_hello dwell in more detail.

The do_hello method describes the only command of our cli (well, except for the default help) - hello. The cmd module follows an agreement whereby methods of the do_command type are converted to command commands in cli. A comment in triple quotes, followed by the first line in the body of the method, is converted into help for this command. In the args argument, a string of user arguments is passed to the method. For example, if the user in the console typed "hello everyone" the args variable would contain the string "everyone". In this case, we simply ignore the command line arguments.

By default, auto-completion (tab-based) and command history are available (up arrow). Also available is the built-in “help” command (it is also a “?”), Which, with the help of a copious dose of magic, converts comments in the script code into command help.

Having this framework framework, we can extend the functionality of our command line interface by adding the necessary do_cmd methods to the code. For example, remove the non-payload hello command and add some useful commands to monitor the system.
to show
 #!/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 " ..." 


Our new shell is ready. Move it to a place that can be read by all users of the system. For example, in / usr / local / bin / . Perhaps the path to our script will need to be written in / etc / shells .

Add a user with our shell and try:
 # 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 (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 > show_mem total used free shared buffers cached Mem: 3911236 2123408 1787828 0 124156 994752 -/+ buffers/cache: 1004500 2906736 Swap: 4393980 0 4393980 > 

Source: https://habr.com/ru/post/175321/


All Articles