Passed
Pull Request — master (#69)
by Humberto
01:53
created

build.main.Main._install_flows()   A

Complexity

Conditions 5

Size

Total Lines 20
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
eloc 12
dl 0
loc 20
rs 9.3333
c 0
b 0
f 0
ccs 0
cts 12
cp 0
cc 5
nop 4
crap 30
1
"""kytos/flow_manager NApp installs, lists and deletes switch flows."""
2
from flask import jsonify, request
3
from kytos.core import KytosEvent, KytosNApp, log, rest
4
5
from napps.kytos.of_core.v0x01.flow import Flow as Flow10
6
from napps.kytos.of_core.v0x04.flow import Flow as Flow13
7
8
9
class Main(KytosNApp):
10
    """Main class to be used by Kytos controller."""
11
12
    def setup(self):
13
        """Replace the 'init' method for the KytosApp subclass.
14
15
        The setup method is automatically called by the run method.
16
        Users shouldn't call this method directly.
17
        """
18
        log.debug("flow-manager starting")
19
20
    def execute(self):
21
        """Run once on NApp 'start' or in a loop.
22
23
        The execute method is called by the run method of KytosNApp class.
24
        Users shouldn't call this method directly.
25
        """
26
        pass
27
28
    def shutdown(self):
29
        """Shutdown routine of the NApp."""
30
        log.debug("flow-manager stopping")
31
32
    @rest('v2/flows')
33
    @rest('v2/flows/<dpid>')
34
    def list(self, dpid=None):
35
        """Retrieve all flows from a switch identified by dpid.
36
37
        If no dpid is specified, return all flows from all switches.
38
        """
39
        if dpid is None:
40
            switches = self.controller.switches.values()
41
        else:
42
            switches = [self.controller.get_switch_by_dpid(dpid)]
43
44
        switch_flows = {}
45
46
        for switch in switches:
47
            flows_dict = [flow.as_dict() for flow in switch.flows]
48
            switch_flows[switch.dpid] = {'flows': flows_dict}
49
50
        return jsonify(switch_flows)
51
52
    @rest('v2/flows', methods=['POST'])
53
    @rest('v2/flows/<dpid>', methods=['POST'])
54
    def add(self, dpid=None):
55
        """Install new flows in the switch identified by dpid.
56
57
        If no dpid is specified, install flows in all switches.
58
        """
59
        return self._send_flow_mods_from_request(dpid, "add")
60
61
    @rest('v2/delete', methods=['POST'])
62
    @rest('v2/delete/<dpid>', methods=['POST'])
63
    def delete(self, dpid=None):
64
        """Delete existing flows in the switch identified by dpid.
65
66
        If no dpid is specified, delete flows from all switches.
67
        """
68
        return self._send_flow_mods_from_request(dpid, "delete")
69
70
    def _get_all_switches_enabled(self):
71
        """Get a list of all switches enabled."""
72
        switches = self.controller.switches.values()
73
        return [switch for switch in switches if switch.is_enabled()]
74
75
    def _send_flow_mods_from_request(self, dpid, command):
76
        """Install FlowsMods from request."""
77
        flows_dict = request.get_json()
78
79
        if flows_dict is None:
80
            return jsonify({"response": 'flows dict is none.'}), 404
81
82
        if dpid:
83
            switch = self.controller.get_switch_by_dpid(dpid)
84
            if not switch:
85
                return jsonify({"response": 'dpid not found.'}), 404
86
            elif switch.is_enabled() is False:
87
                return jsonify({"response": 'switch is disabled.'}), 404
88
            else:
89
                self._install_flows(command, flows_dict, [switch])
90
        else:
91
            self._install_flows(command, flows_dict,
92
                                self._get_all_switches_enabled())
93
94
        return jsonify({"response": "FlowMod Messages Sent"})
95
96
    def _install_flows(self, command, flows_dict, switches=[]):
97
        """Execute all procedures to install flows in the switches.
98
99
        Args:
100
            command: Flow command to be installed
101
            flows_dict: Dictionary with flows to be installed in the switches.
102
            switches: A list of switches
103
        """
104
        for switch in switches:
105
            serializer = self._get_flow_serializer(switch)
106
            flows = flows_dict.get('flows', [])
107
            for flow_dict in flows:
108
                flow = serializer.from_dict(flow_dict, switch)
109
                if command == "delete":
110
                    flow_mod = flow.as_of_delete_flow_mod()
111
                elif command == "add":
112
                    flow_mod = flow.as_of_add_flow_mod()
113
                self._send_flow_mod(flow.switch, flow_mod)
0 ignored issues
show
introduced by
The variable flow_mod does not seem to be defined for all execution paths.
Loading history...
114
115
                self._send_napp_event(switch, flow, command)
116
117
    def _send_flow_mod(self, switch, flow_mod):
118
        event_name = 'kytos/flow_manager.messages.out.ofpt_flow_mod'
119
120
        content = {'destination': switch.connection,
121
                   'message': flow_mod}
122
123
        event = KytosEvent(name=event_name, content=content)
124
        self.controller.buffers.msg_out.put(event)
125
126
    def _send_napp_event(self, switch, flow, command):
127
        """Send an Event to other apps informing about a FlowMod."""
128
        if command == 'add':
129
            name = 'kytos/flow_manager.flow.added'
130
        elif command == 'delete':
131
            name = 'kytos/flow_manager.flow.removed'
132
        content = {'datapath': switch,
133
                   'flow': flow}
134
        event_app = KytosEvent(name, content)
0 ignored issues
show
introduced by
The variable name does not seem to be defined for all execution paths.
Loading history...
135
        self.controller.buffers.app.put(event_app)
136
137
    @staticmethod
138
    def _get_flow_serializer(switch):
139
        """Return the serializer with for the switch OF protocol version."""
140
        version = switch.connection.protocol.version
141
        return Flow10 if version == 0x01 else Flow13
142