• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

atlanticwave-sdx / sdx-controller / 13336339094

14 Feb 2025 07:46PM UTC coverage: 55.747% (+0.4%) from 55.374%
13336339094

Pull #416

github

web-flow
Merge b98d270a9 into 5c5ba2915
Pull Request #416: Change strings to consts

35 of 46 new or added lines in 8 files covered. (76.09%)

1 existing line in 1 file now uncovered.

1135 of 2036 relevant lines covered (55.75%)

1.11 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

55.08
/sdx_controller/controllers/l2vpn_controller.py
1
import json
2✔
2
import logging
2✔
3
import uuid
2✔
4

5
import connexion
2✔
6
from flask import current_app
2✔
7

8
from sdx_controller import util
2✔
9
from sdx_controller.handlers.connection_handler import (
2✔
10
    ConnectionHandler,
11
    get_connection_status,
12
)
13
from sdx_controller.models.connection import Connection  # noqa: E501
2✔
14
from sdx_controller.models.l2vpn_body import L2vpnBody  # noqa: E501
2✔
15
from sdx_controller.models.l2vpn_service_id_body import L2vpnServiceIdBody  # noqa: E501
2✔
16
from sdx_controller.utils.db_utils import DbUtils
2✔
17
from sdx_controller.utils.constants import MongoCollections
2✔
18

19
LOG_FORMAT = (
2✔
20
    "%(levelname) -10s %(asctime)s %(name) -30s %(funcName) "
21
    "-35s %(lineno) -5d: %(message)s"
22
)
23
logger = logging.getLogger(__name__)
2✔
24
logging.getLogger("pika").setLevel(logging.WARNING)
2✔
25
logger.setLevel(logging.DEBUG)
2✔
26

27
# Get DB connection and tables set up.
28
db_instance = DbUtils()
2✔
29
db_instance.initialize_db()
2✔
30
connection_handler = ConnectionHandler(db_instance)
2✔
31

32

33
def delete_connection(service_id):
2✔
34
    """
35
    Delete connection order by ID.
36

37
    :param service_id: ID of the connection that needs to be
38
        deleted
39
    :type service_id: str
40

41
    :rtype: None
42
    """
43
    logger.info(
2✔
44
        f"Handling delete (service id: {service_id}) "
45
        f"with te_manager: {current_app.te_manager}"
46
    )
47

48
    # # Looking up by UUID do not seem work yet.  Will address in
49
    # # https://github.com/atlanticwave-sdx/sdx-controller/issues/252.
50
    #
51
    # value = db_instance.read_from_db(f"{service_id}")
52
    # print(f"value: {value}")
53
    # if not value:
54
    #     return "Not found", 404
55

56
    try:
2✔
57
        # TODO: pce's unreserve_vlan() method silently returns even if the
58
        # service_id is not found.  This should in fact be an error.
59
        #
60
        # https://github.com/atlanticwave-sdx/pce/issues/180
61
        connection = db_instance.read_from_db(
2✔
62
            MongoCollections.CONNECTIONS, f"{service_id}"
63
        )
64
        if not connection:
2✔
65
            return "Did not find connection", 404
2✔
66
        connection_handler.remove_connection(current_app.te_manager, service_id)
2✔
67
        db_instance.mark_deleted(MongoCollections.CONNECTIONS, f"{service_id}")
2✔
68
        db_instance.mark_deleted(MongoCollections.BREAKDOWNS, f"{service_id}")
2✔
69
    except Exception as e:
×
70
        logger.info(f"Delete failed (connection id: {service_id}): {e}")
×
71
        return f"Failed, reason: {e}", 500
×
72

73
    return "OK", 200
2✔
74

75

76
def get_connection_by_id(service_id):
2✔
77
    """
78
    Find connection by ID.
79

80
    :param service_id: ID of connection that needs to be fetched
81
    :type service_id: str
82

83
    :rtype: Connection
84
    """
85

86
    value = get_connection_status(db_instance, service_id)
2✔
87

88
    if not value:
2✔
89
        return "Connection not found", 404
2✔
90

91
    return value
2✔
92

93

94
def get_connections():  # noqa: E501
2✔
95
    """List all connections
96

97
    connection details # noqa: E501
98

99
    :rtype: Connection
100
    """
101
    values = db_instance.get_all_entries_in_collection(MongoCollections.CONNECTIONS)
2✔
102
    if not values:
2✔
103
        return "No connection was found", 404
2✔
104
    return_values = {}
2✔
105
    for connection in values:
2✔
106
        service_id = next(iter(connection))
2✔
107
        return_values[service_id] = get_connection_status(db_instance, service_id)[
2✔
108
            service_id
109
        ]
110
    return return_values
2✔
111

112

113
def place_connection(body):
2✔
114
    """
115
    Place an connection request from the SDX-Controller.
116

117
    :param body: order placed for creating a connection
118
    :type body: dict | bytes
119

120
    :rtype: Connection
121
    """
122
    logger.info(f"Placing connection: {body}")
2✔
123
    if not connexion.request.is_json:
2✔
124
        return "Request body must be JSON", 400
×
125

126
    body = connexion.request.get_json()
2✔
127
    logger.info(f"Gathered connexion JSON: {body}")
2✔
128

129
    logger.info("Placing connection. Saving to database.")
2✔
130

131
    service_id = body.get("id")
2✔
132

133
    if service_id is None:
2✔
134
        service_id = str(uuid.uuid4())
2✔
135
        body["id"] = service_id
2✔
136
        logger.info(f"Request has no ID. Generated ID: {service_id}")
2✔
137

138
    logger.info("Saving to database complete.")
2✔
139

140
    logger.info(
2✔
141
        f"Handling request {service_id} with te_manager: {current_app.te_manager}"
142
    )
143
    reason, code = connection_handler.place_connection(current_app.te_manager, body)
2✔
144

145
    if code // 100 == 2:
2✔
146
        db_instance.add_key_value_pair_to_db(
2✔
147
            MongoCollections.CONNECTIONS, service_id, json.dumps(body)
148
        )
149
        # Service created successfully
150
        code = 201
2✔
151

152
    logger.info(
2✔
153
        f"place_connection result: ID: {service_id} reason='{reason}', code={code}"
154
    )
155

156
    response = {
2✔
157
        "service_id": service_id,
158
        "status": "OK" if code // 100 == 2 else "Failure",
159
        "reason": reason,
160
    }
161

162
    # # TODO: our response is supposed to be shaped just like request
163
    # # ('#/components/schemas/connection'), and in that case the below
164
    # # code would be a quick implementation.
165
    # #
166
    # # https://github.com/atlanticwave-sdx/sdx-controller/issues/251
167
    # response = body
168

169
    # response["id"] = service_id
170
    # response["status"] = "success" if code == 2xx else "failure"
171
    # response["reason"] = reason # `reason` is not present in schema though.
172

173
    return response, code
2✔
174

175

176
def patch_connection(service_id, body=None):  # noqa: E501
2✔
177
    """Edit and change an existing L2vpn connection by ID from the SDX-Controller
178

179
     # noqa: E501
180

181
    :param service_id: ID of l2vpn connection that needs to be changed
182
    :type service_id: dict | bytes'
183
    :param body:
184
    :type body: dict | bytes
185

186
    :rtype: Connection
187
    """
NEW
188
    value = db_instance.read_from_db(MongoCollections.CONNECTIONS, f"{service_id}")
×
189
    if not value:
×
190
        return "Connection not found", 404
×
191

192
    if not connexion.request.is_json:
×
193
        return "Request body must be JSON", 400
×
194

195
    body = L2vpnServiceIdBody.from_dict(connexion.request.get_json())  # noqa: E501
×
196

197
    logger.info(f"Gathered connexion JSON: {body}")
×
198

199
    body["id"] = service_id
×
200
    logger.info(f"Request has no ID. Generated ID: {service_id}")
×
201

202
    try:
×
203
        logger.info("Removing connection")
×
204
        # Get roll back connection before removing connection
NEW
205
        rollback_conn_body = db_instance.read_from_db(
×
206
            MongoCollections.CONNECTIONS, service_id
207
        )
UNCOV
208
        remove_conn_reason, remove_conn_code = connection_handler.remove_connection(
×
209
            current_app.te_manager, service_id
210
        )
211

212
        if remove_conn_code // 100 != 2:
×
213
            response = {
×
214
                "service_id": service_id,
215
                "status": "Failure",
216
                "reason": remove_conn_reason,
217
            }
218
            return response, remove_conn_code
×
219

220
        logger.info(f"Removed connection: {service_id}")
×
221
    except Exception as e:
×
222
        logger.info(f"Delete failed (connection id: {service_id}): {e}")
×
223
        return f"Failed, reason: {e}", 500
×
224

225
    logger.info(
×
226
        f"Placing new connection {service_id} with te_manager: {current_app.te_manager}"
227
    )
228

229
    reason, code = connection_handler.place_connection(current_app.te_manager, body)
×
230

231
    if code // 100 == 2:
×
232
        db_instance.add_key_value_pair_to_db(
×
233
            MongoCollections.CONNECTIONS, service_id, json.dumps(body)
234
        )
235
        # Service created successfully
236
        code = 201
×
237
        logger.info(f"Placed: ID: {service_id} reason='{reason}', code={code}")
×
238
        response = {
×
239
            "service_id": service_id,
240
            "status": "OK",
241
            "reason": reason,
242
        }
243
        return response, code
×
244

245
    logger.info(
×
246
        f"Failed to place new connection. ID: {service_id} reason='{reason}', code={code}"
247
    )
248
    logger.info("Rolling back to old connection.")
×
249

250
    if not rollback_conn_body:
×
251
        response = {
×
252
            "service_id": service_id,
253
            "status": "Failure, unable to rollback to last successful L2VPN connection",
254
            "reason": reason,
255
        }
256
        return response, code
×
257

258
    conn_request = json.loads(rollback_conn_body[service_id])
×
259
    conn_request["id"] = service_id
×
260

261
    try:
×
262
        rollback_conn_reason, rollback_conn_code = connection_handler.place_connection(
×
263
            current_app.te_manager, conn_request
264
        )
265
        if rollback_conn_code // 100 == 2:
×
266
            db_instance.add_key_value_pair_to_db(
×
267
                MongoCollections.CONNECTIONS, service_id, json.dumps(conn_request)
268
            )
269
        logger.info(
×
270
            f"Roll back connection result: ID: {service_id} reason='{rollback_conn_reason}', code={rollback_conn_code}"
271
        )
272
    except Exception as e:
×
273
        logger.info(f"Rollback failed (connection id: {service_id}): {e}")
×
274
        return f"Rollback failed, reason: {e}", 500
×
275

276
    response = {
×
277
        "service_id": service_id,
278
        "status": "Failure, rolled back to last successful L2VPN connection",
279
        "reason": reason,
280
    }
281
    return response, code
×
282

283

284
def get_archived_connections_by_id(service_id):
2✔
285
    """
286
    List archived connection by ID.
287

288
    :param service_id: ID of connection that needs to be fetched
289
    :type service_id: str
290

291
    :rtype: Connection
292
    """
293

294
    value = get_connection_status(db_instance, service_id)
×
295

296
    if not value:
×
297
        return "Connection not found", 404
×
298

299
    return value
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc