Ticket #988: exampleshell

File exampleshell, 8.5 KB (added by tschwaller, 16 months ago)

Example Shell using the python-configshell framework

Line 
1#!/usr/bin/python
2
3'''
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU Affero General Public License as
6published by the Free Software Foundation, version 3 (AGPLv3).
7 
8This program is distributed in the hope that it will be useful,
9but WITHOUT ANY WARRANTY; without even the implied warranty of
10MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11GNU Affero General Public License for more details.
12
13You should have received a copy of the GNU Affero General Public License
14along with this program.  If not, see <http://www.gnu.org/licenses/>.
15'''
16
17import os, sys
18import configshell
19import pwd, grp, libuser
20
21#
22# root config node, aka root directory of the shell,
23# there is not much in it, it only contains the
24# node "system"
25#
26class SystemRoot(configshell.node.ConfigNode):
27    def __init__(self, shell):
28        configshell.node.ConfigNode.__init__(self, '/', shell=shell)
29        System(self)
30
31#
32# node "system", contains the child node "users"
33# and provides two simple commands, "uname" and "lspci"
34# "lspci" can be given one optional parameter
35#
36class System(configshell.node.ConfigNode):
37    def __init__(self, parent):
38        configshell.node.ConfigNode.__init__(self, 'system', parent)
39        Users(self)
40        Hardware(self) 
41
42    # simple command without any parameters
43    def ui_command_uname(self):
44        '''
45        Displays the system uname information.
46        '''
47        os.system("uname -a")
48
49    # Simple command with one optional parameter
50    # it's an optional parameter if it get's initialized in the signature
51    # it's an required parameter if it isn't initialized in the signature
52    def ui_command_lspci(self, opt=None):
53        '''
54        lspci - list all PCI devices, I{opt} is an optional parameter for lspci, i.e. "-v"
55
56        PARAMETERS
57        ==========
58
59        I{opt}
60        -------
61        Option for lspci.
62
63
64        '''
65        if opt == None:
66            os.system("lspci")
67        else:
68            os.system("lspci %s" % opt)
69
70
71#
72# node "user", contains a child node for every user of the system
73# and provides the "show" command, that executes "getent passwd"
74#
75class Users(configshell.node.ConfigNode):
76    def __init__(self, parent):
77        configshell.node.ConfigNode.__init__(self, 'users', parent)
78
79        # get a list of all users and create a child node for each one
80        for user in pwd.getpwall():
81            User(user[0], self)
82                       
83    def ui_command_show(self):
84        '''
85        show  -  print "getent passwd" output of all users.
86        '''
87        os.system("getent passwd")
88
89
90#
91# node of a user
92# provides the commands "id", "show", "chsh" and "change"
93# the "chsh" and "change" commands have parameter completion
94#
95class User(configshell.node.ConfigNode):
96    # username of the user of this node
97    username = ""
98
99
100    def __init__(self, username, parent):
101        configshell.node.ConfigNode.__init__(self, username, parent)
102        self.username = username
103
104
105    # show the output of "getent passwd <user>"
106    def ui_command_ls(self):
107        '''
108        show  -  print "getent passwd" output of the current user.
109        '''
110        os.system("getent passwd %s" % self.username)
111
112
113    # id command, show output of "id <username>"
114    def ui_command_id(self):
115        '''
116        id  -  print "id" output.
117        '''
118        os.system("id %s" % self.username)
119
120
121    # chsh command, shell is a required parameter
122    def ui_command_chsh(self, shell):
123        '''
124        chsh - change the shell of this user to I{shell}
125           
126        PARAMETERS
127        ==========
128
129        I{shell}
130        -------
131        Shell to set as a login shell for the current user.
132
133
134        '''
135        # only execute chsh if shell is a valid login shell
136        if shell in libuser.get_user_shells():
137            os.system("chsh -s %s %s" % (shell, self.username))
138        else:
139            self.shell.log.error("%s is not a valid login shell!" % shell)
140
141
142    # parameter completion for chsh command
143    def ui_complete_chsh(self, parameters, text, current_param):
144        completions = []
145
146        self.shell.log.debug("Called with params=%s, text='%s', current='%s'"
147                             % (str(parameters), text, current_param))
148
149        # if current parameter is "shell" we return completions
150        # that are in /etc/shells and start with "text"
151        if current_param == 'shell':
152            completions = [shell for shell in libuser.get_user_shells()
153                           if shell.startswith(text)]
154
155        self.shell.log.debug("Returning completions %s." % str(completions))
156        return completions
157
158
159    # change command, changes various attributes of a user
160    def ui_command_change(self, shell=None, group=None, home=None):
161        '''
162        change - changes various attributes of a user
163           
164        PARAMETERS
165        ==========
166
167        I{shell}
168        --------
169        Shell to set as a login shell for the current user.
170
171        I{group}
172        --------
173        Group that should be set as the primary group of
174        the current user and changes the group of all files of
175        the users home directory.
176
177        I{home}
178        -------
179        Directory that should be set as the home directory.
180
181        SEE ALSO
182        ========
183        chsh
184
185        '''
186        # only execute chsh if shell is a valid login shell
187        if shell != None:
188            if shell in libuser.get_user_shells():
189                os.system("chsh -s %s %s" % (shell, self.username))
190            else:
191                self.shell.log.error("%s is not a valid login shell!" % shell)
192
193        if home != None:
194            os.system("usermod -d %s %s" % (home, self.username))
195
196        if group != None:
197            if group in [gr[0] for gr in grp.getgrall()]:
198                os.system("usermod -g %s %s" % (group, self.username))
199            else:
200                self.shell.log.error("%s is not a valid group!" % group)
201
202
203    # parameter completion for change command
204    def ui_complete_change(self, parameters, text, current_param):
205        completions = []
206
207        self.shell.log.debug("Called with params=%s, text='%s', current='%s'"
208                             % (str(parameters), text, current_param))
209
210        # if current parameter is "shell" we return completions
211        # that are in /etc/shells and start with "text"
212        if current_param == 'shell':
213            completions = [shell for shell in libuser.get_user_shells() 
214                           if shell.startswith(text)]
215
216        # if current parameter is "group" we get a list of groups
217        # and return completions that start with "text"
218        if current_param == 'group':
219            completions = [gr[0] for gr in grp.getgrall()
220                           if gr[0].startswith(text)]
221
222        if len(completions) == 1 and not completions[0].endswith('='):
223            completions = [completions[0] + ' ']
224
225
226        self.shell.log.debug("Returning completions %s." % str(completions))
227        return completions
228
229
230class Hardware(configshell.node.ConfigNode):
231    def __init__(self, parent):
232        configshell.node.ConfigNode.__init__(self, 'hardware', parent)
233        Partitions(self)
234
235                       
236class Partitions(configshell.node.ConfigNode):
237    def __init__(self, parent):
238        configshell.node.ConfigNode.__init__(self, 'partitions', parent)
239
240        # get a list of all partitions and create a child node for each one
241        for partition in self.get_partitions():
242            Partition(partition, self)
243                       
244    def get_partitions(self):
245        partitions = []
246        with open('/proc/partitions', 'r') as f:
247            for line in f.readlines()[2:]:
248                partitions.append(line.split()[3])
249        return partitions
250
251
252class Partition(configshell.node.ConfigNode):
253    # partition name of this node
254    partition = ""
255
256    def __init__(self, partition, parent):
257        configshell.node.ConfigNode.__init__(self, partition, parent)
258        self.partition = partition
259
260    def ui_command_ls(self):
261        '''
262        ls  -  print "hdparm -I" output of partition.
263        '''
264        os.system("hdparm -I /dev/%s" % self.partition)
265
266    def ui_command_benchmark(self):
267        '''
268        benchmark  -  print "hdparm -t" output of partition.
269        '''
270        os.system("hdparm -t /dev/%s" % self.partition)
271
272#
273# main
274#
275def main():
276    shell = configshell.shell.ConfigShell('~/.exampleshell')
277    root_node = SystemRoot(shell)
278    if len(sys.argv) > 1:
279        shell.run_script(sys.argv[1])
280        sys.exit(0)
281    else:
282        shell.run_interactive()
283
284if __name__ == "__main__":
285    main()