import json
import yaml

'''
将promtheus/vmalert的rule转换为n9e中的rule
支持k8s的rule configmap
'''

rule_file = 'rules.yaml'


def convert_interval(interval):
    if interval.endswith('s') or interval.endswith('S'):
        return int(interval[:-1])
    if interval.endswith('m') or interval.endswith('M'):
        return int(interval[:-1]) * 60
    if interval.endswith('h') or interval.endswith('H'):
        return int(interval[:-1]) * 60 * 60
    if interval.endswith('d') or interval.endswith('D'):
        return int(interval[:-1]) * 60 * 60 * 24
    return int(interval)


def convert_alert(rule, interval):
    name = rule['alert']
    prom_ql = rule['expr']
    if 'for' in rule:
        prom_for_duration = convert_interval(rule['for'])
    else:
        prom_for_duration = 0

    prom_eval_interval = convert_interval(interval)
    note = ''
    if 'annotations' in rule:
        for v in rule['annotations'].values():
            note = v
            break
    
    annotations = {}
    if 'annotations' in rule:
        for k, v in rule['annotations'].items():
            annotations[k] = v
           

    append_tags = []
    severity = 2
    if 'labels' in rule:
        for k, v in rule['labels'].items():
            if k != 'severity':
                append_tags.append('{}={}'.format(k, v))
                continue
            if v == 'critical':
                severity = 1
            elif v == 'info':
                severity = 3
            # elif v == 'warning':
            #     severity = 2

 
    n9e_alert_rule = {
        "name": name,
        "note": note,
        "severity": severity,
        "disabled": 0,
        "prom_for_duration": prom_for_duration,
        "prom_ql": prom_ql,
        "prom_eval_interval": prom_eval_interval,
        "enable_stime": "00:00",
        "enable_etime": "23:59",
        "enable_days_of_week": [
            "1",
            "2",
            "3",
            "4",
            "5",
            "6",
            "0"
        ],
        "enable_in_bg": 0,
        "notify_recovered": 1,
        "notify_channels": [],
        "notify_repeat_step": 60,
        "recover_duration": 0,
        "callbacks": [],
        "runbook_url": "",
        "append_tags": append_tags,
        "annotations":annotations
    }
    return n9e_alert_rule


def convert_record(rule, interval):
    name = rule['record']
    prom_ql = rule['expr']
    prom_eval_interval = convert_interval(interval)
    note = ''
    append_tags = []
    if 'labels' in rule:
        for k, v in rule['labels'].items():
            append_tags.append('{}={}'.format(k, v))

    n9e_record_rule = {
        "name": name,
        "note": note,
        "disabled": 0,
        "prom_ql": prom_ql,
        "prom_eval_interval": prom_eval_interval,
        "append_tags": append_tags
    }
    return n9e_record_rule


'''
example of rule group file
---
groups:
- name: example
  rules:
  - alert: HighRequestLatency
    expr: job:request_latency_seconds:mean5m{job="myjob"} > 0.5
    for: 10m
    labels:
      severity: page
    annotations:
      summary: High request latency
'''
def deal_group(group):
    """
    parse single prometheus/vmalert rule group
    """
    alert_rules = []
    record_rules = []

    for rule_segment in group['groups']:
        if 'interval' in rule_segment:
            interval = rule_segment['interval']
        else:
            interval = '15s'
        for rule in rule_segment['rules']:
            if 'alert' in rule:
                alert_rules.append(convert_alert(rule, interval))
            else:
                record_rules.append(convert_record(rule, interval))

    return alert_rules, record_rules


'''
example of k8s rule configmap
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: rulefiles-0
data:
  etcdrules.yaml: |
    groups:
    - name: etcd
      rules:
      - alert: etcdInsufficientMembers
        annotations:
          message: 'etcd cluster "{{ $labels.job }}": insufficient members ({{ $value}}).'
        expr: sum(up{job=~".*etcd.*"} == bool 1) by (job) < ((count(up{job=~".*etcd.*"})
          by (job) + 1) / 2)
        for: 3m
        labels:
          severity: critical
'''
def deal_configmap(rule_configmap):
    """
    parse rule configmap from k8s
    """
    all_record_rules = []
    all_alert_rules = []
    for _, rule_group_str in rule_configmap['data'].items():
        rule_group = yaml.load(rule_group_str, Loader=yaml.FullLoader)
        alert_rules, record_rules = deal_group(rule_group)
        all_alert_rules.extend(alert_rules)
        all_record_rules.extend(record_rules)

    return all_alert_rules, all_record_rules


def main():
    with open(rule_file, 'r') as f:
        rule_config = yaml.load(f, Loader=yaml.FullLoader)
        
        # 如果文件是k8s中的configmap,使用下面的方法
        # alert_rules, record_rules = deal_configmap(rule_config)
        alert_rules, record_rules = deal_group(rule_config)

        with open("alert-rules.json", 'w') as fw:
            json.dump(alert_rules, fw, indent=2, ensure_ascii=False)

        with open("record-rules.json", 'w') as fw:
            json.dump(record_rules, fw, indent=2, ensure_ascii=False)


if __name__ == '__main__':
    main()
