找回密码
 注册
查看: 53|回复: 0

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

[复制链接]

1

主题

0

回帖

12

积分

管理员

积分
12
QQ
发表于 2025-11-12 10:33:40 | 显示全部楼层 |阅读模式
$ K3 r5 `8 Z) J
非常好 这一步就是把你的 OpenStack Neutron 网络管理模块从「仅网络层」扩展到完整的 网络 + 子网 + 端口管理功能。* m" \3 Z& b6 F+ n6 x8 D: d
下面我给你完整规划 + 代码框架(基于你现有的 network_list_view 和 edit_network_view 结构,可直接嵌入项目)。, b: ]/ L0 H7 r5 k8 U8 F
0 p3 E" i5 Y# g* [
; x3 w) T8 q  i9 V: s* A" `7 }
一、总体架构设计
$ M/ B) m/ I9 m# I* M$ f) _2 U4 r. N: B
我们按功能模块划分成三个部分:# M+ X; j/ H) ?; C
# T; u5 t1 [( L% y' q) B
networks/( [2 y  R% J( s  b% R2 m8 i& k  I
├── views/
- N1 b+ R, d7 i1 _" B7 }│   ├── networks.py     # 网络的增删改查+ f' i) ^' X1 ]6 z
│   ├── subnets.py      # 子网管理(新增/编辑/删除)0 H1 m, K- B$ j, P' R6 {
│   ├── ports.py        # 端口管理(创建/删除/绑定安全组/绑定虚机)" K! C7 S" E; t4 @
4 q8 h* }! `# h, E, X# X
├── templates/0 |, d% F0 ^) f* l* d
│   ├── networks.html
* h# n" f! u1 V, s* h% p( m│   ├── network_edit.html
' W' X/ z. f# x+ X, j: M│   ├── subnets.html
% {& I' Z2 A( k│   ├── subnet_edit.html% S# a4 J) h& [* n
│   ├── ports.html# @5 b9 y8 ^( \% w8 M5 q  H& Q
│   ├── port_edit.html
5 [( p4 L6 m, [! l0 |: r2 x3 l( k/ g. X( V, E% Z
└── urls.py             # 统一注册URL
; k( S7 U1 n5 U& {7 C, W1 e4 J+ R7 z6 M! K. s" d  v* {7 N
二、子网管理 Subnets 功能
" J9 f$ Q1 x, s& x& i, K子网列表
; U  N9 v  s6 ?- d" `% C# views/subnets.py
: b5 P) Z! d, `9 E7 v6 E9 J: Dimport requests
! v3 f' S2 _7 k$ n: q( rfrom django.shortcuts import render, redirect
- u( Z. }/ o$ {1 N, g3 Vfrom django.contrib import messages
* W4 ~6 C# ?3 x9 yfrom django.views.decorators.csrf import csrf_exempt
6 f! m. a! H: Q3 B+ J* O; T( ?3 J# j! {! s3 D
@csrf_exempt% C" O+ @& \7 d* V- Y
def subnet_list_view(request, network_id):2 \0 a' u8 B2 F
    """查看指定网络的所有子网"""8 m' B# q( b3 V" K
    token = request.session.get("token")1 n8 X  c" Z& g- J# C
    headers = {"X-Auth-Token": token}' z- ~6 D+ r8 p, W! Z% Q& N
    resp = requests.get(f"{Neutron_Base}/subnets", headers=headers, timeout=10)
/ G2 K2 C( N/ P9 w. W1 }" ^5 q' j& a) g" h; j% z
    if resp.status_code == 200:
* G4 F/ \) U+ E        all_subnets = resp.json().get("subnets", [])
. F; S( K+ b. u3 }3 `        subnets = [s for s in all_subnets if s["network_id"] == network_id]
5 |$ R' `0 F/ z5 O# j    else:
, X* u9 b( V3 m5 n9 _9 t        messages.error(request, f"无法获取子网列表: {resp.text}")3 P3 n9 K8 A) v/ b6 Y- ^
        subnets = []' o7 U: M& k; {. e2 a: a
  K' j3 H* T5 g5 ]2 G4 u
    return render(request, "subnets.html", {"subnets": subnets, "network_id": network_id})9 e7 I& l: p1 q4 R* ~& I% u9 B

$ T; B, _, G. E7 B新建子网- k9 o; b. I, C+ C
@csrf_exempt( D6 D# H1 f+ n8 i9 k' ~
def subnet_create_view(request, network_id):
1 J1 O; i+ z/ J& Z) q% d' t    if request.method == "POST":# J# t  H* ~! K3 a( r5 I  q
        token = request.session.get("token")
0 Z1 m% O9 [8 s( E  X9 e        headers = {"X-Auth-Token": token, "Content-Type": "application/json"}6 ~3 W" B% R( b' U1 z, ^

0 k3 z' \4 d, |7 ~8 P: z$ i& N5 v        name = request.POST.get("name")
$ W* M2 V$ j. ?& K; \  v! ]        cidr = request.POST.get("cidr")
" N& c+ z. g0 w8 h- I        gateway_ip = request.POST.get("gateway_ip"); v6 P# @6 {* R
        enable_dhcp = request.POST.get("enable_dhcp") == "on"+ c0 S- H! A% R8 K' _! e

" p- W! r" p" I! F6 n6 P        data = {
, S* v9 b& q) ]0 d/ k, `            "subnet": {1 J4 u9 X" d0 n7 a8 u% k7 L  {6 L
                "network_id": network_id,
* [0 P0 L. |; N) b: T                "ip_version": 4,  ~; W9 K  P4 M$ ~8 D. w1 G
                "cidr": cidr,
9 \% {7 ?5 Y' C( @" _9 ]; _) ?) f                "gateway_ip": gateway_ip,
% N. J, F- Z. b) A                "enable_dhcp": enable_dhcp,
  q& \7 J+ n) a6 O3 C7 i7 S                "name": name,+ O# i/ r) ]7 Q9 p) d% E- g. q/ {! S
            }9 A7 ^/ w% O% }
        }
; b) p/ t1 F. e, S* S6 ^* k8 H/ I! z0 [! t0 Z6 D
        resp = requests.post(f"{Neutron_Base}/subnets", headers=headers, json=data, timeout=15)+ C/ t; J5 V) V- J1 a$ o  {# `
        if resp.status_code in [200, 201]:, R0 L: K) s& n+ W4 G
            messages.success(request, "子网创建成功")+ N$ b5 ^  A2 l" h  m: E' _  K
        else:4 b" g# K8 x4 b- p: h$ T9 |3 p
            messages.error(request, f"子网创建失败: {resp.text}")6 {; `% G; p; }: e% n
        return redirect("subnet_list", network_id=network_id)) ?' S! I/ K4 K% u3 {

5 }5 q) l  t" {2 |& I    return render(request, "subnet_edit.html", {"network_id": network_id})) o3 f/ U, [5 A/ J" r

5 r" O/ _, Z2 y删除子网1 @3 Y. t  V' s/ d* o2 t: c4 Z0 k
def subnet_delete_view(request, subnet_id, network_id):
+ ]% W% _9 h2 ~; Z; V: T: u    token = request.session.get("token")
, m. h$ c: d. Y, q; l    headers = {"X-Auth-Token": token}
; Z- A  U! P( c! O( P3 O    resp = requests.delete(f"{Neutron_Base}/subnets/{subnet_id}", headers=headers, timeout=10)
7 s2 k3 a3 N5 l4 `  G
- P1 E% _) @- D$ \, [/ ~    if resp.status_code == 204:7 f$ X" I6 E7 O" n+ ~( c/ W
        messages.success(request, "子网已删除")
5 n4 L$ U: M) A3 l    else:
1 {) D8 N/ a# @! ^  N  r- Q        messages.error(request, f"删除失败: {resp.text}")
& J8 S. |( \# p: I  M) f. u    return redirect("subnet_list", network_id=network_id). x0 Z9 ]# Y' u6 T- h4 H+ w

1 E& B+ y+ l* Z3 k 三、端口 Ports 管理
) X( ]( u& y( |& Y. `& R& W端口列表
: d3 u! N* v0 r! N" Y( M' ydef port_list_view(request, network_id):/ T1 O- k' w' k: |9 G
    token = request.session.get("token"). o$ }% n% T* I2 t& S  N$ @
    headers = {"X-Auth-Token": token}
' E* A! S" j! k% R: x/ o    resp = requests.get(f"{Neutron_Base}/ports", headers=headers, timeout=10)
6 ]. h" r  _: }4 T; D0 C4 R, u  S9 V# x3 \. R, p. k
    if resp.status_code == 200:
( Y. o! w8 T- F1 `( Z8 W        ports = [p for p in resp.json().get("ports", []) if p["network_id"] == network_id]+ s$ H8 ?" H% p! `$ w7 s
    else:
; m! N" O$ m8 W1 c; }1 K% A        ports = []+ F! v9 C4 |( a2 p4 _$ C' @
        messages.error(request, f"无法获取端口: {resp.text}")' _% _! ?) |2 Q/ _  U2 W

( t" N. A7 b8 s* \  g9 u2 v    return render(request, "ports.html", {"ports": ports, "network_id": network_id})
- A/ U: u, l6 {& z, X6 V  w7 C! d: Y4 C% F
新建端口
# T1 _2 S3 t! a( x2 U* D@csrf_exempt" X! x9 Q3 N+ ~1 b2 v. \8 W
def port_create_view(request, network_id):
, G9 ?- v- m1 t# f* G    if request.method == "POST":
/ l% ^0 G' C  _* D        token = request.session.get("token")
2 F! y/ E+ ]* A        headers = {"X-Auth-Token": token, "Content-Type": "application/json"}
6 e) F! R  }4 q* `9 ]. E7 M: C7 p& i; ^) p9 X
        name = request.POST.get("name")
' a2 `4 @- m$ p# s3 i/ m        data = {
; F/ ]) F( J, D9 H. S; @" M( s            "port": {
" z* H# ^5 w# H1 o6 A5 Q" k; }  K  B                "network_id": network_id,. w* v2 W9 Y. S. Z
                "name": name,1 u1 u, N' j4 f; ]  ~% h- O
                "admin_state_up": True6 V2 t& g/ g: J1 R! b
            }- x4 T( E+ j# y; Y/ J) G' k
        }8 K2 @3 P- f  x) D- |" r
        resp = requests.post(f"{Neutron_Base}/ports", headers=headers, json=data, timeout=10)6 z+ N2 n: n6 @, h7 L- e
        if resp.status_code in [200, 201]:+ ]( p1 W. ^4 X. @: g* v
            messages.success(request, "端口创建成功")0 ~/ y% r( {* ?- [+ ]
        else:
9 {$ B* e3 ^& Y7 C            messages.error(request, f"创建失败: {resp.text}")
; `7 y) a- u8 q4 O$ `        return redirect("port_list", network_id=network_id)
2 j6 A* ]+ |2 `5 l+ |/ h" I, `5 D0 K* Y9 |- m- _& L2 C
    return render(request, "port_edit.html", {"network_id": network_id})
' T5 ?* Y3 ?) y" g- \
6 ~$ S4 r: P) W1 m删除端口
1 S' x( E: f% b  U( @* udef port_delete_view(request, port_id, network_id):
8 \5 |0 Y8 T7 o    token = request.session.get("token")
! h* Y4 h- {" O- k% W    headers = {"X-Auth-Token": token}, V0 Z* o- G1 E# `  ^0 U' v
    resp = requests.delete(f"{Neutron_Base}/ports/{port_id}", headers=headers, timeout=10)
# N" m5 v- N5 l5 d
% c% A7 ~5 t/ X2 U" @) }9 e    if resp.status_code == 204:
( A: U. X+ e; e/ L3 x( e& N6 n        messages.success(request, "端口已删除")7 X+ M6 ^1 i+ v" K
    else:/ j' {  n; [: r, N
        messages.error(request, f"删除失败: {resp.text}")% ?5 }  m& u& V2 a

8 w+ W" W& J+ t9 _7 w7 }4 @    return redirect("port_list", network_id=network_id)& ?) @3 u: U# E( e) I. @( L2 W1 ^
/ U" B: h4 I9 W' f7 q7 r% C' k& K8 H
4️⃣ 更新安全组绑定
; U9 U$ I# m' y; m@csrf_exempt
) p7 K4 C& f6 ]def port_update_sg_view(request, port_id, network_id):
1 A3 Y4 R! J$ U; D9 ~& w    if request.method == "POST":: j/ ~. y3 s$ c7 y( K
        token = request.session.get("token")
; _+ k) {& {, j# C9 o, T/ n        headers = {"X-Auth-Token": token, "Content-Type": "application/json"}! A$ T) s8 O2 M/ f, K4 C% |9 G% }
        sg_id = request.POST.get("security_group_id")
5 _4 O) w9 M- h# w" c* W
1 A! S6 C" l( K, s        data = {"port": {"security_groups": [sg_id]}}
% x1 ]8 _4 ~" P# N! ^        resp = requests.put(f"{Neutron_Base}/ports/{port_id}", headers=headers, json=data, timeout=10)
  E  U, C  n% [: k
6 m; G5 ~% [5 l; k7 N' C1 S3 z        if resp.status_code in [200, 202]:
8 c/ p9 P3 H) X' @( v, `            messages.success(request, "安全组更新成功")
& q1 F/ W. X' D# i. h        else:
' @  Q- d  G  _7 j3 V            messages.error(request, f"安全组更新失败: {resp.text}")
. x# [6 |+ u# w: O/ f3 B
$ m4 W# M, F& k9 p  |    return redirect("port_list", network_id=network_id)8 v6 H# W) {9 u, p/ x* L4 H

, j' F1 E" `- H% s绑定虚机(实例)接口
& l/ ^% C9 W& }4 x9 E$ \, o! W@csrf_exempt
6 I& `) C8 L8 G7 p1 Ydef port_bind_instance_view(request, port_id, server_id, network_id):
; H; Q7 Z* z) d) b6 t& P# h    token = request.session.get("token")7 l( R- H/ g: R. u% @& I! {, f
    headers = {"X-Auth-Token": token, "Content-Type": "application/json"}
6 ?8 \! P& f( T7 l3 S& z7 R  `+ Y* ^! k( {/ R0 W* i/ Q
    data = {, E8 N% [. `5 \5 l; V: O2 U
        "port": {
; s9 ^+ p0 X3 f8 L% u6 o0 f) K) `            "device_id": server_id,7 I& z0 f& I4 f1 o3 C
            "device_owner": "compute:nova"5 {: O* u  X. I& G' s4 Z$ d
        }
! K: P6 Y# U/ x9 ]    }
' D4 X3 ]4 w' o) P
/ J1 ~# a" p+ C! d1 C1 E    resp = requests.put(f"{Neutron_Base}/ports/{port_id}", headers=headers, json=data, timeout=10)
0 ?, o+ O) A# l$ I4 a2 z    if resp.status_code in [200, 202]:% ]: \" n; a9 j. `- V
        messages.success(request, "端口成功绑定到虚机")
2 Q2 ?$ T/ r& \  e! J    else:, Q7 \% s- F1 L
        messages.error(request, f"绑定失败: {resp.text}")+ j3 p% r, y$ H" S3 o" b$ y9 Y
    return redirect("port_list", network_id=network_id)2 \! @) T/ h* f- [! U
- q; T! u! t/ s) J1 h/ V0 L
四、URL 路由示例
/ z, s' @, u, p' ?4 V6 h2 {4 b# urls.py4 A/ h7 ]+ p4 K& N4 v1 J+ x" J/ n
from django.urls import path
% `6 m1 `* H6 f7 S9 B, s6 A' F: tfrom .views import networks, subnets, ports- a1 J( U0 E9 u" l. E3 c" X

, b5 k0 B5 q, z1 w2 r2 Z( [urlpatterns = [
/ s& p0 O: e3 Y7 H; p/ B1 Z2 t    path("networks/", networks.network_list_view, name="networks"),- G9 o2 m4 n0 z$ D
    path("networks/edit/<str:network_id>/", networks.edit_network_view, name="edit_network"),% p: s% m' J& h9 }4 P6 s4 c

: P, w+ _7 U0 {5 Q/ b, J& u1 ?    path("networks/<str:network_id>/subnets/", subnets.subnet_list_view, name="subnet_list"),
  t# H6 ?# O# `% Q* L$ w    path("networks/<str:network_id>/subnets/create/", subnets.subnet_create_view, name="subnet_create"),
, t( c1 H( u$ L% y9 Q8 M) B    path("networks/<str:network_id>/subnets/delete/<str:subnet_id>/", subnets.subnet_delete_view, name="subnet_delete"),
+ I4 k1 `& g4 g" e
- U9 }3 a/ ~& a& I0 `1 i% T6 y    path("networks/<str:network_id>/ports/", ports.port_list_view, name="port_list"),
; i2 Y; z8 @) i. O  y" C8 b' Z) U2 ]    path("networks/<str:network_id>/ports/create/", ports.port_create_view, name="port_create"),4 N+ ^4 K8 Q" W! T
    path("networks/<str:network_id>/ports/delete/<str:port_id>/", ports.port_delete_view, name="port_delete"),
1 C9 A( y  w5 S" P    path("networks/<str:network_id>/ports/update_sg/<str:port_id>/", ports.port_update_sg_view, name="port_update_sg"),3 c9 ~% A# A/ U" i. m! \0 h# x: P" a
    path("networks/<str:network_id>/ports/bind/<str:port_id>/<str:server_id>/", ports.port_bind_instance_view, name="port_bind_instance"),
! p! G, C. X' p0 N! ^: {% {$ {  W]& U% p4 E9 e$ f, k' d
- i( H# H6 z& `- m; r2 B3 X7 B6 v
您需要登录后才可以回帖 登录 | 注册

本版积分规则

返回首页|Archiver|手机版|小黑屋|易陆发现技术论坛 ( 蜀ICP备2026014127号-1 )

GMT+8, 2026-6-11 23:54 , Processed in 0.012675 second(s), 22 queries .

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

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