Exemplo n.º 1
0
    def test_walk_list(self):
        # Test gramex.config.walk with lists
        o = yaml.load('''
            - 1
            - 2
            - 3
        ''',
                      Loader=ConfigYAMLLoader)
        result = list(walk(o))
        eq_(result, [(0, 1, [1, 2, 3]), (1, 2, [1, 2, 3]), (2, 3, [1, 2, 3])])

        o = yaml.load('''
            -
                x: 1
            -
                x: 2
            -
                x: 3
        ''',
                      Loader=ConfigYAMLLoader)
        result = list(walk(o))
        eq_([('x', 1), (0, {
            'x': 1
        }), ('x', 2), (1, {
            'x': 2
        }), ('x', 3), (2, {
            'x': 3
        })], [(key, val) for key, val, node in result])
Exemplo n.º 2
0
 def test_walk_dict(self):
     # Test gramex.config.walk with dicts
     o = yaml.load('''
         a:
             b:
                 c: 1
                 d: 2
             e: 3
             f:
                 g:
                     h: 4
                     i: 5
             j: 6
         k: 7
     ''', Loader=ConfigYAMLLoader)
     result = list(walk(o))
     eq_(
         [key for key, val, node in result],
         list('cdbehigfjak'))
     eq_(
         [val for key, val, node in result],
         [o.a.b.c, o.a.b.d, o.a.b, o.a.e, o.a.f.g.h, o.a.f.g.i, o.a.f.g,
          o.a.f, o.a.j, o.a, o.k])
     eq_(
         [node for key, val, node in result],
         [o.a.b, o.a.b, o.a, o.a, o.a.f.g, o.a.f.g, o.a.f,
          o.a, o.a, o, o])
Exemplo n.º 3
0
 def create_mail(data):
     '''
     Return kwargs that can be passed to a mailer.mail
     '''
     mail = {}
     for key in ['bodyfile', 'htmlfile', 'markdownfile']:
         target = key.replace('file', '')
         if key in alert and target not in alert:
             path = _tmpl(alert[key]).generate(**data).decode('utf-8')
             tmpl = gramex.cache.open(path, 'template')
             mail[target] = tmpl.generate(**data).decode('utf-8')
     for key in addr_fields + ['subject', 'body', 'html', 'markdown']:
         if key not in alert:
             continue
         if isinstance(alert[key], list):
             mail[key] = [
                 _tmpl(v).generate(**data).decode('utf-8')
                 for v in alert[key]
             ]
         else:
             mail[key] = _tmpl(alert[key]).generate(**data).decode('utf-8')
     headers = {}
     # user: {id: ...} creates an X-Gramex-User header to mimic the user
     if 'user' in alert:
         user = deepcopy(alert['user'])
         for key, val, node in walk(user):
             node[key] = _tmpl(val).generate(**data).decode('utf-8')
         user = json.dumps(user, ensure_ascii=True, separators=(',', ':'))
         headers['X-Gramex-User'] = tornado.web.create_signed_value(
             info.app.settings['cookie_secret'], 'user', user)
     if 'markdown' in mail:
         mail['html'] = _markdown_convert(mail.pop('markdown'))
     if 'images' in alert:
         mail['images'] = {}
         for cid, val in alert['images'].items():
             urlpath = _tmpl(val).generate(**data).decode('utf-8')
             urldata = urlfetch(urlpath, info=True, headers=headers)
             if urldata['content_type'].startswith('image/'):
                 mail['images'][cid] = urldata['name']
             else:
                 with io.open(urldata['name'], 'rb') as temp_file:
                     bytestoread = 80
                     first_line = temp_file.read(bytestoread)
                 # TODO: let admin know that the image was not processed
                 app_log.error(
                     'alert: %s: %s: %d (%s) not an image: %s\n%r', name,
                     cid, urldata['r'].status_code, urldata['content_type'],
                     urlpath, first_line)
     if 'attachments' in alert:
         mail['attachments'] = [
             urlfetch(_tmpl(v).generate(**data).decode('utf-8'),
                      headers=headers) for v in alert['attachments']
         ]
     return mail
Exemplo n.º 4
0
def badgerfish(content, handler=None, mapping={}, doctype='<!DOCTYPE html>'):
    '''
    A transform that converts string content to YAML, then maps nodes
    using other functions, and renders the output as HTML.

    The specs for this function are in progress.
    '''
    data = yaml.load(content, Loader=AttrDictYAMLLoader)  # nosec
    if handler is not None and hasattr(handler, 'file'):
        load_imports(data, handler.file)
    maps = {
        tag: build_transform(trans, vars={'val': None}, filename='badgerfish')
        for tag, trans in mapping.items()
    }
    for tag, value, node in walk(data):
        if tag in maps:
            node[tag] = yield maps[tag](value)
    raise tornado.gen.Return(
        lxml.html.tostring(xmljson.badgerfish.etree(data)[0],
                           doctype=doctype,
                           encoding='unicode'))
Exemplo n.º 5
0
    def run_alert(callback=None):
        '''
        Runs the configured alert. If a callback is specified, calls the
        callback with all email arguments. Else sends the email.
        '''
        app_log.info('alert: %s running', name)
        data = {'config': alert}
        for key, dataset in datasets.items():
            # Allow raw data in lists as-is. Treat dicts as {url: ...}
            data[key] = dataset if isinstance(
                dataset, list) else gramex.data.filter(**dataset)

        result = condition(**data)
        # Avoiding isinstance(result, pd.DataFrame) to avoid importing pandas
        if type(result).__name__ == 'DataFrame':
            data['data'] = result
        elif isinstance(result, dict):
            data.update(result)
        elif not result:
            app_log.debug('alert: %s stopped. condition = %s', name, result)
            return

        each = [(None, None)]
        if 'each' in alert:
            each_data = data[alert['each']]
            if isinstance(each_data, dict):
                each = list(each_data.items())
            elif isinstance(each_data, list):
                each = list(enumerate(each_data))
            elif hasattr(each_data, 'iterrows'):
                each = list(each_data.iterrows())
            else:
                app_log.error(
                    'alert: %s: each: requires data.%s to be a dict/list/DataFrame',
                    name, alert['each'])
                return

        kwargslist = []
        for index, row in each:
            data['index'], data['row'], data['config'] = index, row, alert

            # Generate email content
            kwargs = {}
            kwargslist.append(kwargs)
            for key in ['bodyfile', 'htmlfile', 'markdownfile']:
                target = key.replace('file', '')
                if key in alert and target not in alert:
                    path = _tmpl(alert[key]).generate(**data).decode('utf-8')
                    tmpl = gramex.cache.open(path, 'template')
                    kwargs[target] = tmpl.generate(**data).decode('utf-8')
            try:
                for key in [
                        'to', 'cc', 'bcc', 'from', 'subject', 'body', 'html',
                        'markdown'
                ]:
                    if key in alert:
                        if isinstance(alert[key], list):
                            kwargs[key] = [
                                _tmpl(val).generate(**data).decode('utf-8')
                                for val in alert[key]
                            ]
                        else:
                            kwargs[key] = _tmpl(
                                alert[key]).generate(**data).decode('utf-8')
            except Exception:
                # If any template raises an exception, log it and continue with next email
                app_log.exception('alert: %s(#%s).%s: Template exception',
                                  name, index, key)
                continue
            headers = {}
            # user: {id: ...} creates an X-Gramex-User header to mimic the user
            if 'user' in alert:
                user = deepcopy(alert['user'])
                for key, val, node in walk(user):
                    node[key] = _tmpl(val).generate(**data).decode('utf-8')
                user = json.dumps(user,
                                  ensure_ascii=True,
                                  separators=(',', ':'))
                headers['X-Gramex-User'] = tornado.web.create_signed_value(
                    info.app.settings['cookie_secret'], 'user', user)
            if 'markdown' in kwargs:
                kwargs['html'] = _markdown_convert(kwargs.pop('markdown'))
            if 'images' in alert:
                kwargs['images'] = {}
                for cid, val in alert['images'].items():
                    urlpath = _tmpl(val).generate(**data).decode('utf-8')
                    urldata = urlfetch(urlpath, info=True, headers=headers)
                    if urldata['content_type'].startswith('image/'):
                        kwargs['images'][cid] = urldata['name']
                    else:
                        with io.open(urldata['name'], 'rb') as temp_file:
                            bytestoread = 80
                            first_line = temp_file.read(bytestoread)
                        app_log.error(
                            'alert: %s: %s: %d (%s) not an image: %s\n%r',
                            name, cid, urldata['r'].status_code,
                            urldata['content_type'], urlpath, first_line)
            if 'attachments' in alert:
                kwargs['attachments'] = [
                    urlfetch(
                        _tmpl(attachment).generate(**data).decode('utf-8'),
                        headers=headers) for attachment in alert['attachments']
                ]
            if callable(callback):
                return callback(**kwargs)
            # Email recipient. TODO: run this in a queue. (Anand)
            mailer.mail(**kwargs)
            # Log the event
            event = {
                'alert':
                name,
                'service':
                service,
                'from':
                mailer.email or '',
                'to':
                '',
                'cc':
                '',
                'bcc':
                '',
                'subject':
                '',
                'datetime':
                datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%SZ")
            }
            event.update({k: v for k, v in kwargs.items() if k in event})
            event['attachments'] = ', '.join(kwargs.get('attachments', []))
            alert_logger.info(event)
        return kwargslist