diff --git a/console/application/cl_client.py b/console/application/cl_client.py index 84578fc..4473ab8 100644 --- a/console/application/cl_client.py +++ b/console/application/cl_client.py @@ -13,6 +13,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +from calculate.core.server.replace_class import Display, Methods from sudsds import WebFault from sudsds.transport import TransportError @@ -22,7 +23,6 @@ import traceback as tb import time, logging import os, sys import threading, urllib2 -from function import analysis, clear, get_entire_frame, get_view_params from pid_information import client_list_methods from cert_func import client_post_auth, client_post_request, client_get_cert,\ client_post_cert, get_password_from_daemon, clear_password @@ -33,10 +33,21 @@ import M2Crypto, OpenSSL from calculate.core.datavars import DataVarsCore from client_class import HTTPSClientCertTransport from methods_func import call_method, get_method_argparser, parse, get_view +from function import MessageReceiver, MessageDispatcher, clear, _print, \ + get_view_params from calculate.lib.utils.files import makeDirectory, readLinesFile from calculate.lib.cl_lang import setLocalTranslate setLocalTranslate('cl_console3',sys.modules[__name__]) + +def get_message_receiver(client): + return MessageReceiver(client, MessageDispatcher(Methods()), Display()) + + +def get_entire_message_receiver(client, pid): + return MessageReceiver.from_entire(client, pid, + MessageDispatcher(Methods()), Display()) + def client_signal(client): Vars = DataVarsCore() Vars.importCore() @@ -235,11 +246,23 @@ def https_server(client, args, unknown_args, url, clVarsCore, wait_thread): else: from pid_information import client_list_pid client_list_pid(client) + return 0 + + try: + client.frame_period = clVarsCore.Get('core.cl_core_get_frame_period') + except: + client.frame_period = 2 if args.pid_res: wait_thread.stop() - get_entire_frame(client, args.pid_res) - return 0 + mr = get_entire_message_receiver(client, args.pid_res) + if mr: + mr.get_messages() + if not args.keep_result: + client.service.clear_pid_cache(client.sid, args.pid_res) + return 0 + else: + return 1 if args.pid_kill: wait_thread.stop() @@ -265,15 +288,13 @@ def https_server(client, args, unknown_args, url, clVarsCore, wait_thread): client.service.clear_method_cache(client.sid, args.method) else: - try: - client.frame_period = clVarsCore.Get('core.cl_core_get_frame_period') - except: - client.frame_period = 2 method_result = call_method(client, args, unknown_args, wait_thread) + mr = get_message_receiver(client) if method_result: client.no_progress = args.no_progress try: - analysis(client, client.sid, method_result) + mr.analysis(method_result) + #analysis(client, client.sid, method_result) except urllib2.URLError, e: _print (e) except KeyboardInterrupt: @@ -290,10 +311,9 @@ def https_server(client, args, unknown_args, url, clVarsCore, wait_thread): print _("Session not matching your certificate") elif result == 1: print _("Failed to terminate the process") -# get_entire_frame(client, pid) - analysis(client, client.sid, method_result) + mr.analysis(method_result) except Exception, e: - _print (e.message) + _print(e.message) try: mess = method_result[0][0] @@ -302,7 +322,8 @@ def https_server(client, args, unknown_args, url, clVarsCore, wait_thread): return 1 retCode = \ 1 if int(client.service.pid_info(client.sid,pid)[0][1]) else 0 - client.service.clear_pid_cache(client.sid, pid) + if not args.keep_result: + client.service.clear_pid_cache(client.sid, pid) client.service.clear_method_cache(client.sid, args.method) wait_thread.stop() return retCode diff --git a/console/application/function.py b/console/application/function.py index 65517b0..b6ca5e0 100644 --- a/console/application/function.py +++ b/console/application/function.py @@ -1,6 +1,6 @@ #-*- coding: utf-8 -*- -# Copyright 2012-2013 Calculate Ltd. http://www.calculate-linux.org +# Copyright 2012-2014 Calculate Ltd. http://www.calculate-linux.org # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,39 +13,24 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from itertools import cycle -import time, os, sys, re -from fcntl import ioctl -from array import array -import termios +import time, os, sys import subprocess from OpenSSL import crypto import shlex -from calculate.core.server.func import shortTraceback -from calculate.lib.utils.colortext import get_terminal_print -from sudsds import MethodNotFound +from calculate.core.client.function import create_obj +from calculate.core.server.api_types import ArrayReturnedMessage, TableAdapter from calculate.core.server.cert_cmd import getHwAddr, getIpLocal -from calculate.core.server.replace_class import (printTable, Methods, - print_brief_group) +from calculate.core.server.replace_class import print_brief_group -from calculate.core.client.progressbar import Bar,Percentage,ETA,ProgressBar from calculate.lib.cl_lang import setLocalTranslate -from calculate.lib.cl_print import color_print -setLocalTranslate('cl_console3',sys.modules[__name__]) -from calculate.core.client.function import create_obj - -green = '\033[32m * \033[0m' -red = '\033[31m * \033[0m' +from sudsds import MethodNotFound -class _color_print(color_print): - def _printSUCCESS(self, string, offsetL=0, printBR=True): - self.printSUCCESS(string.encode('utf-8'), offsetL, printBR) +setLocalTranslate('cl_console3', sys.modules[__name__]) -colorPrint = _color_print() -def _print (*args): - print " ".join(map(lambda x:unicode(x).encode('utf-8'),args)) +def _print(*args): + print " ".join(map(lambda x: unicode(x).encode('utf-8'), args)) # get list of certificate and session id def get_sid (SID_FILE): @@ -68,8 +53,8 @@ def clear (): #print "delete", filename try: os.unlink (filename) - except OSError, e: - _print (e.message) + except OSError as e: + _print(e.message) except: print _("Failed to clear the cache! ") return 1 @@ -107,90 +92,29 @@ def print_brief(view, brief_label): continue print_brief_group(Group.fields.Field, Group.name) -class switch(object): - def __init__(self, value): - self.value = value - self.fall = False - - def __iter__(self): - """Return the match method once, then stop""" - yield self.match - raise StopIteration - - def match(self, *args): - """Indicate whether or not to enter a case suite""" - if self.fall or not args: - return True - elif self.value in args: # changed for v1.5, see below - self.fall = True - return True - else: - return False - -#################API FUNCTION############################### -def show_view(view): - return - print "+====== show view! ======+" - -def show_table(table, item): - if item.message: - colorPrint._printSUCCESS(item.message) - head = table.head.string if hasattr (table.head, 'string') else None - data = [] - for line in table.body[0]: - if hasattr (line, 'string'): - data.append(line.string) - - res = printTable(data, head) - sys.stdout.write(res+"\n") - sys.stdout.flush() - -def show_error(item): - if item.message: - for line in item.message.splitlines(): - Methods().printERROR(line) - -def show_warning(item): - if item.message: - for line in item.message.splitlines(): - Methods().printWARNING(line) - -def show_group(item): - if item.message: - for line in item.message.splitlines(): - Methods().printSUCCESS(line) - -def show_result(result): - pass - -def startTask(item): - if item.message: - for line in item.message.splitlines(): - Methods().printSUCCESS(line) - #colorPrint._printSUCCESS(line) - -def endTask(item): - if item.result is None: - result = item.message - else: - result = item.result - methods = Methods() - methods.terminal_print.up(1)('\r') - Methods().displayResult(result) - - -def beginFrame(item): - pass - -def endFrame(item): - pass -def startGroup(item): - if item.message: - Methods().startGroup(item.message) - -def endGroup(item): - pass +def _return_revoked_serials(self, crlfile): + try: + serials = [] + crltext = open(crlfile, 'r').read() + crl = crypto.load_crl(crypto.FILETYPE_PEM, crltext) + revs = crl.get_revoked() + for revoked in revs: + serials.append(str(revoked.get_serial())) + return serials + except (ImportError, AttributeError): + call = '/usr/bin/openssl crl -text -noout -in %s' % crlfile + call = shlex.split(call) + serials = [] + (res,err)=subprocess.Popen(call, stdout=subprocess.PIPE).communicate() + for line in res.split('\n'): + if line.find('Serial Number:') == -1: + continue + (crap, serial) = line.split(':') + serial = serial.strip() + serial = int(serial, 16) + serials.append(serial) + return serials def _create_obj(client, method): try: @@ -211,285 +135,207 @@ def get_view_params(client, method, step = None, expert = None, brief = None, view_params.onlyhelp = onlyhelp return view_params -def callView(client, item, sid): - return - _print ("\n",item.message) - try: - view_params = get_view_params(client, item.message, brief = True, \ - expert = True) - view = client.service[0][item.message] (sid, view_params) - show_view(view) - except: - pass -#################MESSAGE#################################### -def analysis(client, sid, s): - """ analysis of the bounced message method """ - messages = s[0] - for mess in messages: - if mess.type == 'pid': - try: - pid = int(mess.message) - except: - show_error(_('the server sent PID = ') + pid) - return 1 - get_messages(client, sid, pid) - elif mess.type == 'error': - show_error(mess) - elif mess.type == 'warning': - show_warning(mess) - -def get_message(client, item, sid, pid): - """ get one message by its type """ - for case in switch(item.type): - if case('normal'): - if item.message: - Methods().printSUCCESS(item.message) - return 1 - if case('plain'): - if item.message: - Methods().printDefault(item.message) - return 1 - if case('pre'): - if item.message: - Methods().printPre(item.message) - return 1 - if case('choice'): - message, answers = item.message.split('|') - answers = map(lambda x: (x[0], x[1].strip(')')), - map(lambda x: x.split('('), - answers.split(','))) - answer = Methods().askChoice(message, answers) - client.service.send_message(sid, pid, answer) - return 1 - if case('progress'): - if not client.no_progress: - get_Progress(client, sid, pid, item.id) - return 1 - if case('error'): - show_error(item) - if item.message == "403 Forbidden": - return 0 - return 1 - if case('warning'): - show_warning(item) - return 1 - if case('table'): - get_Table(client, sid, pid, item) - return 1 - if case('group'): - show_group(client, sid, pid, item) - return 1 - if case('question'): - send_Message(client, sid, pid, item) - return 1 - if case('confirm'): - send_Confirm(client, sid, pid, item) - return 1 - if case('password'): - send_Password(client, sid, pid, item) - return 1 - if case('startTask'): - startTask(item) - return 1 - if case('endTask'): - endTask(item) - return 1 - if case('beginFrame'): - beginFrame(item) - return 1 - if case('endFrame'): - endFrame(item) - return 0 - if case('startGroup'): - startGroup(item) - return 1 - if case('endGruop'): - endGroup(item) - return 1 - if case('briefParams'): - callView(client, item, sid) - if case(): # default, could also just omit condition or 'if True' - return 1 - -def get_messages(client, sid, pid): - """ get frame in a separate thread """ - #thread_messages = threading.Thread(target=get_Frame,\ - #args = (client, sid, pid)) - #thread_messages.start() - get_Frame(client, sid, pid) - - -def get_Frame(client, sid, pid): - """ get all messages, until type is not endFrame (or Error) """ - end_frame = 1 - spinner = cycle('/-\|') - while end_frame: - current_frame = client.service[0].get_frame(sid, pid, "console") - sys.stdout.write(spinner.next()) - sys.stdout.flush() - while current_frame in [None, [], ""]: - sys.stdout.write("\b%s"% spinner.next()) - sys.stdout.flush() - time.sleep(float(client.frame_period)/10) - current_frame = client.service[0].get_frame(sid, pid, "console") - sys.stdout.write('\b') - sys.stdout.flush() - - for item in current_frame[0]: - end_frame = get_message(client, item, sid, pid) - -def get_entire_frame(client, pid): - """ get entire frame, from beginning (if client disconnected) """ - sid = get_sid(client.SID_FILE) - list_pid = client.service.list_pid(sid = sid) - if hasattr (list_pid, 'integer'): - if not pid in list_pid.integer: - print \ - _('The process does not exist or does not belong to your session') - end_frame = 1 - while end_frame: - current_frame = client.service.get_entire_frame(sid, pid) - while current_frame in [None, [], ""]: - time.sleep(1) - current_frame = client.service.get_frame(sid, pid, "console") - for item in current_frame[0]: - end_frame = get_message(client, item, sid, pid) - - -def get_Progress(client, sid, pid, id): - widgets = ['', '', Bar(), '', Percentage(), ' ', ETA()] - pbar = ProgressBar(widgets=widgets, maxval=100) - pbar.start() - - """ get progress for the current job """ - returnProgr = client.service.get_progress(sid, pid, id) - temp_progress = -1 - last_message = '' - percent = returnProgr.percent - try: - while percent <= 100 and percent >= 0: - if temp_progress != percent: - last_message = print_progressbar(returnProgr, pbar, - last_msg=last_message) - if percent == 100: - return - temp_progress = percent - else: - pbar.update(percent) - time.sleep(1) - returnProgr = client.service.get_progress(sid, pid, id) - percent = returnProgr.percent - if percent < 0: - pbar.update(0) - pbar.finish() - else: - pbar.update(100) - pbar.finish() - finally: - terminal_print = \ - get_terminal_print(color_print().defaultPrint) - terminal_print.up(1).clear_line("") - #terminal_print.up(1)("") - -def cout_progress(string): - h,w=array('h', ioctl(sys.stderr,termios.TIOCGWINSZ,'\0'*8))[:2] - sys.stdout.write('\r' + (' '*(w))) - sys.stdout.write('\r' + string) - sys.stdout.flush() - -def cout(string): - sys.stdout.write(string) - sys.stdout.flush() - -def print_progressbar(returnProgr, pbar, last_msg = None, error = False): - if returnProgr.long_message: - if last_msg != returnProgr.long_message: - colorPrint._printSUCCESS('%s\n' %returnProgr.long_message) - pbar.update(returnProgr.percent) - return returnProgr.long_message - elif returnProgr.short_message: - if last_msg != returnProgr.short_message: - colorPrint._printSUCCESS('%s\n' %returnProgr.short_message) - pbar.update(returnProgr.percent) - return returnProgr.short_message - else: - pbar.update(returnProgr.percent) - return last_msg - -def print_progress(returnProgr, last_msg = None, error = False): - if error: - cout_progress (red + '\n'+_("Task error by %s") \ - %str(0 - returnProgr.percent).rjust(5) + '%\n') - return '' - elif returnProgr.long_message: - if last_msg == returnProgr.long_message: - cout_progress('%s%%' %str(returnProgr.percent).rjust(5)) - else: - if not last_msg: - cout_progress('') - else: - cout_progress('OK'.rjust(6) + '\n') - cout_progress(green + '%s %s%%' %(returnProgr.long_message, \ - str(returnProgr.percent).rjust(5))) - return returnProgr.long_message - elif returnProgr.short_message: - if last_msg == returnProgr.short_message: - cout_progress('%s%%' %str(returnProgr.percent).rjust(5)) +class MessageReceiver(object): + """ + Объект организует цикл получения сообщений от WsdlServer и передает их на + обработку MessageDispatcher + """ + class States: + Messages = 0 + Progress = 1 + Finish = 2 + + def __init__(self, client, message_dispatcher=None, display=None): + """ + @param display: Display + @param message_dispatcher: MessageDispatcher + """ + self.client = client + self.sid = client.sid + self.message_dispatcher = message_dispatcher + self.message_dispatcher.parent = self + self.display = display + self.state = self.States.Messages + self.pid = 0 + self.entire = False + + @classmethod + def from_entire(cls, client, pid, message_dispatcher=None, display=None): + sid = get_sid(client.SID_FILE) + list_pid = client.service.list_pid(sid=sid) + if hasattr(list_pid, 'integer'): + if not pid in list_pid.integer: + display.print_error( + _("The process does not exist or does not belong to " + "your session")) + return None + obj = cls(client, message_dispatcher, display) + obj.sid = sid + obj.pid = pid + obj.entire = True + return obj + + def analysis(self, method_result): + """ analysis of the bounced message method """ + messages = ArrayReturnedMessage.from_detect(method_result) + for message in messages: + if message.type == 'pid': + try: + self.pid = int(message.message) + except (ValueError, AttributeError): + self.display.print_error( + _('the server sent PID = ') + str(message)) + return 1 + try: + self.get_messages() + except Exception as e: + import traceback + traceback.print_exc() + elif message.type == 'error': + self.display.print_error(message.message) + elif message.type == 'warning': + self.display.print_warning(message.message) + + def get_client_frame(self): + if self.entire: + self.entire = False + return self.client.service[0].get_entire_frame(self.sid, self.pid, + "console") else: - if not last_msg: - cout_progress('') - else: - cout_progress('OK'.rjust(6) + '\n') - cout_progress(green + '%s %s%%' %(returnProgr.short_message, \ - str(returnProgr.percent).rjust(5))) - return returnProgr.short_message - else: -# print '%s' %str(returnProgr.percent).rjust(5) + '%' - cout_progress ('%s' %str(returnProgr.percent).rjust(5) + '%') - return '' - -def get_Table(client, sid, pid, item): - table = client.service.get_table(sid, pid, item.id) - show_table(table, item) - -def send_Confirm(client,sid,pid,item): - ask = Methods().askConfirm(item.message, item.default or "") - client.service.send_message(sid, pid, ask) - -def send_Message(client, sid, pid, item): - """ send answer to the question """ - print - answer = raw_input (item.message) - client.service.send_message(sid, pid, answer) -# show_result(result) - -def send_Password(client, sid, pid, item): - """ send password """ - from getpass import getpass - password = getpass(prompt=item.message) - result = client.service.send_message(sid, pid, password) - show_result(result) + return self.client.service[0].get_frame(self.sid, self.pid, + "console") + + def get_messages(self): + """ get all messages, until type is not endFrame (or Error) """ + self.state = self.States.Messages + + while self.state != self.States.Finish: + if self.state == self.States.Messages: + current_frame = self.get_client_frame() + while current_frame in [None, [], ""]: + time.sleep(float(self.client.frame_period)/10) + current_frame = self.get_client_frame() + for item in current_frame[0]: + self.message_dispatcher.dispatch_message(item) + + def get_client_progress(self, id): + return self.client.service.get_progress(self.sid, self.pid, id).percent + + def get_progress(self, id): + percent = self.get_client_progress(id) + yield percent + while 0 <= percent < 100: + time.sleep(0.2) + temp_percent = self.get_client_progress(id) + if temp_percent != percent: + percent = temp_percent + yield percent + if percent < 0: + yield 0 + elif percent > 100: + yield 100 + + def get_table(self, id): + return self.client.service.get_table(self.sid, self.pid, id) + + def send_message(self, message): + self.client.service.send_message(self.sid, self.pid, message) + + +class MessageDispatcher(object): + """ + Объект разбирает полученное сообщение Message через функцию dispatch_message + + В дальнейшем взаимодействует с parent через методы get_progress, get_table, + send_message, поле State + """ + def __init__(self, methods=None): + """ + @param methods: Common + """ + self.methods = methods + self.parent = None + self.dispatchers = {'endFrame': self.end_frame, + 'progress': self.progress, + 'startTask': self.start_task, + 'endTask': self.end_task, + 'startGroup': self.start_group, + 'endGroup': self.end_group, + 'normal': self.print_success, + 'error': self.print_error, + 'warning': self.print_warning, + 'pre': self.print_pre, + 'plain': self.print_default, + 'table': self.print_table, + 'choice': self.ask_choice, + 'confirm': self.ask_confirm, + 'question': self.ask_question, + } + + def default_action(self, message): + pass -def _return_revoked_serials(self, crlfile): - try: - serials = [] - crltext = open(crlfile, 'r').read() - crl = crypto.load_crl(crypto.FILETYPE_PEM, crltext) - revs = crl.get_revoked() - for revoked in revs: - serials.append(str(revoked.get_serial())) - return serials - except (ImportError, AttributeError): - call = '/usr/bin/openssl crl -text -noout -in %s' % crlfile - call = shlex.split(call) - serials = [] - (res,err)=subprocess.Popen(call, stdout=subprocess.PIPE).communicate() - for line in res.split('\n'): - if line.find('Serial Number:') == -1: - continue - (crap, serial) = line.split(':') - serial = serial.strip() - serial = int(serial, 16) - serials.append(serial) - return serials + def dispatch_message(self, message): + self.dispatchers.get(message.type, self.default_action)(message) + + def end_frame(self, message): + self.parent.state = self.parent.States.Finish + + def progress(self, message): + self.methods.addProgress(message.message) + for perc in self.parent.get_progress(message.id): + self.methods.setProgress(perc) + + def start_task(self, message): + self.methods.startTask(message.message) + + def end_task(self, message): + self.methods.endTask(message.message) + + def start_group(self, message): + self.methods.startGroup(message.message) + + def end_group(self, message): + self.methods.endGroup() + + def print_success(self, message): + self.methods.printSUCCESS(message.message) + + def print_error(self, message): + self.methods.printERROR(message.message) + if "403 Forbidden" in message.message: + self.parent.state = self.parent.States.Finish + + def print_warning(self, message): + self.methods.printWARNING(message.message) + + def print_pre(self, message): + self.methods.printPre(message.message) + + def print_default(self, message): + self.methods.printDefault(message.message) + + def print_table(self, message): + table = TableAdapter.from_detect(self.parent.get_table(message.id)) + self.methods.printTable(message.message, table.head, table.body) + + def ask_choice(self, message): + message, answers = message.message.split('|') + answers = map(lambda x: (x[0], x[1].strip(')')), + map(lambda x: x.split('('), + answers.split(','))) + answer = self.methods.askChoice(message, answers) + self.parent.send_message(answer) + + def ask_confirm(self, message): + answer = self.methods.askConfirm(message.message, message.default or "") + self.parent.send_message(answer) + + def ask_question(self, message): + answer = self.methods.askQuestion(message.message) + self.parent.send_message(answer) + + def ask_password(self, message): + answer = self.methods.askPassword(message.message, message.id == 2) + self.parent.send_message(answer) diff --git a/console/application/methods_func.py b/console/application/methods_func.py index 0bc6f7a..0570742 100644 --- a/console/application/methods_func.py +++ b/console/application/methods_func.py @@ -1,6 +1,6 @@ #-*- coding: utf-8 -*- -# Copyright 2012-2013 Calculate Ltd. http://www.calculate-linux.org +# Copyright 2012-2014 Calculate Ltd. http://www.calculate-linux.org # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,10 +17,10 @@ import argparse, sys from calculate.core.server.api_types import ViewInfoAdapter from calculate.core.server.replace_class import Methods -from function import _create_obj, get_view_params, print_brief, _print, \ - colorPrint +from function import _create_obj, get_view_params, print_brief, _print from calculate.lib.cl_lang import setLocalTranslate -setLocalTranslate('cl_console3',sys.modules[__name__]) + +setLocalTranslate('cl_console3', sys.modules[__name__]) import urllib2 from calculate.core.server.methods_func import get_method_argparser, \ @@ -65,6 +65,9 @@ def parse(): parser.add_argument( '--pid-result', type=int, metavar = 'PID', dest='pid_res', help=_("view the result of the process")) + parser.add_argument( + '--keep-result', action='store_true', default=False, + dest='keep_result', help=_("keep cache of process result")) parser.add_argument( '--pid-kill', type=int, metavar = 'PID', dest='pid_kill', help=_("kill the selected process")) @@ -108,8 +111,8 @@ def get_view(client, method, sid, view_params): def call_method(client, args, unknown_args, wait_thread): method = args.method stdin_passwd = args.stdin_passwd - view_params = get_view_params(client, method + '_view', step = None, \ - expert = True) + view_params = get_view_params(client, method + '_view', step=None, \ + expert=True) view = get_view(client, method, client.sid, view_params) method_parser = get_method_argparser(view, args) @@ -167,7 +170,7 @@ def call_method(client, args, unknown_args, wait_thread): except KeyboardInterrupt: ask = "no" if ask.lower() in ['n', 'no']: - colorPrint.printERROR(_('Manually interrupted')) + Methods().printERROR(_('Manually interrupted')) return None param_object['CheckOnly'] = False