cli.py 8.72 KB
Newer Older
Giorgos Korfiatis's avatar
Giorgos Korfiatis committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Copyright (C) 2015 GRNET S.A.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

16
17
18
import cmd
import sys
import logging
19
import time
20
from agkyra import config, protocol, protocol_client
21
22
23
24
25


LOG = logging.getLogger(__name__)


26
27
class ConfigCommands:
    """Commands for handling Agkyra config options"""
28
29
30
31
32
33
    cnf = config.AgkyraConfig()

    def print_option(self, section, name, option):
        """Print a configuration option"""
        section = '%s.%s' % (section, name) if name else section
        value = self.cnf.get(section, option)
34
        sys.stdout.write('  %s: %s\n' % (option, value))
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

    def list_section(self, section, name):
        """list contents of a section"""
        content = dict(self.cnf.items(section))
        if section in 'global' and name:
            self.print_option(section, '', name)
        else:
            if name:
                content = content[name]
            for option in content.keys():
                self.print_option(section, name, option)

    def list_section_type(self, section):
        """print the contents of a configuration section"""
        names = ['', ] if section in ('global', ) else self.cnf.keys(section)
        assert names, 'Section %s not found' % section
        for name in names:
            print section, name
            self.list_section(section, name)

    def list_sections(self):
        """List all configuration sections"""
        for section in self.cnf.sections():
            self.list_section_type(section)

60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
    def set_global_setting(self, section, option, value):
        assert section in ('global'), 'Syntax error'
        self.cnf.set(section, option, value)
        self.cnf.write()

    def set_setting(self, section, name, option, value):
        assert section in self.cnf.sections(), 'Syntax error'
        self.cnf.set('%s.%s' % (section, name), option, value)
        self.cnf.write()

    def delete_global_option(self, section, option, yes=False):
        """Delete global option"""
        if (not yes and 'y' != raw_input(
                'Delete %s option %s? [y|N]: ' % (section, option))):
            sys.stderr.write('Aborted\n')
        else:
            self.cnf.remove_option(section, option)
            self.cnf.write()

    def delete_section_option(self, section, name, option, yes=False):
        """Delete a section (sync or cloud) option"""
        assert section in self.cnf.sections(), 'Syntax error'
        if (not yes and 'y' != raw_input(
                'Delete %s of %s "%s"? [y|N]: ' % (option, section, name))):
            sys.stderr.write('Aborted\n')
        else:
            if section == config.CLOUD_PREFIX:
                self.cnf.remove_from_cloud(name, option)
            elif section == config.SYNC_PREFIX:
                self.cnf.remove_from_sync(name, option)
            else:
                self.cnf.remove_option('%s.%s' % (section, name), option)
            self.cnf.write()

    def delete_section(self, section, name, yes=False):
        """Delete a section (sync or cloud)"""
        if (not yes and 'y' != raw_input(
                'Delete %s "%s"? [y|N]: ' % (section, name))):
            sys.stderr.write('Aborted\n')
        else:
            self.cnf.remove_option(section, name)
            self.cnf.write()


104
class AgkyraCLI(cmd.Cmd):
105
106
    """The CLI for Agkyra is connected to a protocol server"""
    cnf_cmds = ConfigCommands()
107
108
109
110
111
112
113
114
115
116
117
118
    helper = protocol.SessionHelper()

    @property
    def client(self):
        """Return the helper client instace or None"""
        self._client = getattr(self, '_client', None)
        if not self._client:
            session = self.helper.load_active_session()
            if session:
                self._client = protocol_client.UIClient(session)
                self._client.connect()
        return self._client
119
120
121
122
123
124
125
126
127
128
129
130

    def preloop(self):
        """Prepare agkyra shell"""
        self.prompt = '\xe2\x9a\x93 '
        self.default('')

    def precmd(self):
        print 'PRE'

    def postcmd(self):
        print 'POST'

131
132
133
134
135
136
137
    def config_list(self, args):
        """List (all or some) options
        list                                List all options
        list <global | cloud | sync>        List global | cloud | sync options
        list global OPTION                  Get global option
        list <cloud | sync> NAME            List options a cloud or sync
        list <cloud | sync> NAME OPTION     List an option from a cloud or sync
138
139
140
        """
        try:
            {
141
142
143
144
                0: self.cnf_cmds.list_sections,
                1: self.cnf_cmds.list_section_type,
                2: self.cnf_cmds.list_section,
                3: self.cnf_cmds.print_option
145
146
            }[len(args)](*args)
        except Exception as e:
147
148
            LOG.debug('%s\n' % e)
            sys.stderr.write(self.config_list.__doc__ + '\n')
149

150
151
152
153
154
155
156
    def config_set(self, args):
        """Set an option
        set global OPTION VALUE                 Set a global option
        set <cloud | sync> NAME OPTION VALUE    Set an option on cloud or sync
                                                Creates a sync or cloud, if it
                                                does not exist
        """
157
158
        try:
            {
159
160
                3: self.cnf_cmds.set_global_setting,
                4: self.cnf_cmds.set_setting
161
162
            }[len(args)](*args)
        except Exception as e:
163
164
165
166
167
            LOG.debug('%s\n' % e)
            sys.stderr.write(self.config_set.__doc__ + '\n')

    def config_delete(self, args):
        """Delete an option
168
169
170
        delete global OPTION [-y]               Delete a global option
        delete <cloud | sync> NAME [-y]         Delete a sync or cloud
        delete <cloud |sync> NAME OPTION [-y]   Delete a sync or cloud option
171
        """
172
173
174
175
176
        try:
            args.remove('-y')
            args.append(True)
        except ValueError:
            args.append(False)
177
178
        try:
            {
179
180
181
                3: self.cnf_cmds.delete_global_option if (
                    args[0] == 'global') else self.cnf_cmds.delete_section,
                4: self.cnf_cmds.delete_section_option
182
183
184
185
            }[len(args)](*args)
        except Exception as e:
            LOG.debug('%s\n' % e)
            sys.stderr.write(self.config_delete.__doc__ + '\n')
186

187
188
189
190
191
192
193
194
195
196
197
198
199
    def do_config(self, line):
        """Commands for managing the agkyra settings
        list   [global|cloud|sync [setting]]          List all or some settings
        set    <global|cloud|sync> <setting> <value>  Set a setting
        delete <global|cloud|sync> [setting]          Delete a setting or group
        """
        args = line.split(' ')
        try:
            method = getattr(self, 'config_' + args[0])
            method(args[1:])
        except AttributeError:
            self.do_help('config')

200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
    def do_status(self, line):
        """Get Agkyra client status. Status may be one of the following:
            Up and syncing  There is a process syncing right now
            Up and paused   Notifiers are active but syncing is paused
            Not running     No active processes
        """
        client = self.client
        if client:
            # Ask the server for the status
            status = client.get_status()
            msg = 'paused' if status['paused'] else 'running'
            sys.stdout.write('Up and %s\n' % msg)
        else:
            sys.stdout.write('Not running\n')
        sys.stdout.flush()
215

216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
    def do_launch(self, line):
        """Start the Agkyra daemon if it is not running"""
        if self.client:
            sys.stderr.write('An Agkyra daemon is already running\n')
        else:
            sys.stderr.write('Launcing a new Agkyra daemon\n')
            protocol.launch_server()
            sys.stderr.write('Waiting for the deamon to load\n')
            self.helper.wait_session_to_load()
            self.do_status('')
        sys.stderr.flush()

    def do_stop(self, line):
        """Stop the Agkyra daemon, if it is running"""
        client = self.client
        if client:
            client.shutdown()
            success = self.helper.wait_session_to_stop()
            sys.stderr.write('Stopped' if success else 'Still up (timed out)')
            sys.stderr.write('\n')
        else:
            sys.stderr.write('No daemons running\n')
        sys.stderr.flush()