Hmm, I should have added a type field, but would we require a version number as well?
On 04/11/2017 08:34 PM, Goldwyn Rodrigues wrote: > From: Goldwyn Rodrigues <[email protected]> > > This adds JSON support for tools in order to be able to talk to > other utilities such as Yast. > > The json is one per line, in order to differentiate between multiple > records. This is based on work presented by Christian Boltz some time > back. > > Signed-off-by: Goldwyn Rodrigues <[email protected]> > --- > utils/aa-genprof | 4 ++ > utils/aa-logprof | 5 ++ > utils/apparmor/ui.py | 192 > ++++++++++++++++++++++++++++++--------------------- > 3 files changed, 124 insertions(+), 77 deletions(-) > > diff --git a/utils/aa-genprof b/utils/aa-genprof > index e2e6544..9a8783d 100755 > --- a/utils/aa-genprof > +++ b/utils/aa-genprof > @@ -61,8 +61,12 @@ parser = argparse.ArgumentParser(description=_('Generate > profile for the given p > parser.add_argument('-d', '--dir', type=str, help=_('path to profiles')) > parser.add_argument('-f', '--file', type=str, help=_('path to logfile')) > parser.add_argument('program', type=str, help=_('name of program to > profile')) > +parser.add_argument('-j', '--json', action="store_true", help=_('provide > output in json format')) > args = parser.parse_args() > > +if args.json: > + aaui.set_json_mode() > + > profiling = args.program > profiledir = args.dir > > diff --git a/utils/aa-logprof b/utils/aa-logprof > index c05cbef..a00cfea 100755 > --- a/utils/aa-logprof > +++ b/utils/aa-logprof > @@ -16,6 +16,7 @@ import argparse > import os > > import apparmor.aa as apparmor > +import apparmor.ui as aaui > > # setup exception handling > from apparmor.fail import enable_aa_exception_handler > @@ -29,8 +30,12 @@ parser = argparse.ArgumentParser(description=_('Process > log entries to generate > parser.add_argument('-d', '--dir', type=str, help=_('path to profiles')) > parser.add_argument('-f', '--file', type=str, help=_('path to logfile')) > parser.add_argument('-m', '--mark', type=str, help=_('mark in the log to > start processing after')) > +parser.add_argument('-j', '--json', action='store_true', help=_('provide the > output in json format')) > args = parser.parse_args() > > +if args.json: > + aaui.set_json_mode() > + > profiledir = args.dir > logmark = args.mark or '' > > diff --git a/utils/apparmor/ui.py b/utils/apparmor/ui.py > index f25fff3..064cf74 100644 > --- a/utils/apparmor/ui.py > +++ b/utils/apparmor/ui.py > @@ -1,5 +1,7 @@ > # ---------------------------------------------------------------------- > # Copyright (C) 2013 Kshitij Gupta <[email protected]> > +# Copyright (C) 2017 Christian Boltz <[email protected]> > +# Copyright (C) 2017 SUSE Linux > # > # This program is free software; you can redistribute it and/or > # modify it under the terms of version 2 of the GNU General Public > @@ -11,6 +13,8 @@ > # GNU General Public License for more details. > # > # ---------------------------------------------------------------------- > + > +import json > import sys > import re > import readline > @@ -24,14 +28,20 @@ _ = init_translation() > # Set up UI logger for separate messages from UI module > debug_logger = DebugLogger('UI') > > -# The operating mode: yast or text, text by default > -UI_mode = 'text' > - > # If Python3, wrap input in raw_input so make check passes > if not 'raw_input' in dir(__builtins__): raw_input = input > > ARROWS = {'A': 'UP', 'B': 'DOWN', 'C': 'RIGHT', 'D': 'LEFT'} > > +UI_mode = 'text' > + > +def set_json_mode(): > + global UI_mode > + UI_mode = 'json' > + > +def write_json(jsonout): > + sys.stdout.write(json.dumps(jsonout, sort_keys=False, separators=(',', > ': ')) + '\n') > + > def getkey(): > key = readkey() > if key == '\x1B': > @@ -44,12 +54,18 @@ def getkey(): > > def UI_Info(text): > debug_logger.info(text) > - if UI_mode == 'text': > + if UI_mode == 'json': > + jsonout = {'info': text} > + write_json(jsonout) > + else: # text mode > sys.stdout.write(text + '\n') > > def UI_Important(text): > debug_logger.debug(text) > - if UI_mode == 'text': > + if UI_mode == 'json': > + jsonout = {'important': text} > + write_json(jsonout) > + else: # text mode: > sys.stdout.write('\n' + text + '\n') > > def get_translated_hotkey(translated, cmsg=''): > @@ -67,53 +83,57 @@ def get_translated_hotkey(translated, cmsg=''): > def UI_YesNo(text, default): > debug_logger.debug('UI_YesNo: %s: %s %s' % (UI_mode, text, default)) > default = default.lower() > - ans = None > - if UI_mode == 'text': > - yes = CMDS['CMD_YES'] > - no = CMDS['CMD_NO'] > - yeskey = get_translated_hotkey(yes).lower() > - nokey = get_translated_hotkey(no).lower() > - ans = 'XXXINVALIDXXX' > - while ans not in ['y', 'n']: > + yes = CMDS['CMD_YES'] > + no = CMDS['CMD_NO'] > + yeskey = get_translated_hotkey(yes).lower() > + nokey = get_translated_hotkey(no).lower() > + ans = 'XXXINVALIDXXX' > + while ans not in ['y', 'n']: > + if UI_mode == 'json': > + jsonout = {'dialog': 'yesno', 'text': text, 'default': default} > + write_json(jsonout) > + else: # text mode: > sys.stdout.write('\n' + text + '\n') > if default == 'y': > sys.stdout.write('\n[%s] / %s\n' % (yes, no)) > else: > sys.stdout.write('\n%s / [%s]\n' % (yes, no)) > - ans = getkey() > - if ans: > - # Get back to english from localised answer > - ans = ans.lower() > - if ans == yeskey: > - ans = 'y' > - elif ans == nokey: > - ans = 'n' > - elif ans == 'left': > - default = 'y' > - elif ans == 'right': > - default = 'n' > - else: > - ans = 'XXXINVALIDXXX' > - continue # If user presses any other button ask again > + ans = getkey() > + if ans: > + # Get back to english from localised answer > + ans = ans.lower() > + if ans == yeskey: > + ans = 'y' > + elif ans == nokey: > + ans = 'n' > + elif ans == 'left': > + default = 'y' > + elif ans == 'right': > + default = 'n' > else: > - ans = default > + ans = 'XXXINVALIDXXX' > + continue # If user presses any other button ask again > + else: > + ans = default > return ans > > def UI_YesNoCancel(text, default): > debug_logger.debug('UI_YesNoCancel: %s: %s %s' % (UI_mode, text, > default)) > default = default.lower() > - ans = None > - if UI_mode == 'text': > - yes = CMDS['CMD_YES'] > - no = CMDS['CMD_NO'] > - cancel = CMDS['CMD_CANCEL'] > - > - yeskey = get_translated_hotkey(yes).lower() > - nokey = get_translated_hotkey(no).lower() > - cancelkey = get_translated_hotkey(cancel).lower() > - > - ans = 'XXXINVALIDXXX' > - while ans not in ['c', 'n', 'y']: > + yes = CMDS['CMD_YES'] > + no = CMDS['CMD_NO'] > + cancel = CMDS['CMD_CANCEL'] > + > + yeskey = get_translated_hotkey(yes).lower() > + nokey = get_translated_hotkey(no).lower() > + cancelkey = get_translated_hotkey(cancel).lower() > + > + ans = 'XXXINVALIDXXX' > + while ans not in ['c', 'n', 'y']: > + if UI_mode == 'json': > + jsonout = {'dialog': 'yesnocancel', 'text': text, 'default': > default} > + write_json(jsonout) > + else: # text mode: > sys.stdout.write('\n' + text + '\n') > if default == 'y': > sys.stdout.write('\n[%s] / %s / %s\n' % (yes, no, cancel)) > @@ -121,55 +141,60 @@ def UI_YesNoCancel(text, default): > sys.stdout.write('\n%s / [%s] / %s\n' % (yes, no, cancel)) > else: > sys.stdout.write('\n%s / %s / [%s]\n' % (yes, no, cancel)) > - ans = getkey() > - if ans: > - # Get back to english from localised answer > - ans = ans.lower() > - if ans == yeskey: > - ans = 'y' > - elif ans == nokey: > - ans = 'n' > - elif ans == cancelkey: > - ans = 'c' > - elif ans == 'left': > - if default == 'n': > - default = 'y' > - elif default == 'c': > - default = 'n' > - elif ans == 'right': > - if default == 'y': > - default = 'n' > - elif default == 'n': > - default = 'c' > - else: > - ans = default > + ans = getkey() > + if ans: > + # Get back to english from localised answer > + ans = ans.lower() > + if ans == yeskey: > + ans = 'y' > + elif ans == nokey: > + ans = 'n' > + elif ans == cancelkey: > + ans = 'c' > + elif ans == 'left': > + if default == 'n': > + default = 'y' > + elif default == 'c': > + default = 'n' > + elif ans == 'right': > + if default == 'y': > + default = 'n' > + elif default == 'n': > + default = 'c' > + else: > + ans = default > return ans > > def UI_GetString(text, default): > debug_logger.debug('UI_GetString: %s: %s %s' % (UI_mode, text, default)) > string = default > - if UI_mode == 'text': > + if UI_mode == 'json': > + jsonout = {'dialog': 'getstring', 'text': text, 'default': default} > + write_json(jsonout) > + else: # text mode: > readline.set_startup_hook(lambda: readline.insert_text(default)) > - try: > - string = raw_input('\n' + text) > - except EOFError: > - string = '' > - finally: > - readline.set_startup_hook() > + try: > + string = raw_input('\n' + text) > + except EOFError: > + string = '' > + finally: > + readline.set_startup_hook() > return string.strip() > > def UI_GetFile(file): > debug_logger.debug('UI_GetFile: %s' % UI_mode) > filename = None > - if UI_mode == 'text': > + if UI_mode == 'json': > + jsonout = {'dialog': 'getfile', 'text': file['description']} > + write_json(jsonout) > + else: # text mode: > sys.stdout.write(file['description'] + '\n') > - filename = sys.stdin.read() > + filename = sys.stdin.read() > return filename > > def UI_BusyStart(message): > debug_logger.debug('UI_BusyStart: %s' % UI_mode) > - if UI_mode == 'text': > - UI_Info(message) > + UI_Info(message) > > def UI_BusyStop(): > debug_logger.debug('UI_BusyStop: %s' % UI_mode) > @@ -254,8 +279,7 @@ class PromptQuestion(object): > def promptUser(self, params=''): > cmd = None > arg = None > - if UI_mode == 'text': > - cmd, arg = self.Text_PromptUser() > + cmd, arg = self.Text_PromptUser() > if cmd == 'CMD_ABORT': > confirm_and_abort() > cmd = 'XXXINVALIDXXX' > @@ -324,6 +348,16 @@ class PromptQuestion(object): > function_regexp += ')$' > > ans = 'XXXINVALIDXXX' > + hdict = dict() > + jsonprompt = { > + 'title': title, > + 'headers': hdict, > + 'explanation': explanation, > + 'options': options, > + 'menu_items': menu_items, > + 'default_key': default_key, > + } > + > while not re.search(function_regexp, ans, flags=re.IGNORECASE): > > prompt = '\n' > @@ -335,6 +369,7 @@ class PromptQuestion(object): > while header_copy: > header = header_copy.pop(0) > value = header_copy.pop(0) > + hdict[header] = value > prompt += formatstr % (header + ':', value) > prompt += '\n' > > @@ -352,7 +387,10 @@ class PromptQuestion(object): > > prompt += ' / '.join(menu_items) > > - sys.stdout.write(prompt + '\n') > + if UI_mode == 'json': > + write_json(jsonprompt) > + else: # text mode: > + sys.stdout.write(prompt + '\n') > > ans = getkey().lower() > > -- Goldwyn -- AppArmor mailing list [email protected] Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/apparmor
