URL: https://github.com/freeipa/freeipa/pull/174
Author: shanyin
 Title: #174: add log module
Action: opened

PR body:
"""
add log module on the ipa-4-3 branch, the function of log module is to record 
any of our operation.
"""

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/174/head:pr174
git checkout pr174
From 74c4ef4331482c8763dcd9b86e9209cd2054686b Mon Sep 17 00:00:00 2001
From: shanyin <zheng...@kylinos.cn>
Date: Thu, 20 Oct 2016 14:56:11 +0800
Subject: [PATCH] add log module

---
 install/ui/src/freeipa/app.js                  |   1 +
 install/ui/src/freeipa/facet.js                |   9 +-
 install/ui/src/freeipa/log.js                  |  79 +++++++++
 install/ui/src/freeipa/navigation/menu_spec.js |   7 +
 ipalib/errors.py                               |  16 ++
 ipalib/plugins/config.py                       |   3 +-
 ipalib/plugins/log.py                          | 227 +++++++++++++++++++++++++
 ipaserver/install/cainstance.py                |   5 +
 ipaserver/rpcserver.py                         |  48 ++++++
 9 files changed, 392 insertions(+), 3 deletions(-)
 create mode 100644 install/ui/src/freeipa/log.js
 create mode 100644 ipalib/plugins/log.py

diff --git a/install/ui/src/freeipa/app.js b/install/ui/src/freeipa/app.js
index daf17b7..4a132ee 100644
--- a/install/ui/src/freeipa/app.js
+++ b/install/ui/src/freeipa/app.js
@@ -52,6 +52,7 @@ define([
     './trust',
     './topology',
     './user',
+    './log',
     './stageuser',
     'dojo/domReady!'
 ],function(app_container) {
diff --git a/install/ui/src/freeipa/facet.js b/install/ui/src/freeipa/facet.js
index 9d71487..91a1474 100644
--- a/install/ui/src/freeipa/facet.js
+++ b/install/ui/src/freeipa/facet.js
@@ -1105,7 +1105,8 @@ exp.facet = IPA.facet = function(spec, no_init) {
             name: 'facet_actions',
             'class': 'dropdown facet-actions',
             right_aligned: true,
-            toggle_text: 'Actions ',
+            //toggle_text: 'Actions ',
+			toggle_text: text.get('@i18n:actions.title'),
             toggle_class: 'btn btn-default',
             toggle_icon: 'fa fa-angle-down'
         });
@@ -2086,7 +2087,11 @@ exp.table_facet = IPA.table_facet = function(spec, no_init) {
 
         // sort map based on primary keys
         if (that.sort_enabled) {
-            records_map = records_map.sort();
+			//records_map = records_map.sort();
+            if (that.managed_entity.metadata.name == 'log')
+                ;
+            else
+                records_map = records_map.sort();
         }
 
         // trim map leaving the entries visible in the current page only
diff --git a/install/ui/src/freeipa/log.js b/install/ui/src/freeipa/log.js
new file mode 100644
index 0000000..5344cb5
--- /dev/null
+++ b/install/ui/src/freeipa/log.js
@@ -0,0 +1,79 @@
+/*  Authors:
+ *    Zheng Lei <zheng...@kylinos.cn>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * 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/>.
+ */
+
+define([
+        './builder',
+        './ipa',
+        './jquery',
+        './phases',
+        './reg',
+        './rpc',
+        './text',
+        './dialogs/password',
+        './details',
+        './search',
+        './association',
+        './entity',
+        './certificate'],
+    function(builder, IPA, $, phases, reg, rpc, text, password_dialog) {
+
+/**
+ * Log module
+ * @class log
+ * @alternateClassName IPA.log
+ * @singleton
+ */
+var exp = IPA.log = {};
+
+var make_spec = function() {
+return {
+    name: 'log',
+    label: '日志',
+    facets: [
+        {
+    	    label: '日志',
+            $type: 'search',
+            // setting no_update value(ture) to control add and remove buttons invisible
+            no_update: true,
+            // setting selectable value(false) to control checkbox invisible
+            selectable: false,
+            columns: [
+                { name: 'logtime', label: "时间" },
+                { name: 'loglevel', label: "级别" },
+                { name: 'loguser', label: "用户" },
+                { name: 'logip', label: "远程地址" },
+                { name: 'logstatus', label: "状态" },
+                { name: 'logmessage', label: "信息" }
+            ],
+        },
+    ],
+}
+};
+
+exp.entity_spec = make_spec();
+exp.register = function() {
+    var e = reg.entity;
+    e.register({type: 'log', spec: exp.entity_spec});
+};
+
+phases.on('registration', exp.register);
+
+return exp;
+});
diff --git a/install/ui/src/freeipa/navigation/menu_spec.js b/install/ui/src/freeipa/navigation/menu_spec.js
index fb64cca..7dc21f2 100644
--- a/install/ui/src/freeipa/navigation/menu_spec.js
+++ b/install/ui/src/freeipa/navigation/menu_spec.js
@@ -239,6 +239,13 @@ var nav = {};
                 },
                 { entity: 'config' }
             ]
+        },
+        {
+            name: 'log',
+            label: 'IPA日志',
+            children: [
+                { entity: 'log' }
+            ]
         }
     ]
 };
diff --git a/ipalib/errors.py b/ipalib/errors.py
index 6d1b328..bc94af5 100644
--- a/ipalib/errors.py
+++ b/ipalib/errors.py
@@ -1752,6 +1752,22 @@ class CertificateInvalidError(CertificateError):
     errno = 4310
     format = _('%(name)s certificate is not valid')
 
+# add log primary key error judge
+class NotInt(ExecutionError):
+    """
+    **4311** Raised when an pkey is not int.
+ 
+    For example:
+ 
+    >>> raise NotInt(reason='not logline')
+    Traceback (most recent call last):
+      ...
+    NotInt: not logline
+ 
+    """
+
+    errno = 4311
+    format = _('%(reason)s')
 
 class DNSError(ExecutionError):
     """
diff --git a/ipalib/plugins/config.py b/ipalib/plugins/config.py
index 0f4d289..aaf70ec 100644
--- a/ipalib/plugins/config.py
+++ b/ipalib/plugins/config.py
@@ -164,7 +164,8 @@ class config(LDAPObject):
         ),
         IA5Str('ipagroupsearchfields',
             cli_name='groupsearch',
-            label='Group search fields',
+            #label='Group search fields',
+            label=_('Group search fields'),
             doc=_('A comma-separated list of fields to search in when searching for groups'),
         ),
         Bool('ipamigrationenabled',
diff --git a/ipalib/plugins/log.py b/ipalib/plugins/log.py
new file mode 100644
index 0000000..c5c5ea1
--- /dev/null
+++ b/ipalib/plugins/log.py
@@ -0,0 +1,227 @@
+from ipalib import api, Object, Str, _, ngettext, Int, Flag, crud, errors, output, create_api
+from ipalib.parameters import Any
+from ipalib.output import Output
+from ipalib.plugins.baseldap import *
+from ipalib.plugins import baseldap
+from ipalib.plugable import Registry
+from ipalib.cli import to_cli
+from ipapython.version import API_VERSION
+from ipalib.capabilities import client_has_capability
+
+register = Registry()
+
+def gen_pkey_only_option(cli_name):
+    return Flag('pkey_only?',
+                label=_('Primary key only'),
+                doc=_('Results should contain primary key attribute only ("%s")') \
+                    % to_cli(cli_name),)
+
+def pkey_to_value(key, options):
+    version = options.get('version', API_VERSION)
+    if client_has_capability(version, 'primary_key_types'):
+        return key
+    return pkey_to_unicode(key)
+
+@register()
+class log(LDAPObject):
+
+    default_attributes = [
+        'logtime', 'loglevel', 'loguser', 'logip', 'logstatus', 'logmessage'
+    ]
+
+    search_display_attributes = [
+        'logtime', 'loglevel', 'loguser', 'logip', 'logstatus', 'logmessage',
+    ]
+
+    takes_params = (
+        Str('logline', primary_key=True),
+        Str('logtime', cli_name="time", label='time'),
+        Str('loglevel', cli_name="level", label='level'),
+        Str('loguser', cli_name="user", label='user'),
+        Str('logip', cli_name="ip", label='ip'),
+        Str('logstatus', cli_name="status", label='status'),
+        Str('logmessage', cli_name="message", label='message'),
+    )
+
+    parent_object = ''
+    object_not_found_msg = _('%(pkey)s: not found')
+
+    def get_ancestor_primary_keys(self):
+        if self.parent_object:
+            parent_obj = self.api.Object[self.parent_object]
+            for key in parent_obj.get_ancestor_primary_keys():
+                yield key
+            if parent_obj.primary_key:
+                pkey = parent_obj.primary_key
+                yield pkey.clone_rename(
+                    parent_obj.name + pkey.name, required=True, query=True,
+                    cli_name=parent_obj.name, label=pkey.label
+                )
+
+    def handle_not_found(self, *keys):
+        pkey = ''
+        if self.primary_key:
+            pkey = keys[-1]
+        raise errors.NotFound(
+            reason=self.object_not_found_msg % {
+                'pkey': pkey,
+            }
+        )
+
+@register()
+class log_show(crud.Retrieve):
+    __doc__ = _('Display information about a log.')
+
+    takes_options = (
+        Flag('rights',
+            label=_('Rights'),
+            doc=_('Display the access rights of this entry (requires --all). See ipa man page for details.'),
+        ),
+    )
+
+    def get_args(self):
+        for key in self.obj.get_ancestor_primary_keys():
+            yield key
+        for arg in super(crud.Retrieve, self).get_args():
+            yield arg
+
+    # list of attributes we want exported to JSON
+    json_friendly_attributes = (
+        'takes_args',
+    )
+
+    def execute(self, *keys, **options):
+        flag=keys[-1]
+        entry_list=[]
+
+        if options.get('all', False):
+            attrs_list = ['*'] + self.obj.default_attributes
+        else:
+            attrs_list = set(self.obj.default_attributes)
+            if options.get('no_members', False):
+                attrs_list.difference_update(self.obj.attribute_members)
+            attrs_list = list(attrs_list)
+
+        linenumber = 0
+        for line in open("/var/log/ipa/ipa.log"):
+            line_ignore_enter = line.strip('\n')
+            line_list = line_ignore_enter.split('\t')
+            (logtime, loglevel, loguser, logip, logstatus, logmessage) = line_list
+            entry_attrs=dict()
+            linenumber += 1
+            entry_attrs[u'logline'] = unicode(linenumber)
+            i = 0
+            for param in self.obj.default_attributes:
+                entry_attrs[unicode(param)] = unicode(line_list[i]).split("\n", 1)
+                i += 1
+            entry_list.append(entry_attrs)
+
+        try:
+            int(flag)
+        except(ValueError):
+            raise errors.NotInt(
+                reason=_('%(pkey)s: not logline') % {
+                    'pkey': flag,
+                }
+            )
+
+        results = dict()
+        for entry in entry_list:
+            if flag == entry['logline']:
+                results = entry
+                break
+        if self.obj.primary_key:
+            pkey = keys[-1]
+        else:
+            pkey = None
+        if not results:
+            self.obj.handle_not_found(*keys)
+
+        return dict(result=results, value=pkey_to_value(pkey, options))
+
+@register()
+class log_find(crud.Search):
+    __doc__ = _('search for log.')
+    
+    takes_options = (
+        Int('timelimit?',
+            label=_('Time Limit'),
+            doc=_('Time limit of search in seconds'),
+            flags=['no_display'],
+            minvalue=0,
+            autofill=False,
+        ),
+        Int('sizelimit?',
+            label=_('Size Limit'),
+            doc=_('Maximum number of entries returned'),
+            flags=['no_display'],
+            minvalue=0,
+            autofill=False,
+        ),
+    )
+
+    member_attributes = []
+
+    def get_member_options(self, attr):
+        for ldap_obj_name in self.obj.attribute_members[attr]:
+            ldap_obj = self.api.Object[ldap_obj_name]
+            relationship = self.obj.relationships.get(
+                attr, ['member', '', 'no_']
+            )
+            doc = self.member_param_incl_doc % dict(
+                searched_object=self.obj.object_name_plural,
+                relationship=relationship[0].lower(),
+                ldap_object=ldap_obj.object_name_plural
+            )
+            name = '%s%s' % (relationship[1], to_cli(ldap_obj_name))
+            yield Str(
+                '%s*' % name, cli_name='%ss' % name, doc=doc,
+                label=ldap_obj.object_name, csv=True
+            )
+            doc = self.member_param_excl_doc % dict(
+                searched_object=self.obj.object_name_plural,
+                relationship=relationship[0].lower(),
+                ldap_object=ldap_obj.object_name_plural
+            )
+            name = '%s%s' % (relationship[2], to_cli(ldap_obj_name))
+            yield Str(
+                '%s*' % name, cli_name='%ss' % name, doc=doc,
+                label=ldap_obj.object_name, csv=True
+            )
+
+    def get_options(self):
+        for option in super(crud.Search, self).get_options():
+            yield option
+        if self.obj.primary_key and \
+                'no_output' not in self.obj.primary_key.flags:
+            yield gen_pkey_only_option(self.obj.primary_key.cli_name)
+        for attr in self.member_attributes:
+            for option in self.get_member_options(attr):
+                yield option
+
+    def execute(self, *args, **options):
+        flag = args[-1]
+        entries=[]
+        linenumber = 0
+        truncated = False
+
+        for line in open("/var/log/ipa/ipa.log"):
+            line_ignore_enter = line.strip('\n')
+            line_list = line_ignore_enter.split('\t')
+            (logtime, loglevel, loguser, logip, logstatus, logmessage) = line_list
+
+            entry_dict=dict()
+            linenumber += 1
+            entry_dict[u'logline'] = unicode(linenumber)
+            i = 0
+            for params in self.obj.default_attributes:
+                entry_dict[unicode(params)] = unicode(line_list[i]).split("\n", 1)
+                i += 1
+            if flag:
+                if flag in line:
+                    entries.append(entry_dict)
+                else:
+                    entries = entries
+            else:
+                entries.append(entry_dict)
+        return dict(result=entries[::-1], count=len(entries), truncated=truncated)
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index aba5f8c..c6b57d0 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -573,6 +573,11 @@ def __spawn_instance(self):
         with open(cfg_file, "wb") as f:
             config.write(f)
 
+        # Create parent directory for pki-tomcatd service file
+        PKI_SERVICE_LOCATION="/etc/systemd/system/pki-tomcatd.target.wants"
+        if not os.path.exists(PKI_SERVICE_LOCATION):
+            os.mkdir(PKI_SERVICE_LOCATION)
+
         self.backup_state('installed', True)
         try:
             DogtagInstance.spawn_instance(self, cfg_file)
diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py
index 64620b4..a2f96a4 100644
--- a/ipaserver/rpcserver.py
+++ b/ipaserver/rpcserver.py
@@ -31,6 +31,7 @@
 import traceback
 import gssapi
 import time
+import logging
 
 import ldap.controls
 from pyasn1.type import univ, namedtype
@@ -304,6 +305,10 @@ class WSGIExecutioner(Executioner):
 
     _system_commands = {}
 
+    # add kydc log
+    LOGGING_FORMAT='\t'.join(['%(asctime)s', '%(levelname)s', '%(message)s',])
+    logging.basicConfig(filename='/var/log/ipa/ipa.log', level=logging.INFO, format=LOGGING_FORMAT, datefmt='%Y-%m-%d %H:%M:%S')
+
     def _on_finalize(self):
         self.url = self.env.mount_ipa + self.key
         super(WSGIExecutioner, self)._on_finalize()
@@ -374,6 +379,43 @@ def wsgi_execute(self, environ):
                 result_string = type(e).__name__
             else:
                 result_string = 'SUCCESS'
+            # handle batch
+            if name == 'batch':
+                for param in args:
+                    result_param = dict()
+                    method = None
+                    if 'method' not in param:
+                        raise errors.RequirementError(method='method')
+                    if 'params' not in param:
+                        raise errors.RequirementError(method='params')
+                    method = param['method']
+                    if method not in self.Command:
+                        raise errors.CommandError(method=method)
+                    if method == 'log_show' or method == 'log_find':
+                        continue
+                    a, kw = param['params']
+                    newkw = dict((str(k), v) for k, v in kw.iteritems())
+                    result_param = self.Command[method].args_options_2_params(*a, **newkw)
+                    newkw.setdefault('version', options['version'])
+
+                    logging.info('%s\t%s\t%s\t%s(%s)',
+                              principal.split('@')[0],
+                              environ.get('REMOTE_ADDR'),
+                              result_string,
+                              method,
+                              #', '.join(result_param))
+                              ', '.join(self.Command[method]._repr_iter(**result_param)))
+            else:
+                if name == 'log_show' or name == 'log_find':
+                    pass
+                else:
+                    logging.info('%s\t%s\t%s\t%s(%s)',
+                          principal.split('@')[0],
+                          environ.get('REMOTE_ADDR'),
+                          result_string,
+                          name,
+                          ', '.join(self.Command[name]._repr_iter(**params)))
+
             self.info('[%s] %s: %s(%s): %s',
                       type(self).__name__,
                       principal,
@@ -946,9 +988,15 @@ def __call__(self, environ, start_response):
         try:
             self.kinit(user, self.api.env.realm, password, ipa_ccache_name)
         except PasswordExpired as e:
+            # add log information
+            logging.info("%s\t%s\t%s\t%s", user, environ.get("REMOTE_ADDR"), 'FAILURE', 'password-expired')
             return self.unauthorized(environ, start_response, str(e), 'password-expired')
         except InvalidSessionPassword as e:
+            logging.info("%s\t%s\t%s\t%s", user, environ.get("REMOTE_ADDR"), 'FAILURE', 'invalid-password')
             return self.unauthorized(environ, start_response, str(e), 'invalid-password')
+        else:
+            self.info("%s logined from %s\n", user, environ.get("REMOTE_ADDR"))
+            logging.info("%s\t%s\t%s\t%s", user, environ.get("REMOTE_ADDR"), 'SUCCESS', 'session_login()')
 
         return self.finalize_kerberos_acquisition('login_password', ipa_ccache_name, environ, start_response)
 
-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to