Passed
Pull Request — master (#160)
by
unknown
02:55
created

vlan_pool   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 198
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 149
dl 0
loc 198
rs 9.76
c 0
b 0
f 0
wmc 33

4 Functions

Rating   Name   Duplication   Size   Complexity  
C update_database() 0 65 9
C aggregate_outdated_interfaces() 0 61 11
A generate_ranges() 0 17 5
B get_range() 0 27 8
1
import datetime
2
import sys
3
import os
4
from collections import defaultdict
5
from kytos.core.db import Mongo
6
7
DEFAULT_TAG_RANGES = [[1, 4095]]
8
9
def get_range(vlans, avoid) -> list[list[int]]:
10
    """Convert available_vlans to available_tags.
11
    From list[int] to list[list[int]]"""
12
    result = []
13
    if not vlans:
14
        return result
15
    vlans.sort()
16
    i = 0
17
    while i < len(vlans):
18
        if vlans[i] in avoid:
19
            i += 1
20
        else:
21
            break
22
    if not vlans[i:]:
23
        return result
24
25
    start = end = vlans[i]
26
    for tag in vlans[i+1:]:
27
        if tag in avoid:
28
            continue
29
        if tag == end + 1:
30
            end = tag
31
        else:
32
            result.append([start, end])
33
            start = end = tag
34
    result.append([start, end])
35
    return result
36
37
def generate_ranges(avoid) -> [list[list[int]]]:
38
    """Generate available_tags only from avoid"""
39
    if not avoid:
40
        return DEFAULT_TAG_RANGES
41
42
    avoid.sort()
43
    ranges = []
44
    start = 1
45
46
    for num in avoid:
47
        if num > start:
48
            ranges.append([start, num - 1])
49
        start = num + 1
50
51
    if start <= 4095:
52
        ranges.append([start, 4095])
53
    return ranges
54
55
def update_database(mongo: Mongo):
56
    """Update database"""
57
    db = mongo.client[mongo.db_name]
58
    intf_documents = db.interface_details.find()
59
    evc_documents = db.evcs.find()
60
61
    evc_intf = defaultdict(set)
62
    evc_tags = defaultdict(set)
63
64
    for evc in evc_documents:
65
        tag_a = evc["uni_a"].get("tag")
66
        if tag_a:
67
            intf_id = evc["uni_a"]["interface_id"]
68
            if tag_a["value"] in evc_tags[intf_id]:
69
                print(f"Error: Detected duplicated {tag_a['value']} TAG"
70
                      f" in EVCs {evc['id']} and {evc_intf[intf_id].pop()}"
71
                      f" in interface {intf_id}")
72
                sys.exit(1)
73
            evc_tags[intf_id].add(tag_a["value"])
74
            evc_intf[intf_id].add(evc["id"])
75
76
        tag_z = evc["uni_z"].get("tag")
77
        if tag_z:
78
            intf_id = evc["uni_z"]["interface_id"]
79
            if tag_z["value"] in evc_tags[intf_id]:
80
                print(f"Error: Detected duplicated {tag_z['value']} TAG"
81
                      f" in EVCs {evc['id']} and {evc_intf[intf_id].pop()}"
82
                      f" in interface {intf_id}")
83
                sys.exit(1)
84
            evc_tags[intf_id].add(tag_z["value"])
85
            evc_intf[intf_id].add(evc["id"])
86
87
    intf_count = 0
88
    for document in intf_documents:
89
        avoid_tags = evc_tags.pop(document["id"], set())
90
        ranges = get_range(document["available_vlans"], avoid_tags)
91
        result = db.interface_details.update_one(
92
            {"id": document["id"]},
93
            {
94
                "$set": 
95
                {
96
                    "available_tags": {"vlan": ranges},
97
                    "tag_ranges": {"vlan": DEFAULT_TAG_RANGES}
98
                },
99
                "$unset": {"available_vlans": ""}
100
            }
101
        )
102
        intf_count += result.modified_count
103
104
    evc_intf_count = 0
105
    for intf_id, avoid_tags in evc_tags.items():
106
        available_tags = generate_ranges(list(avoid_tags))
107
        utc_now = datetime.datetime.utcnow()
108
        result = db.interface_details.insert_one({
109
            "_id": intf_id,
110
            "id": intf_id,
111
            "inserted_at": utc_now,
112
            "updated_at": utc_now,
113
            "available_tags": {"vlan": available_tags},
114
            "tag_ranges": {"vlan": DEFAULT_TAG_RANGES},
115
        })
116
        if result:
117
            evc_intf_count += 1
118
119
    print(f"{intf_count} documents modified. {evc_intf_count} documents inserted")
120
121
def aggregate_outdated_interfaces(mongo: Mongo):
122
    """Aggregate outdated inteface details"""
123
    db = mongo.client[mongo.db_name]
124
    document_ids = set()
125
    result = db.interface_details.aggregate(
126
        [
127
            {"$sort": {"_id": 1}},
128
            {"$project": {
129
                "_id": 0,
130
                "id": 1,
131
                "max_number": {"$max": "$available_vlans"},
132
                "min_number": {"$min": "$available_vlans"},
133
            }}
134
        ]
135
    )
136
    print("Here are the outdated interfaces. 'available_vlans' have a massive"
137
          " amount of items, minimum and maximum items will be shown only")
138
    for document in result:
139
        print(document)
140
        document_ids.add(document["id"])
141
    print()
142
    
143
    evc_documents = db.evcs.find()
144
    evc_intf = defaultdict(set)
145
    evc_tags = defaultdict(set)
146
147
    for evc in evc_documents:
148
        tag_a = evc["uni_a"].get("tag")
149
        if tag_a:
150
            intf_id = evc["uni_a"]["interface_id"]
151
            if tag_a["value"] in evc_tags[intf_id]:
152
                print(f"WARNING: Detected duplicated {tag_a['value']} TAG"
153
                      f" in EVCs {evc['id']} and {evc_intf[intf_id].pop()}"
154
                      f" in interface {intf_id}")
155
                print()
156
            evc_tags[intf_id].add(tag_a["value"])
157
            evc_intf[intf_id].add(evc["id"])
158
159
        tag_z = evc["uni_z"].get("tag")
160
        if tag_z:
161
            intf_id = evc["uni_z"]["interface_id"]
162
            if tag_z["value"] in evc_tags[intf_id]:
163
                print(f"WARNING: Detected duplicated {tag_z['value']} TAG"
164
                      f" in EVCs {evc['id']} and {evc_intf[intf_id].pop()}"
165
                      f" in interface {intf_id}")
166
                print()
167
            evc_tags[intf_id].add(tag_z["value"])
168
            evc_intf[intf_id].add(evc["id"])
169
170
    for id_ in document_ids:
171
        evc_tags.pop(id_, None)
172
173
    if evc_tags:
174
        print("New documents are going to be created. From the next interfaces,"
175
              " these tags should be avoided")
176
177
    for intf, avoid_tags in evc_tags.items():
178
        if intf in document_ids:
179
            continue
180
        aux = {"id": intf, "avoid_tags": avoid_tags}
181
        print(aux)
182
183
184
if __name__ == "__main__":
185
    mongo = Mongo()
186
    cmds = {
187
        "aggregate_outdated_interfaces": aggregate_outdated_interfaces,
188
        "update_database": update_database,
189
    }
190
    try:
191
        cmd = os.environ["CMD"]
192
        cmds[cmd](mongo)
193
    except KeyError:
194
        print(
195
            f"Please set the 'CMD' env var. \nIt has to be one of these: {list(cmds.keys())}"
196
        )
197
        sys.exit(1)
198