易陆发现互联网技术论坛

 找回密码
 开始注册
查看: 53|回复: 0
收起左侧

新增neutron中subnet的删除,修改以及端口的操作

[复制链接]
发表于 2025-11-12 10:33:40 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?开始注册

x
7 ]; w* N7 C8 k5 g/ i
非常好 这一步就是把你的 openstack Neutron 网络管理模块从「仅网络层」扩展到完整的 网络 + 子网 + 端口管理功能。
) Y. w4 S$ b7 t. U) }下面我给你完整规划 + 代码框架(基于你现有的 network_list_view 和 edit_network_view 结构,可直接嵌入项目)。& B( {% @; z9 R5 j3 I1 ?

0 Z: \. m! l: U1 y
" ]5 O/ B& m" o1 W& H 一、总体架构设计
. C4 i# L" a+ N
& X1 d! w1 X+ ?我们按功能模块划分成三个部分:. l8 Z& p8 T/ c1 X( G
2 _* ]/ A. O$ N, d6 R1 n
networks/
" O3 I% K& t2 u/ {2 b( u- L* X├── views/
9 i! J5 O5 b) ~4 [5 @: S│   ├── networks.py     # 网络的增删改查3 G( u; y: N  s* {7 V5 S7 t9 k/ c
│   ├── subnets.py      # 子网管理(新增/编辑/删除)4 H6 `! w: y' Z% @- j8 i( s4 i
│   ├── ports.py        # 端口管理(创建/删除/绑定安全组/绑定虚机)
! r/ g3 I, M- _: w
& o( n- x9 X# P3 Z├── templates/4 Q+ e4 m; u  ~. q; c7 v8 s
│   ├── networks.html: e# c$ ^& f) _( _+ x: W
│   ├── network_edit.html; x6 Z% J, u/ u4 S$ p* i1 q* M
│   ├── subnets.html: \/ Q* }) ?! U# l2 c3 J
│   ├── subnet_edit.html$ @; t. n& C! y+ b. b- l
│   ├── ports.html0 X1 A, Q5 t: e. u6 ~- e, D
│   ├── port_edit.html
4 R) e- x. B- [# K  }2 c
, P1 e. k# [+ L2 `* i( c! q└── urls.py             # 统一注册URL4 N1 D$ \: d% u3 P# W) |
* d0 T0 x& [# I+ c  s
二、子网管理 Subnets 功能
) |* @$ Y: P9 E5 ?: f' m3 m子网列表
2 o- I9 y$ ^; C8 b# views/subnets.py
8 w) I  ^1 N' O: Q  S5 Q) i* Bimport requests8 \8 |' ]* f. f# r* c2 q2 M3 U
from django.shortcuts import render, redirect4 G- |% u4 x( ^; y. o: J
from django.contrib import messages
% w- M$ U3 v5 k. g0 I6 l1 L. C9 rfrom django.views.decorators.csrf import csrf_exempt
1 _/ S% ~4 x" R0 P  @) {1 W0 X& S5 a7 S  u
@csrf_exempt! _6 S( c. I  I, k3 j- f7 p0 }- w
def subnet_list_view(request, network_id):. q" D3 S  _4 H% b- p
    """查看指定网络的所有子网"""9 O+ ^, X. g% F: S
    token = request.session.get("token"): Q- R) `  M& f/ {6 E4 d, [3 w: P
    headers = {"X-Auth-Token": token}3 @6 U7 P; p1 }9 a4 U0 T
    resp = requests.get(f"{Neutron_Base}/subnets", headers=headers, timeout=10)1 `* I& R3 D! F! I8 |

& `/ D$ s9 Y! Z: A# i' Q! T3 r3 G    if resp.status_code == 200:
- {$ s+ S7 y2 x! n  S0 n% A( A        all_subnets = resp.json().get("subnets", [])( ^4 S/ ?3 N. E$ l% l
        subnets = [s for s in all_subnets if s["network_id"] == network_id]8 a) J! {1 g% y, p' @
    else:
4 ?0 y6 o8 @8 i, n2 S        messages.error(request, f"无法获取子网列表: {resp.text}"). g% J1 N. ?" B! U% s1 ~
        subnets = []
, X3 [3 p" P) _% R% A5 W7 d- A
" G) N- ?; E; G. K    return render(request, "subnets.html", {"subnets": subnets, "network_id": network_id})6 g, F9 F) ~; [' @

: t) g' H9 f* w+ w3 C5 D. t新建子网
- H) c* S# e- ^, u+ C& g@csrf_exempt: d! Y  G  G* w" L2 ~
def subnet_create_view(request, network_id):/ ?) [; f' x/ w) `9 A# y! R
    if request.method == "POST":
2 d- T5 _: i( [8 p2 [* P/ ?' k' Z: W        token = request.session.get("token")
+ M- h5 S2 e+ J& c        headers = {"X-Auth-Token": token, "Content-Type": "application/json"}: ^- p8 t6 d! x; B
, _7 n/ E) D' c6 N1 U9 X
        name = request.POST.get("name")
( r/ S  ~( P$ T% G/ K6 k( P        cidr = request.POST.get("cidr")4 x) F6 R2 q' L2 f+ {" J. c" C$ }
        gateway_ip = request.POST.get("gateway_ip")
5 m' y' w6 M3 C0 n6 S4 n# z        enable_dhcp = request.POST.get("enable_dhcp") == "on"
, C! }; `: d6 q/ E* x* B5 s& x! N4 V" K: _, D) g* g+ S! T
        data = {8 u% c, {& k, O, j9 W
            "subnet": {* _. T" w. H* Y  f3 t1 B
                "network_id": network_id,2 u; T+ ~1 p, a" v4 j& R: p
                "ip_version": 4,/ ^% K( J: ]1 v1 G0 [2 m) v
                "cidr": cidr,
: v- A) i5 B0 d& M                "gateway_ip": gateway_ip,
+ l+ g9 Q, j! q                "enable_dhcp": enable_dhcp,
/ [# {! Z- u1 }: e                "name": name,, G3 \; U' ?- R: p
            }
5 ^) m9 v$ P$ h1 z7 m) f9 \        }
7 z& x; U- G) `4 h0 r2 A
; e+ M5 X; W  Y        resp = requests.post(f"{Neutron_Base}/subnets", headers=headers, json=data, timeout=15)% t, C& w4 S/ y2 H' m7 x
        if resp.status_code in [200, 201]:, `2 G$ E: s3 ^# X. j+ o( X
            messages.success(request, "子网创建成功")
4 W7 I) |1 f& E' {5 _& f; N+ x' y        else:% x5 b) ~4 P9 v/ o( Z) |
            messages.error(request, f"子网创建失败: {resp.text}")
& w. R/ F* B4 A2 C        return redirect("subnet_list", network_id=network_id)$ B% S& O1 I3 \! [

8 r4 \1 O; T" j7 O    return render(request, "subnet_edit.html", {"network_id": network_id})
, G, |' X* L$ ?) C* ?1 x  O0 [5 O' ^5 R
删除子网
6 H, s! \9 S& R1 I9 X2 q. udef subnet_delete_view(request, subnet_id, network_id):' Z0 ~, x- P: i
    token = request.session.get("token")& M" ~9 G! b, m  |4 Z- n4 e1 D
    headers = {"X-Auth-Token": token}
- `$ p8 ]* N) Q8 q8 ^/ W    resp = requests.delete(f"{Neutron_Base}/subnets/{subnet_id}", headers=headers, timeout=10). B- w" E% n7 @/ o+ Q2 H. [
4 x4 i! Z7 K5 S, m" L7 @" \  [8 D
    if resp.status_code == 204:" S* M! _. P/ T. w( n' e, H8 L
        messages.success(request, "子网已删除")
4 \. h) M- Y6 R; {1 L9 Y' q  w2 _    else:; u/ c2 L, g# P% |/ \
        messages.error(request, f"删除失败: {resp.text}")
5 V* u* r  R! T5 m    return redirect("subnet_list", network_id=network_id)
# |4 Z" g, }+ J- v; h* p  u1 F) [" q/ m0 {. L) f3 O; e
三、端口 Ports 管理
0 R" L5 S7 k8 j8 a/ T端口列表
/ w" g( K  `* k$ P1 bdef port_list_view(request, network_id):
4 r4 h% D8 E7 a3 Y4 O" q    token = request.session.get("token")
& C/ T' S: {$ }2 L    headers = {"X-Auth-Token": token}8 G$ |; O" X7 e" |
    resp = requests.get(f"{Neutron_Base}/ports", headers=headers, timeout=10)' A6 Q- q* ]+ y% [! L* ~
5 H" ]7 W' x0 V& }0 [% t; s, F
    if resp.status_code == 200:
- U3 z% S8 u1 O2 O, g        ports = [p for p in resp.json().get("ports", []) if p["network_id"] == network_id]3 |$ H& K& H. h  b8 a' a
    else:# [0 C* Z# U: I! p3 I* K
        ports = []1 @' ~" g' g2 ?( F6 O; ^# @
        messages.error(request, f"无法获取端口: {resp.text}")( |# ?( @7 Y& V
3 W; f2 X, z2 n* f+ P7 k
    return render(request, "ports.html", {"ports": ports, "network_id": network_id})
- n1 `2 }" K( \( h
2 n1 `4 M+ w) @7 U1 a新建端口+ W" a& d& k; q$ j0 ?% V% b6 q7 o
@csrf_exempt
5 u3 U6 c8 ?4 {# F) p# N6 F% j: k6 Edef port_create_view(request, network_id):
; }8 J8 m0 F2 Q+ g( D$ o7 a    if request.method == "POST":
2 _2 j' y8 z9 e; I5 Y7 \        token = request.session.get("token")
- Q) u* `& E: {' m- i        headers = {"X-Auth-Token": token, "Content-Type": "application/json"}/ f0 @& s4 j1 r# u8 F( k3 r9 ?# ]

. n1 p2 `; Y* {        name = request.POST.get("name")
) T! B# J/ f0 d- U% A        data = {5 i$ s; K, h" Z4 s) h
            "port": {  Z' _3 R  V& G1 ]9 [7 m+ @1 _  U
                "network_id": network_id,* I6 G( S, J. [% T
                "name": name,
4 a; @7 L  H3 q, G$ ]                "admin_state_up": True$ u% U$ m5 m3 ^/ R* K! R
            }5 c% _# q% V; c5 b% _# b7 X
        }) _3 q+ v, v* D  `- E$ X  i% l6 `) m
        resp = requests.post(f"{Neutron_Base}/ports", headers=headers, json=data, timeout=10)7 C6 A  |$ C  X1 `& F
        if resp.status_code in [200, 201]:: A" Q( M3 U- ^' y9 B
            messages.success(request, "端口创建成功")
: d9 g) q: U; b8 Y, U3 }# y( X$ S        else:$ P! v$ z- l: b* V
            messages.error(request, f"创建失败: {resp.text}")' K5 e! @8 B6 j# |3 g- T4 O
        return redirect("port_list", network_id=network_id)5 ~2 U) n" c, R7 B4 E4 Y+ K
* V# H! m$ d1 \$ h! |
    return render(request, "port_edit.html", {"network_id": network_id})% M' ?5 b" O# X  z& g2 ^% |, Q# L7 b

( W# ~6 ]; [! [6 c删除端口- b) }$ I- ^! ^# [& h9 g
def port_delete_view(request, port_id, network_id):& Q" T2 T+ S; Q
    token = request.session.get("token")( ~0 Z; c; ?# B9 x. G
    headers = {"X-Auth-Token": token}
/ D# r, F2 o5 b+ \/ k0 P5 P) F    resp = requests.delete(f"{Neutron_Base}/ports/{port_id}", headers=headers, timeout=10)
# x% @# X$ W- t+ Y6 m* k
+ i* M% M, P. _0 ^7 n6 j) l* F    if resp.status_code == 204:
2 O/ ]$ D% E, p        messages.success(request, "端口已删除"); u: F1 T, o8 `( ?! {( o, y) O
    else:
5 t1 N6 e5 B) B+ _        messages.error(request, f"删除失败: {resp.text}")4 H" }' A) A% F. x

% _3 Y- v5 a$ z3 X. b- z    return redirect("port_list", network_id=network_id)& }; N/ h% E( A) |7 T) F* f
4 M8 E5 W' V; K+ `+ x" F. M
4️⃣ 更新安全组绑定* V+ l6 Z& M0 k* I$ ?, s/ S
@csrf_exempt
/ ~; O6 o: F# g% edef port_update_sg_view(request, port_id, network_id):
% M0 ]$ q9 ~' l0 D$ h! P2 `' g    if request.method == "POST":- c+ T- w6 ~' D: |/ z
        token = request.session.get("token")2 U2 Y' c% W5 i: u
        headers = {"X-Auth-Token": token, "Content-Type": "application/json"}
$ J2 C5 l9 E4 f* w$ S* w5 r        sg_id = request.POST.get("security_group_id")6 C9 x0 z6 z# k9 Z, C* f. t1 h

: V$ D; ~4 J7 u! u' H+ J) H+ n# y6 t        data = {"port": {"security_groups": [sg_id]}}
* v+ R. R$ i( w        resp = requests.put(f"{Neutron_Base}/ports/{port_id}", headers=headers, json=data, timeout=10)
5 h" M* W: ?, v9 l& M
& C0 U1 T2 H1 H  z/ W+ O( E3 {        if resp.status_code in [200, 202]:
9 h+ M, H/ [7 g- I            messages.success(request, "安全组更新成功")- x, R6 c7 G  p* {
        else:0 N  q+ l: M9 x
            messages.error(request, f"安全组更新失败: {resp.text}")% a9 u2 [5 n! Z

! `: D. q0 }: ?, r' ^    return redirect("port_list", network_id=network_id): G# T7 l8 A. ]# P5 x, Y! Z( k

1 n; I' [6 r5 T6 V! }5 e绑定虚机(实例)接口
4 i. M+ l; r) T$ j: x* r, W@csrf_exempt4 c! T2 p' R3 v/ G4 \/ Q
def port_bind_instance_view(request, port_id, server_id, network_id):4 C5 a" v# O+ \8 r
    token = request.session.get("token")
7 S2 y- m# g  V    headers = {"X-Auth-Token": token, "Content-Type": "application/json"}' _* f# m& S' N+ o+ S% g+ e% h3 K- T
' e5 C, B7 U0 \1 k4 }+ \! `
    data = {
/ M+ }" n2 f1 w        "port": {6 _! v; `2 w* |/ c% {
            "device_id": server_id,+ E; f$ U  J8 N3 D
            "device_owner": "compute:nova"0 T5 L. v2 }8 n& [, \! d
        }# e" C( _2 o% P7 q% u
    }
( }+ V8 R3 A! ^- o5 \2 i  D9 S
! M/ E" @! u6 c. h; S    resp = requests.put(f"{Neutron_Base}/ports/{port_id}", headers=headers, json=data, timeout=10)
' O' K7 W/ {, a2 j2 i* s  B8 b    if resp.status_code in [200, 202]:
1 t5 ]+ q' X4 |9 g        messages.success(request, "端口成功绑定到虚机"); P+ N. z: u9 K
    else:
' T. R# Y1 ~' A. s  D0 @' l        messages.error(request, f"绑定失败: {resp.text}")) q, H( d7 |6 f& D8 b
    return redirect("port_list", network_id=network_id)( i/ b& C' R! F
2 O" K: ~7 k( s( K' O
四、URL 路由示例
7 J" c3 E! V. _' R4 f8 }" S# urls.py
9 O0 a9 P  |9 H  h2 P7 [from django.urls import path
; B! F% H* ^; ]; P- Ffrom .views import networks, subnets, ports
! e; m" y3 I6 R( j' c4 i
- K$ L% r8 M' ]# P0 N8 r1 Z% m$ ?$ u4 k9 wurlpatterns = [
3 p* G9 L0 }, a% [$ q7 W3 x$ B4 i$ U+ y    path("networks/", networks.network_list_view, name="networks"),
/ s1 J, I4 \4 ^    path("networks/edit/<str:network_id>/", networks.edit_network_view, name="edit_network"),5 S; f" y9 s3 j& M  P' N1 N
. q2 A) r3 l( {+ M
    path("networks/<str:network_id>/subnets/", subnets.subnet_list_view, name="subnet_list"),
9 y, {- {, A! Z' ~    path("networks/<str:network_id>/subnets/create/", subnets.subnet_create_view, name="subnet_create"),
3 h1 X5 p# D8 M* a+ F! ~    path("networks/<str:network_id>/subnets/delete/<str:subnet_id>/", subnets.subnet_delete_view, name="subnet_delete"),
' |5 I2 L0 w1 B
' Y5 Y9 _: l( q/ {+ e    path("networks/<str:network_id>/ports/", ports.port_list_view, name="port_list"),0 Q: Y: q  a" m
    path("networks/<str:network_id>/ports/create/", ports.port_create_view, name="port_create"),
  z+ w1 f4 D* I. b7 g    path("networks/<str:network_id>/ports/delete/<str:port_id>/", ports.port_delete_view, name="port_delete"),
) e* @, R2 @' f5 U$ g    path("networks/<str:network_id>/ports/update_sg/<str:port_id>/", ports.port_update_sg_view, name="port_update_sg"),* p; M# ~/ `( o4 ~) y
    path("networks/<str:network_id>/ports/bind/<str:port_id>/<str:server_id>/", ports.port_bind_instance_view, name="port_bind_instance"),
- W' o$ k9 Y$ b. ?! G4 x]9 {6 q: l+ n7 o" {0 M' P7 Z* P

4 Z7 C7 E% d. a3 w
您需要登录后才可以回帖 登录 | 开始注册

本版积分规则

关闭

站长推荐上一条 /4 下一条

北京云银创陇科技有限公司以云计算运维,代码开发

QQ|返回首页|Archiver|小黑屋|易陆发现技术论坛 点击这里给我发消息

GMT+8, 2026-4-8 13:40 , Processed in 0.043709 second(s), 21 queries .

Powered by Discuz! X3.4 Licensed

© 2012-2025 Discuz! Team.

快速回复 返回顶部 返回列表