[53e7d45] | 1 | #!/usr/bin/env python3 |
---|
[11f7a07] | 2 | # -*- coding: utf-8 -*- |
---|
| 3 | # |
---|
| 4 | # Copyright (c) 2014 Virtual Cable S.L. |
---|
| 5 | # All rights reserved. |
---|
| 6 | # |
---|
| 7 | # Redistribution and use in source and binary forms, with or without modification, |
---|
| 8 | # are permitted provided that the following conditions are met: |
---|
| 9 | # |
---|
| 10 | # * Redistributions of source code must retain the above copyright notice, |
---|
| 11 | # this list of conditions and the following disclaimer. |
---|
| 12 | # * Redistributions in binary form must reproduce the above copyright notice, |
---|
| 13 | # this list of conditions and the following disclaimer in the documentation |
---|
| 14 | # and/or other materials provided with the distribution. |
---|
| 15 | # * Neither the name of Virtual Cable S.L. nor the names of its contributors |
---|
| 16 | # may be used to endorse or promote products derived from this software |
---|
| 17 | # without specific prior written permission. |
---|
| 18 | # |
---|
| 19 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
---|
| 20 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
| 21 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
---|
| 22 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
---|
| 23 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
| 24 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
---|
| 25 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
---|
| 26 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
---|
| 27 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
---|
| 28 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
[ed55bec] | 29 | """ |
---|
[08ecf23] | 30 | @author: Ramón M. Gómez, ramongomez at us dot es |
---|
[ed55bec] | 31 | """ |
---|
[53e7d45] | 32 | |
---|
[683d8d4] | 33 | import base64 |
---|
[11f7a07] | 34 | import os |
---|
[5d68449] | 35 | import random |
---|
[bedce23] | 36 | import shutil |
---|
[5d68449] | 37 | import string |
---|
[a850bd1] | 38 | import threading |
---|
[0440c7c] | 39 | import time |
---|
[53e7d45] | 40 | import urllib.error |
---|
| 41 | import urllib.parse |
---|
| 42 | import urllib.request |
---|
[11f7a07] | 43 | |
---|
[68c4c91] | 44 | from configparser import NoOptionError |
---|
[53e7d45] | 45 | from opengnsys import REST, operations, VERSION |
---|
[90e5c2d] | 46 | from opengnsys.log import logger |
---|
[8c6a652] | 47 | from opengnsys.jobmgr import JobMgr |
---|
[53e7d45] | 48 | from opengnsys.workers import ServerWorker |
---|
[90e5c2d] | 49 | |
---|
[03a1cb2] | 50 | |
---|
[ed55bec] | 51 | # Check authorization header decorator |
---|
| 52 | def check_secret(fnc): |
---|
| 53 | """ |
---|
| 54 | Decorator to check for received secret key and raise exception if it isn't valid. |
---|
| 55 | """ |
---|
| 56 | def wrapper(*args, **kwargs): |
---|
| 57 | try: |
---|
[de4289a] | 58 | this, path, get_params, post_params, server = args |
---|
[3a3b642] | 59 | # Accept "status" operation with no arguments or any function with Authorization header |
---|
| 60 | if fnc.__name__ == 'process_status' and not get_params: |
---|
| 61 | return fnc(*args, **kwargs) |
---|
| 62 | elif this.random == server.headers['Authorization']: |
---|
| 63 | return fnc(*args, **kwargs) |
---|
[ed55bec] | 64 | else: |
---|
| 65 | raise Exception('Unauthorized operation') |
---|
| 66 | except Exception as e: |
---|
[1fdeb2a] | 67 | logger.debug (str(e)) |
---|
[ed55bec] | 68 | raise Exception(e) |
---|
| 69 | |
---|
| 70 | return wrapper |
---|
| 71 | |
---|
| 72 | |
---|
[0440c7c] | 73 | # Check if operation is permitted |
---|
| 74 | def execution_level(level): |
---|
| 75 | def check_permitted(fnc): |
---|
| 76 | def wrapper(*args, **kwargs): |
---|
| 77 | levels = ['status', 'halt', 'full'] |
---|
| 78 | this = args[0] |
---|
| 79 | try: |
---|
| 80 | if levels.index(level) <= levels.index(this.exec_level): |
---|
| 81 | return fnc(*args, **kwargs) |
---|
| 82 | else: |
---|
| 83 | raise Exception('Unauthorized operation') |
---|
| 84 | except Exception as e: |
---|
[1fdeb2a] | 85 | logger.debug (str(e)) |
---|
[0440c7c] | 86 | raise Exception(e) |
---|
| 87 | |
---|
| 88 | return wrapper |
---|
| 89 | |
---|
| 90 | return check_permitted |
---|
| 91 | |
---|
| 92 | |
---|
[11f7a07] | 93 | class OpenGnSysWorker(ServerWorker): |
---|
[4aa86de] | 94 | name = 'opengnsys' # Module name |
---|
[03a1cb2] | 95 | interface = None # Bound interface for OpenGnsys |
---|
[ed55bec] | 96 | REST = None # REST object |
---|
[e298c49] | 97 | user = [] # User sessions |
---|
[be263c6] | 98 | session_type = '' # User session type |
---|
[dab4e35] | 99 | random = None # Random string for secure connections |
---|
| 100 | length = 32 # Random string length |
---|
[0440c7c] | 101 | exec_level = None # Execution level (permitted operations) |
---|
[8c6a652] | 102 | jobmgr = JobMgr() |
---|
[90e5c2d] | 103 | |
---|
[16554e5] | 104 | ## pings ogcore |
---|
| 105 | def mon (self): |
---|
| 106 | n = 0 |
---|
| 107 | while True: |
---|
| 108 | time.sleep (1) |
---|
| 109 | n += 1 |
---|
| 110 | if not n % 10: |
---|
| 111 | body = { |
---|
| 112 | "iph": self.interface.ip, |
---|
| 113 | "timestamp": int (time.time()), |
---|
| 114 | } |
---|
[22f7ce0] | 115 | #logger.debug (f'about to send ping ({body})') |
---|
[16554e5] | 116 | self.REST.sendMessage ('clients/status/webhook', body) |
---|
| 117 | |
---|
[11f7a07] | 118 | def onActivation(self): |
---|
[bedce23] | 119 | """ |
---|
[44e1e4c] | 120 | Sends OGAgent activation notification to OpenGnsys server |
---|
[bedce23] | 121 | """ |
---|
[a5d0da2] | 122 | if os.path.exists ('/scripts/oginit'): |
---|
| 123 | ## estamos en oglive, este modulo no debe cargarse |
---|
| 124 | ## esta lógica la saco de src/opengnsys/linux/operations.py, donde hay un if similar |
---|
| 125 | raise Exception ('Refusing to load within an ogLive image') |
---|
| 126 | |
---|
[68c4c91] | 127 | e = None # Error info |
---|
| 128 | t = 0 # Count of time |
---|
[feb481a] | 129 | # Generate random secret to send on activation |
---|
| 130 | self.random = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(self.length)) |
---|
[11f7a07] | 131 | # Ensure cfg has required configuration variables or an exception will be thrown |
---|
[68c4c91] | 132 | try: |
---|
[16d24f3] | 133 | url = self.service.config.get(self.name, 'remote') |
---|
| 134 | ca_file = self.service.config.get(self.name, 'ca') |
---|
| 135 | crt_file = self.service.config.get(self.name, 'crt') |
---|
| 136 | key_file = self.service.config.get(self.name, 'key') |
---|
[68c4c91] | 137 | except NoOptionError as e: |
---|
| 138 | logger.error("Configuration error: {}".format(e)) |
---|
| 139 | raise e |
---|
[16d24f3] | 140 | self.REST = REST (url, ca_file=ca_file, crt_file=crt_file, key_file=key_file) |
---|
[0440c7c] | 141 | # Execution level ('full' by default) |
---|
| 142 | try: |
---|
[a5d0da2] | 143 | self.exec_level = self.service.config.get(self.name, 'level') |
---|
[68c4c91] | 144 | except NoOptionError: |
---|
[0440c7c] | 145 | self.exec_level = 'full' |
---|
[2e072d2] | 146 | # Get network interfaces until they are active or timeout (5 minutes) |
---|
| 147 | for t in range(0, 300): |
---|
[804c389] | 148 | try: |
---|
[68c4c91] | 149 | # Get the first network interface |
---|
[1a38999] | 150 | nets = list (operations.getNetworkInfo()) |
---|
| 151 | if 0 == len (nets): |
---|
| 152 | logger.error ('No network interfaces found') |
---|
| 153 | raise Exception ('No network interfaces found') |
---|
| 154 | self.interface = nets[0] |
---|
[804c389] | 155 | except Exception as e: |
---|
| 156 | # Wait 1 sec. and retry |
---|
[b84ab33] | 157 | logger.warn (e) |
---|
[02399e9] | 158 | time.sleep(1) |
---|
[804c389] | 159 | finally: |
---|
| 160 | # Exit loop if interface is active |
---|
| 161 | if self.interface: |
---|
| 162 | if t > 0: |
---|
| 163 | logger.debug("Fetch connection data after {} tries".format(t)) |
---|
| 164 | break |
---|
| 165 | # Raise error after timeout |
---|
| 166 | if not self.interface: |
---|
[f69d3ab] | 167 | ## UnboundLocalError: cannot access local variable 'e' where it is not associated with a value |
---|
[804c389] | 168 | raise e |
---|
[6a01818] | 169 | |
---|
[feb481a] | 170 | # Loop to send initialization message |
---|
[6a01818] | 171 | init_retries = 100 |
---|
| 172 | for t in range(0, init_retries): |
---|
[feb481a] | 173 | try: |
---|
| 174 | try: |
---|
| 175 | self.REST.sendMessage('ogagent/started', {'mac': self.interface.mac, 'ip': self.interface.ip, |
---|
[ed55bec] | 176 | 'secret': self.random, 'ostype': operations.os_type, |
---|
[a850bd1] | 177 | 'osversion': operations.os_version, |
---|
| 178 | 'agent_version': VERSION}) |
---|
[feb481a] | 179 | break |
---|
[6a01818] | 180 | except Exception as e: |
---|
| 181 | logger.warn (str (e)) |
---|
[feb481a] | 182 | # Trying to initialize on alternative server, if defined |
---|
| 183 | # (used in "exam mode" from the University of Seville) |
---|
[16d24f3] | 184 | self.REST = REST(self.service.config.get(self.name, 'altremote'), ca_file=ca_file, crt_file=crt_file, key_file=key_file) |
---|
[feb481a] | 185 | self.REST.sendMessage('ogagent/started', {'mac': self.interface.mac, 'ip': self.interface.ip, |
---|
[ed55bec] | 186 | 'secret': self.random, 'ostype': operations.os_type, |
---|
[a850bd1] | 187 | 'osversion': operations.os_version, 'alt_url': True, |
---|
| 188 | 'agent_version': VERSION}) |
---|
[feb481a] | 189 | break |
---|
[6a01818] | 190 | except Exception as e: |
---|
| 191 | logger.warn (str (e)) |
---|
[feb481a] | 192 | time.sleep(3) |
---|
[ed55bec] | 193 | # Raise error after timeout |
---|
[6a01818] | 194 | if t < init_retries-1: |
---|
[ed55bec] | 195 | logger.debug('Successful connection after {} tries'.format(t)) |
---|
[6a01818] | 196 | elif t == init_retries-1: |
---|
[feb481a] | 197 | raise Exception('Initialization error: Cannot connect to remote server') |
---|
[6a01818] | 198 | |
---|
[6c8f1c2] | 199 | # Delete marking files |
---|
| 200 | for f in ['ogboot.me', 'ogboot.firstboot', 'ogboot.secondboot']: |
---|
| 201 | try: |
---|
| 202 | os.remove(os.sep + f) |
---|
| 203 | except OSError: |
---|
| 204 | pass |
---|
[bedce23] | 205 | # Copy file "HostsFile.FirstOctetOfIPAddress" to "HostsFile", if it exists |
---|
[03a1cb2] | 206 | # (used in "exam mode" from the University of Seville) |
---|
[ed55bec] | 207 | hosts_file = os.path.join(operations.get_etc_path(), 'hosts') |
---|
| 208 | new_hosts_file = hosts_file + '.' + self.interface.ip.split('.')[0] |
---|
| 209 | if os.path.isfile(new_hosts_file): |
---|
| 210 | shutil.copyfile(new_hosts_file, hosts_file) |
---|
[90e5c2d] | 211 | |
---|
[16554e5] | 212 | threading.Thread (name='monitoring_thread', target=self.mon, daemon=True).start() |
---|
| 213 | |
---|
[bf09933] | 214 | logger.debug ('onActivation ok') |
---|
[a67669b] | 215 | |
---|
[11f7a07] | 216 | def onDeactivation(self): |
---|
[bedce23] | 217 | """ |
---|
[44e1e4c] | 218 | Sends OGAgent stopping notification to OpenGnsys server |
---|
[bedce23] | 219 | """ |
---|
[d231816] | 220 | now = time.time() |
---|
| 221 | for elem in self.user: |
---|
| 222 | sess_len = now - elem['login_ts'] |
---|
| 223 | logger.debug ('Session of logged in user {} took {} seconds'.format (elem['username'], int (sess_len))) |
---|
[11f7a07] | 224 | logger.debug('onDeactivation') |
---|
[03a1cb2] | 225 | self.REST.sendMessage('ogagent/stopped', {'mac': self.interface.mac, 'ip': self.interface.ip, |
---|
[ed55bec] | 226 | 'ostype': operations.os_type, 'osversion': operations.os_version}) |
---|
[90e5c2d] | 227 | |
---|
[bedce23] | 228 | def onLogin(self, data): |
---|
| 229 | """ |
---|
[44e1e4c] | 230 | Sends session login notification to OpenGnsys server |
---|
[bedce23] | 231 | """ |
---|
[be263c6] | 232 | user, language, self.session_type = tuple(data.split(',')) |
---|
| 233 | logger.debug('Received login for {0} using {2} with language {1}'.format(user, language, self.session_type)) |
---|
[d231816] | 234 | self.user.append ({'username': user, 'login_ts': time.time() }) |
---|
[03a1cb2] | 235 | self.REST.sendMessage('ogagent/loggedin', {'ip': self.interface.ip, 'user': user, 'language': language, |
---|
[be263c6] | 236 | 'session': self.session_type, |
---|
[ed55bec] | 237 | 'ostype': operations.os_type, 'osversion': operations.os_version}) |
---|
[5d68449] | 238 | |
---|
[11f7a07] | 239 | def onLogout(self, user): |
---|
[bedce23] | 240 | """ |
---|
[44e1e4c] | 241 | Sends session logout notification to OpenGnsys server |
---|
[bedce23] | 242 | """ |
---|
[d231816] | 243 | sess_len = 0 |
---|
| 244 | for elem in self.user: |
---|
| 245 | if user != elem['username']: continue |
---|
| 246 | sess_len = time.time() - elem['login_ts'] |
---|
| 247 | logger.debug ('Received logout for {}, session length {} seconds'.format (user, int (sess_len))) |
---|
[e298c49] | 248 | try: |
---|
| 249 | self.user.pop() |
---|
| 250 | except IndexError: |
---|
| 251 | pass |
---|
[44e1e4c] | 252 | self.REST.sendMessage('ogagent/loggedout', {'ip': self.interface.ip, 'user': user}) |
---|
[11f7a07] | 253 | |
---|
[ed55bec] | 254 | def process_ogclient(self, path, get_params, post_params, server): |
---|
[bedce23] | 255 | """ |
---|
| 256 | This method can be overridden to provide your own message processor, or better you can |
---|
| 257 | implement a method that is called exactly as "process_" + path[0] (module name has been removed from path |
---|
| 258 | array) and this default processMessage will invoke it |
---|
[11f7a07] | 259 | * Example: |
---|
| 260 | Imagine this invocation url (no matter if GET or POST): http://example.com:9999/Sample/mazinger/Z |
---|
| 261 | The HTTP Server will remove "Sample" from path, parse arguments and invoke this method as this: |
---|
[ed55bec] | 262 | module.processMessage(["mazinger","Z"], get_params, post_params) |
---|
[90e5c2d] | 263 | |
---|
[bedce23] | 264 | This method will process "mazinger", and look for a "self" method that is called "process_mazinger", |
---|
| 265 | and invoke it this way: |
---|
[ed55bec] | 266 | return self.process_mazinger(["Z"], get_params, post_params) |
---|
[90e5c2d] | 267 | |
---|
[bedce23] | 268 | In the case path is empty (that is, the path is composed only by the module name, like in |
---|
| 269 | "http://example.com/Sample", the "process" method will be invoked directly |
---|
[90e5c2d] | 270 | |
---|
[bedce23] | 271 | The methods must return data that can be serialized to json (i.e. Objects are not serializable to json, |
---|
| 272 | basic type are) |
---|
| 273 | """ |
---|
[90e5c2d] | 274 | if not path: |
---|
[11f7a07] | 275 | return "ok" |
---|
| 276 | try: |
---|
| 277 | operation = getattr(self, 'ogclient_' + path[0]) |
---|
| 278 | except Exception: |
---|
| 279 | raise Exception('Message processor for "{}" not found'.format(path[0])) |
---|
[ed55bec] | 280 | return operation(path[1:], get_params, post_params) |
---|
[90e5c2d] | 281 | |
---|
[de4289a] | 282 | # Warning: the order of the decorators matters |
---|
[0440c7c] | 283 | @execution_level('status') |
---|
[de4289a] | 284 | @check_secret |
---|
[ed55bec] | 285 | def process_status(self, path, get_params, post_params, server): |
---|
[bedce23] | 286 | """ |
---|
[ed55bec] | 287 | Returns client status (OS type or execution status) and login status |
---|
| 288 | :param path: |
---|
[3a3b642] | 289 | :param get_params: optional parameter "detail" to show extended status |
---|
[ed55bec] | 290 | :param post_params: |
---|
| 291 | :param server: |
---|
[3a3b642] | 292 | :return: JSON object {"status": "status_code", "loggedin": boolean, ...} |
---|
[bedce23] | 293 | """ |
---|
[4aa86de] | 294 | st = {'linux': 'LNX', 'macos': 'OSX', 'windows': 'WIN'} |
---|
| 295 | try: |
---|
[3a3b642] | 296 | # Standard status |
---|
[be263c6] | 297 | res = {'status': st[operations.os_type.lower()], 'loggedin': len(self.user) > 0, |
---|
| 298 | 'session': self.session_type} |
---|
[3a3b642] | 299 | # Detailed status |
---|
| 300 | if get_params.get('detail', 'false') == 'true': |
---|
| 301 | res.update({'agent_version': VERSION, 'os_version': operations.os_version, 'sys_load': os.getloadavg()}) |
---|
| 302 | if res['loggedin']: |
---|
[d231816] | 303 | res.update({'sessions': len(self.user), 'current_user': self.user[-1]['username']}) |
---|
[4aa86de] | 304 | except KeyError: |
---|
[e298c49] | 305 | # Unknown operating system |
---|
| 306 | res = {'status': 'UNK'} |
---|
[11f7a07] | 307 | return res |
---|
[90e5c2d] | 308 | |
---|
[0440c7c] | 309 | @execution_level('halt') |
---|
[de4289a] | 310 | @check_secret |
---|
[22f7ce0] | 311 | def process_Reiniciar(self, path, get_params, post_params, server): |
---|
[bedce23] | 312 | """ |
---|
[ed55bec] | 313 | Launches a system reboot operation |
---|
| 314 | :param path: |
---|
| 315 | :param get_params: |
---|
| 316 | :param post_params: |
---|
| 317 | :param server: authorization header |
---|
| 318 | :return: JSON object {"op": "launched"} |
---|
[bedce23] | 319 | """ |
---|
[11f7a07] | 320 | logger.debug('Received reboot operation') |
---|
[03a1cb2] | 321 | |
---|
[ed55bec] | 322 | # Rebooting thread |
---|
[11f7a07] | 323 | def rebt(): |
---|
| 324 | operations.reboot() |
---|
| 325 | threading.Thread(target=rebt).start() |
---|
| 326 | return {'op': 'launched'} |
---|
| 327 | |
---|
[0440c7c] | 328 | @execution_level('halt') |
---|
[de4289a] | 329 | @check_secret |
---|
[22f7ce0] | 330 | def process_Apagar(self, path, get_params, post_params, server): |
---|
[bedce23] | 331 | """ |
---|
[ed55bec] | 332 | Launches a system power off operation |
---|
| 333 | :param path: |
---|
| 334 | :param get_params: |
---|
| 335 | :param post_params: |
---|
| 336 | :param server: authorization header |
---|
| 337 | :return: JSON object {"op": "launched"} |
---|
[bedce23] | 338 | """ |
---|
[11f7a07] | 339 | logger.debug('Received poweroff operation') |
---|
[03a1cb2] | 340 | |
---|
[ed55bec] | 341 | # Powering off thread |
---|
[11f7a07] | 342 | def pwoff(): |
---|
| 343 | time.sleep(2) |
---|
| 344 | operations.poweroff() |
---|
| 345 | threading.Thread(target=pwoff).start() |
---|
| 346 | return {'op': 'launched'} |
---|
| 347 | |
---|
[0440c7c] | 348 | @execution_level('full') |
---|
[de4289a] | 349 | @check_secret |
---|
[22f7ce0] | 350 | def process_EjecutarScript(self, path, get_params, post_params, server): |
---|
[bedce23] | 351 | """ |
---|
[937c21f] | 352 | Processes an script execution (script should be encoded in base64) |
---|
[ed55bec] | 353 | :param path: |
---|
| 354 | :param get_params: |
---|
| 355 | :param post_params: JSON object {"script": "commands"} |
---|
| 356 | :param server: authorization header |
---|
| 357 | :return: JSON object {"op": "launched"} |
---|
[bedce23] | 358 | """ |
---|
[937c21f] | 359 | logger.debug('Processing script request') |
---|
[f69d3ab] | 360 | # Decoding script |
---|
[250de7a] | 361 | param_script = post_params.get('script') |
---|
| 362 | if not param_script: |
---|
| 363 | return {'op': 'error', 'err': 'Required parameter "script" is missing or empty'} |
---|
| 364 | try: |
---|
| 365 | b64decoded = base64.b64decode (param_script) |
---|
| 366 | except Exception as e: |
---|
| 367 | return {'op': 'error', 'err': f'Failed to decode base64: {e}'} |
---|
| 368 | script = urllib.parse.unquote (b64decoded.decode ('utf-8')) |
---|
[8c6a652] | 369 | logger.debug('received script "{}"'.format(script)) |
---|
| 370 | |
---|
[ed55bec] | 371 | if post_params.get('client', 'false') == 'false': |
---|
[8c6a652] | 372 | jobid = self.jobmgr.launch_job (script, False) |
---|
| 373 | return {'op': 'launched', 'jobid': jobid} |
---|
| 374 | |
---|
| 375 | else: ## post_params.get('client') is not 'false' |
---|
| 376 | ## send script as-is |
---|
[08ecf23] | 377 | self.sendClientMessage('script', {'code': script}) |
---|
[8c6a652] | 378 | #return {'op': 'launched', 'jobid': jobid} ## TODO obtain jobid generated at the client (can it be done?) |
---|
| 379 | return {'op': 'launched'} |
---|
| 380 | |
---|
| 381 | @execution_level('full') |
---|
| 382 | @check_secret |
---|
[d4e21da] | 383 | def process_terminatescript(self, path, get_params, post_params, server): |
---|
| 384 | jobid = post_params.get('jobid', None) |
---|
| 385 | logger.debug('Processing terminate_script request, jobid "{}"'.format (jobid)) |
---|
| 386 | if jobid is None: |
---|
| 387 | return {} |
---|
| 388 | self.sendClientMessage('terminatescript', {'jobid': jobid}) |
---|
| 389 | self.jobmgr.terminate_job (jobid) |
---|
| 390 | return {} |
---|
| 391 | |
---|
| 392 | @execution_level('full') |
---|
| 393 | @check_secret |
---|
[8c6a652] | 394 | def process_preparescripts(self, path, get_params, post_params, server): |
---|
| 395 | logger.debug('Processing preparescripts request') |
---|
| 396 | self.st = self.jobmgr.prepare_jobs() |
---|
| 397 | logger.debug('Sending preparescripts to client') |
---|
| 398 | self.sendClientMessage('preparescripts', None) |
---|
| 399 | return {} |
---|
| 400 | |
---|
| 401 | def process_client_preparescripts(self, params): |
---|
| 402 | logger.debug('Processing preparescripts message from client') |
---|
| 403 | for p in params: |
---|
| 404 | #logger.debug ('p "{}"'.format(p)) |
---|
[d4e21da] | 405 | self.st.append (p) |
---|
[8c6a652] | 406 | |
---|
| 407 | @execution_level('full') |
---|
| 408 | @check_secret |
---|
| 409 | def process_getscripts(self, path, get_params, post_params, server): |
---|
| 410 | logger.debug('Processing getscripts request') |
---|
| 411 | return self.st |
---|
[90e5c2d] | 412 | |
---|
[0440c7c] | 413 | @execution_level('full') |
---|
[de4289a] | 414 | @check_secret |
---|
[ed55bec] | 415 | def process_logoff(self, path, get_params, post_params, server): |
---|
[bedce23] | 416 | """ |
---|
[ed55bec] | 417 | Closes user session |
---|
[bedce23] | 418 | """ |
---|
[11f7a07] | 419 | logger.debug('Received logoff operation') |
---|
[ed55bec] | 420 | # Sending log off message to OGAgent client |
---|
[11f7a07] | 421 | self.sendClientMessage('logoff', {}) |
---|
[bedce23] | 422 | return {'op': 'sent to client'} |
---|
[11f7a07] | 423 | |
---|
[0440c7c] | 424 | @execution_level('full') |
---|
[de4289a] | 425 | @check_secret |
---|
[ed55bec] | 426 | def process_popup(self, path, get_params, post_params, server): |
---|
[bedce23] | 427 | """ |
---|
[ed55bec] | 428 | Shows a message popup on the user's session |
---|
[bedce23] | 429 | """ |
---|
[1deb0d1] | 430 | logger.debug('Received message operation') |
---|
[ed55bec] | 431 | # Sending popup message to OGAgent client |
---|
| 432 | self.sendClientMessage('popup', post_params) |
---|
[1deb0d1] | 433 | return {'op': 'launched'} |
---|
| 434 | |
---|
[90e5c2d] | 435 | def process_client_popup(self, params): |
---|
[1deb0d1] | 436 | self.REST.sendMessage('popup_done', params) |
---|