Index: /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/apv/models/prometheus/__init__.py
===================================================================
--- /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/apv/models/prometheus/__init__.py	(revision 0)
+++ /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/apv/models/prometheus/__init__.py	(working copy)
@@ -0,0 +1 @@
+child_seq = ['BasicSetting', 'Log']
\ No newline at end of file
Index: /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/apv/models/prometheus/basic.py
===================================================================
--- /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/apv/models/prometheus/basic.py	(revision 0)
+++ /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/apv/models/prometheus/basic.py	(working copy)
@@ -0,0 +1,261 @@
+from hive.imports.model import *
+import os
+from datetime import datetime
+from djproject.settings import FILE_UPLOAD_DIR
+from django.utils.translation import ugettext_lazy as _
+__ = _
+
+class BasicSetting(ANModel):
+    get = FieldGroup(writable=False, verbose_name=_('Running Configuration'), level=BASIC, fields={
+        'enable': BooleanField(verbose_name=_('Enable Prometheus'), optional=True),
+        'port': PortField(verbose_name=_('Port Number'), default=9100, scope='1025..65000', optional=True),
+        'enable_https': BooleanField(verbose_name=_('Enable Https'), optional=True),
+        'ttl': Uint8Field(verbose_name='TTL', scope='3..60', unit_name=_('Minutes'), default=5, optional=True),
+    })
+    ssl_cert = FieldGroup(writable=False, verbose_name=_('Certificate'), level=ADVANCED, editable=True, fields={
+        'private_key': CharField(verbose_name=_('Private Key'), optional=True, default=""),
+        'cert_content': CharField(verbose_name=_('Certificate Content'), optional=True, default=""),
+    })
+
+    class Import_Cert(Action):
+        verbose_name = _('Import Certificate')
+        action_name = _('Import')
+        btn_class = 'btn-danger slow-action'
+        process_title = "Importing..."
+        config_change = True
+
+        option_fields = (
+            UnionField(name='using', verbose_name=_('Using'), optional=True, fields={
+                'local': GroupField(verbose_name=_('Local File'),fields={
+                    'key_url': ImportLocalFileField(verbose_name=_('Local File'), button_text=__('Choose Local File'), maxFileSize=5000000),
+                    'crt_url': ImportLocalFileField(verbose_name=_('Local File'), button_text=__('Choose Local File'), maxFileSize=5000000),
+                }),
+                'online': GroupField(verbose_name=_('TFTP/FTP/HTTP'),fields={
+                    'key_url': URLField(verbose_name=_('URL'), pattern='((tftp|ftp|http)://)', pattern_msg='Please specify tftp:// ftp:// or http://'),
+                    'crt_url': URLField(verbose_name=_('URL'), pattern='((tftp|ftp|http)://)', pattern_msg='Please specify tftp:// ftp:// or http://'),
+                }),
+                'manual_input': GroupField(verbose_name=_('Manual Input'),fields={
+                    'key_content': TextField(verbose_name=_('Key Content')),
+                    'crt_content': TextField(verbose_name=_('Cert Content')),
+                }),
+            }),
+        )
+
+    class Clear_Cert(Action):
+        verbose_name = _('Remove Certificate')
+        action_name = _('Remove')
+        btn_class = 'btn-danger slow-action'
+        process_title = "Remove..."
+        config_change = True
+
+    class Meta:
+        profile = True
+        verbose_name = _('Basic Settings')
+
+    class Manager(CLIManager):
+        def _get_query_set(self):
+            self.cli.set_enable()
+            result = {
+                "enable": self._get_enable(),
+                "port": self._get_port(),
+                "enable_https": self._get_enable_https(),
+                "ttl": self._get_ttl(),
+            }
+            self._model._meta.mark_delay_query(result)
+
+            return QuerySet(self._model, [result])
+
+        def _get_enable(self):
+            self.cli.set_enable()
+            cli_res = self.cli.cmd('show prometheus status',
+                                   EasyParser("Prometheus client status: ", ['?status']))
+            if "on" == cli_res[0]['status']:
+                return True
+            return False
+
+        def _get_port(self):
+            self.cli.set_enable()
+            cli_res = self.cli.cmd('show prometheus port',
+                                   EasyParser("Prometheus client port number: ", ['?port']))
+            return cli_res[0]['port']
+
+        def _get_enable_https(self):
+            self.cli.set_enable()
+            cli_res = self.cli.cmd('show prometheus https status',
+                                   EasyParser("Prometheus client https status: ", ['?status']))
+            if "on" == cli_res[0]['status']:
+                return True
+            return False
+
+        def _get_ttl(self):
+            self.cli.set_enable()
+            cli_res = self.cli.cmd('show prometheus token ttl')
+            res_split = cli_res.split(" ") # 5 minute(s)
+            return res_split[0]
+
+        def _update(self, instance):
+            data = instance.get_field_dict()
+            self.cli.set_config()
+            if "enable" in data:
+                enable_system = "on" if data["enable"] else "off"
+                self.cli.cmd('prometheus %s' % enable_system,
+                                    BlankParser(nonblank_exception=CLICmdError, supplement=True,
+                                                ignore_msg=["The Prometheus client service has been stopped.\n"]))
+            else:
+                if "port" in data:
+                    self.cli.cmd('prometheus port %s' % data['port'],
+                                        BlankParser(nonblank_exception=CLICmdError, supplement=True))
+                if "enable_https" in data:
+                    self._update_enable_https(data["enable_https"])
+                if "ttl" in data:
+                    self.cli.cmd('prometheus token ttl %s' % data['ttl'],
+                                        BlankParser(nonblank_exception=CLICmdError, supplement=True))
+            return
+
+        def _update_enable_https(self, value):
+            enable_https = "on" if value else "off"
+            self.cli.set_config()
+            self.cli.cmd('prometheus https %s' % enable_https,
+                                    BlankParser(nonblank_exception=CLICmdError, supplement=True))
+
+        def _get_private_key(self):
+            self.cli.set_enable()
+            cert = self.cli.cmd('show prometheus https ssl')
+            pattern = r"-----BEGIN PRIVATE KEY-----.*?-----END PRIVATE KEY-----"
+            matches = re.findall(pattern, cert, re.DOTALL)
+            if not matches:
+                return ""
+            return matches[0]
+
+        def _get_cert_content(self):
+            self.cli.set_enable()
+            cert = self.cli.cmd('show prometheus https ssl')
+            pattern = r"-----BEGIN CERTIFICATE-----.*?-----END CERTIFICATE-----"
+            matches = re.findall(pattern, cert, re.DOTALL)
+            if not matches:
+                return ""
+            return matches[0]
+
+        def _perform_Import_Cert(self, options):
+            if 'local' in options['using']:
+                self.cli.set_config()
+                result = self.cli.cmd('prometheus https ssl %s %s' % (options['using']['local']['key_url'],
+                                                                        options['using']['local']['crt_url']),
+                                      BlankParser(nonblank_exception=CLICmdError, supplement=True,
+                                                  ignore_msg=["The private key and certificate match.\n"]))
+            elif 'online' in options['using']:
+                self.cli.set_config()
+                result = self.cli.cmd('prometheus https ssl %s %s' % (options['using']['online']['key_url'],
+                                                                      options['using']['online']['crt_url']),
+                                      BlankParser(nonblank_exception=CLICmdError, supplement=True,
+                                                  ignore_msg=["The private key and certificate match.\n"]))
+            elif 'manual_input' in options['using']:
+                self.cli.set_config()
+                key_content = options['using']['manual_input']['key_content']
+                crt_content = options['using']['manual_input']['crt_content']
+                key_file_name = "%s.key" % datetime.now().strftime("%Y%m%d%H%M%S")
+                crt_file_name = "%s.crt" % datetime.now().strftime("%Y%m%d%H%M%S")
+                key_file_path = os.path.join('/tmp', 'webui_upload', key_file_name)
+                crt_file_path = os.path.join('/tmp', 'webui_upload', crt_file_name)
+                if not os.path.exists(FILE_UPLOAD_DIR):
+                    os.makedirs(FILE_UPLOAD_DIR)
+                with open(key_file_path, 'w') as file:
+                    file.write(key_content)
+                with open(crt_file_path, 'w') as file:
+                    file.write(crt_content)
+                result = self.cli.cmd('prometheus https ssl %s %s' % (key_file_path,
+                                                                      crt_file_path),
+                                    BlankParser(nonblank_exception=CLICmdError, supplement=True,
+                                                ignore_msg=["The private key and certificate match.\n"]))
+            return result
+
+        def _perform_Clear_Cert(self, options):
+            self.cli.set_config()
+            self.cli.cmd("no prometheus https ssl",
+                         BlankParser(nonblank_exception=CLICmdError, supplement=True))
+            # clear https enable
+            self._update_enable_https(False)
+            return
+
+class Token(ANModel):
+    default = FieldGroup(editable=False, fields={
+        'id': CharField(verbose_name=_('ID'), optional=True),
+        'username': CharField(verbose_name=_('Username'), optional=True),
+        'token': CharField(verbose_name=_('Token'), primary_key=True),
+        'created': CharField(verbose_name=_('Created Date'), optional=True),
+        'expired': CharField(verbose_name=_('Expired Date'), optional=True),
+        'last_used': CharField(verbose_name=_('Last Used Date'), optional=True),
+        'is_expired': BooleanField(verbose_name=_('Is Expired'), optional=True)
+    })
+
+    class Create(Action):
+        verbose_name = _('Create')
+        action_name = _('Create')
+        config_change = True
+
+    class Meta:
+        verbose_name = _('Token Management')
+
+    class Manager(CLIManager):
+        def _get_query_set(self):
+            self.cli.set_enable()
+            data = self.cli.cmd('show prometheus token all')
+            result = self._get_token_list(data.splitlines())
+            return QuerySet(self._model, result)
+
+        def _check_empty(self, content):
+            result = False
+            match = re.findall(r"\s+(\S+)\s+(\S+)\s+(.*?)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)", content, re.DOTALL)
+            for each in match:
+                # id and username and token is None
+                if "None" == each[0] and "None" == each[1] and "None" == each[2]:
+                    result = True
+                    break
+            return result
+
+        def _filter(self, filter_dict):
+            if "is_expired" not in filter_dict:
+                return self._get_query_set()
+            self.cli.set_enable()
+            cli_command = 'show prometheus token valid'
+            if filter_dict["is_expired"]:
+                cli_command = 'show prometheus token expired'
+            data  = self.cli.cmd(cli_command)
+            result = self._get_token_list(data.splitlines())
+            return QuerySet(self._model, result)
+
+        def _get_token_list(self, content):
+            result = []
+            split_newline = content
+            target_content = "\n".join(split_newline[1:])
+            if (self._check_empty(target_content)):
+                return QuerySet(self._model, result)
+            match = re.findall(r"\s+(\d+)\s+(\w+)\s+(.*?)\s+(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\s+(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\s+(\S+)\s+(\S+)", target_content, re.DOTALL)
+            for each in match:
+                result.append({
+                    'id': each[0],
+                    'username': each[1],
+                    'token': each[2],
+                    'created': each[3],
+                    'expired': each[4],
+                    'last_used': each[5],
+                    'is_expired': True if each[6] == "True" else False
+                })
+            return result
+
+        def _perform_Create(self):
+            self.cli.set_enable()
+            data = self.cli.cmd("prometheus token new")
+            # will return result of token, so data should not be empty
+            if (self._check_empty(data)):
+                return data
+            return
+
+        def _delete(self, pk_list):
+            self.cli.set_config()
+            for each in pk_list:
+                data = self.cli.cmd('no prometheus token %s' % each['token'])
+                # will return result of token, so data should not be empty
+                if (self._check_empty(data)):
+                    return data
+            return
Index: /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/apv/models/prometheus/log.py
===================================================================
--- /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/apv/models/prometheus/log.py	(revision 0)
+++ /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/apv/models/prometheus/log.py	(working copy)
@@ -0,0 +1,20 @@
+from hive.imports.model import *
+from django.utils.translation import ugettext_lazy as _
+__ = _
+
+class Log(ANModel):
+    get = FieldGroup(editable=False, verbose_name=_('Prometheus Log'),
+        fields={
+            'content': CLITextField(verbose_name=_('Prometheus Log')),
+        })     
+
+    class Meta:
+        profile = True
+        verbose_name = _('Prometheus Log')
+        show_im_export_button = False
+
+    class Manager(CLIManager):
+        def _get_query_set(self):
+            self.cli.set_enable(force=True)
+            cli_res = self.cli.cmd('show prometheus log 200')
+            return QuerySet(self._model, [{'content':cli_res}])
Index: /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/apv/router.py
===================================================================
--- /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/apv/router.py	(revision 38852)
+++ /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/apv/router.py	(working copy)
@@ -14,6 +14,7 @@
 import geoip2.database as database
 from apv.company import *
 import re
+import time
 
 lruCache = LRUCacheDict(max_size=10000)
 reader = database.Reader('/ca/webui/conf/GeoLite2-City.mmdb')
@@ -721,4 +722,17 @@
         "device_unhealthy_count" : device_unhealthy_count,
     }))
 
+def prometheus_log_download(request):
+    lines = 0
+    if "lines" in request.GET and request.GET["lines"]:
+        lines = request.GET["lines"]
+    sess = get_current_session()
+    sess.cli.set_enable()
+    logs = sess.cli.cmd('show prometheus log %s' % lines)
+    cur_time = time.strftime("%Y%m%d%H%M%S", time.localtime())
+    file_name = "%s_%s.%s" % ("Prometheus_log", cur_time, 'txt')
+    response = HttpResponse(logs)
+    response['Content-Type'] = 'text/plain; charset=utf-8'
+    response['Content-Disposition'] = 'attachment; filename=%s' % file_name
+    return response
 
Index: /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/apv/urls.py
===================================================================
--- /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/apv/urls.py	(revision 38852)
+++ /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/apv/urls.py	(working copy)
@@ -47,4 +47,5 @@
     url(r'^generate_report$', generateReport),
     url(r'^%s/get_listener_list$' % PRODUCT_KEYWORD, get_listener_list),
     url(r'^%s/get_sslo_status$' % PRODUCT_KEYWORD, get_sslo_status),
+    url(r'^%s/prometheus/Log/download' % PRODUCT_KEYWORD, prometheus_log_download),
 )
Index: /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/hive/model/ajax.py
===================================================================
--- /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/hive/model/ajax.py	(revision 38852)
+++ /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/hive/model/ajax.py	(working copy)
@@ -1293,7 +1293,18 @@
         except Exception as e:
             data = self.object.get_rest_field_dict()
         return json.dumps(data)
-    
+
+    def field_group(self, **kwargs):
+        data = {}
+        try:
+            group_name = kwargs['name']
+        except KeyError:
+            raise Http404('no group name provided')
+        for key in self.model._meta.field_groups[group_name].fields:
+            if key.attname not in data:
+                data[key.attname] = self.manager.get_field(self.object.pk_dict(), key.attname)
+        return json.dumps(data)
+
     def export(self, **kwargs):
         try:
             field_name = kwargs['field']
