From 14d87a3584c53b20ce0be38aeea92b2307f11355 Mon Sep 17 00:00:00 2001 From: thatmattlove Date: Tue, 31 Aug 2021 23:56:18 -0700 Subject: [PATCH] Fixes #7041: Properly format JSON config object returned from a NAPALM device --- docs/release-notes/version-3.0.md | 1 + netbox/dcim/api/views.py | 4 +- netbox/project-static/dist/config.js | Bin 114815 -> 115055 bytes netbox/project-static/dist/config.js.map | Bin 113061 -> 113259 bytes netbox/project-static/dist/jobs.js.map | Bin 113241 -> 113238 bytes netbox/project-static/dist/lldp.js.map | Bin 113710 -> 113707 bytes netbox/project-static/dist/netbox.js | Bin 322387 -> 322387 bytes netbox/project-static/dist/netbox.js.map | Bin 310915 -> 310912 bytes netbox/project-static/dist/status.js | Bin 135621 -> 135621 bytes netbox/project-static/dist/status.js.map | Bin 135773 -> 135770 bytes netbox/project-static/src/device/config.ts | 20 +++++++--- netbox/project-static/src/global.d.ts | 9 +++-- netbox/project-static/src/util.ts | 4 +- netbox/utilities/utils.py | 41 +++++++++++++++++++++ 14 files changed, 67 insertions(+), 12 deletions(-) diff --git a/docs/release-notes/version-3.0.md b/docs/release-notes/version-3.0.md index db3bc822c..ecccb7306 100644 --- a/docs/release-notes/version-3.0.md +++ b/docs/release-notes/version-3.0.md @@ -4,6 +4,7 @@ ### Bug Fixes +* [#7041](https://github.com/netbox-community/netbox/issues/7041) - Properly format JSON config object returned from a NAPALM device * [#7070](https://github.com/netbox-community/netbox/issues/7070) - Fix exception when filtering by prefix max length in UI * [#7071](https://github.com/netbox-community/netbox/issues/7071) - Fix exception when removing a primary IP from a device/VM * [#7072](https://github.com/netbox-community/netbox/issues/7072) - Fix table configuration under prefix child object views diff --git a/netbox/dcim/api/views.py b/netbox/dcim/api/views.py index 3ee225335..3d23cde5c 100644 --- a/netbox/dcim/api/views.py +++ b/netbox/dcim/api/views.py @@ -22,7 +22,7 @@ from netbox.api.authentication import IsAuthenticatedOrLoginNotRequired from netbox.api.exceptions import ServiceUnavailable from netbox.api.metadata import ContentTypeMetadata from utilities.api import get_serializer_for_model -from utilities.utils import count_related +from utilities.utils import count_related, decode_dict from virtualization.models import VirtualMachine from . import serializers from .exceptions import MissingFilterException @@ -498,7 +498,7 @@ class DeviceViewSet(ConfigContextQuerySetMixin, CustomFieldModelViewSet): response[method] = {'error': 'Only get_* NAPALM methods are supported'} continue try: - response[method] = getattr(d, method)() + response[method] = decode_dict(getattr(d, method)()) except NotImplementedError: response[method] = {'error': 'Method {} not implemented for NAPALM driver {}'.format(method, driver)} except Exception as e: diff --git a/netbox/project-static/dist/config.js b/netbox/project-static/dist/config.js index 18f4811a2f2c6aca27e6a3ff2d60606c38868fec..cf10225897ccff4bb2e7d618389f55d4e4eb61f8 100644 GIT binary patch delta 4351 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 diff --git a/netbox/project-static/dist/config.js.map b/netbox/project-static/dist/config.js.map index 176f8c85ebd7f8158b56452e5f7dc376edf387a6..5f27e84a67d6b0856fe2b883776b8a2d40433c04 100644 GIT binary patch delta 333 zcmZ9HO^U)m5QS+Ovho6+!Ga(n;_`LT1ZhJEA+(vD41+uI2I?t1fw*!f{#;?MGT=rJ zU{&HqH$`{7_r9vy-J}0Uv_6{sq0JL=;6MzXo=*q!7n%6HIU4u1%7L6xAQcBZW#EOS zUvNPQ(B-CE0W%HvoOUZJfRefvn7<4G2$DsnfT5!g>PzO4r2zJdnkXryj?^FdgQ-+T zU1o57-rg=|uo8JpW1Z>MF2SX3lA;vNb~QZ#$CjXWxhB(0kUgE)<*;1AmAsO-zc9Tj TC6)wuUW?%h&QdW;^M)Iyz>%=r}t%SGjKAyq5748>9L5x-E>ZEE?gC&fXvi zA02l`M_&+;4C3ZE>4Z8uJ3@#=M|ZdB(K{JUH5?rsJ#{=C9V2yo9i3A^ssn*afLx#j W-a6rqj^R3ij^4)3(*<`iMgahUbts+y diff --git a/netbox/project-static/dist/jobs.js.map b/netbox/project-static/dist/jobs.js.map index fbd95026752bc3cac84fb2eb4bcd0ebfb86b4fd0..e07a4157de968c29146982fd80c46bbd22192f75 100644 GIT binary patch delta 38 ucmcclh3(oGwuUW?^Vae>`{=kjI*02xJ32>fU%Qs^0xP5W_PWiCx7h$c8xKDK delta 41 xcmccih3)1SwuUW?^Vae^W;^M)Iyz>%=r}t%SGjIqwU+S$E2HuD>dlO|*#K^%5L5sF diff --git a/netbox/project-static/dist/lldp.js.map b/netbox/project-static/dist/lldp.js.map index be357a5bc1312edf9251846efc0cc05eed2e04c7..028c35995d72367a0121b5636191984469c42f57 100644 GIT binary patch delta 38 ucmZ4YgKhN>wuUW?OV{!^`{=kjI*02xJ32>f-?EnR6dR-d_WCW1>)8P`VGhXv delta 41 xcmZ4egKgapwuUW?OV{!{W;^M)Iyz>%=r}t%SGjKAxR&u08>9L5nk|g$*#To{59$B_ diff --git a/netbox/project-static/dist/netbox.js b/netbox/project-static/dist/netbox.js index a5995f96aae5daa27f7f6153233639b5a2f9fd60..e9ea8ddbfe19387a60e7c0b0f5bbf4c71efe92a8 100644 GIT binary patch delta 2845 zcmZWre^3;)u+#Y*-{16a~ zCRQaH=Q=*4G}W1=kk(&Fbz^I4Y}CYQVl`?qo!DvORFl-1np$mb+Qxq0sh!O9pZ)Cn z{(Rrh`+nc<)sM_qKQbTFV-XF9Vr5K2;p}OX!=Fx!34anRndOjGD(UHPX<5!{$?g-Z z#q!wfxGDtJeetJ}JXVzO+o*V2EmbRmRg|kG8cs^C0Qvglh0%zP?M)w#3Te<5)Lpu= zSZLR!r;FZR;pwa7S30wtomO$VM{3t?&5AC{;cHW8B02o;soUWBQpShy{9dLT(!P~B zEk*W70YBth+9}DNh}!JrkqiD zKbdn4%y!IhN5gLKim3!3I{y(kt(Kk-Mw}80=S0!ff&%{EExZUmN%JD5&HFovrcIm} z8m?P7)htKeIZ0ZV)D1)cN!u4@BtZNT`6zHTws!e743Jm8g0DI&;yHm^R(=ADhRPu{ zP4-G%f)H3GQtwl~tL=~X-tGlX(;Y?v_1cuKfU4<1n@3`!Y1kaT=eQd~HQ4JiyCjeO zxynw=)GoE#1&dEtG?%Vw7G8WsO}R<7*U_>4HFx8o%pHyHSS-83yNk_Zr0q)tob2v+ z2cDzqGw}3xo`8J~1QNJnXZuR-h{c6MIwOeP-|O6ggn?x`Osj zze7_4il%pqjrnjKmwNd@`1A%J;n7(~NcKR1EduE8TQ zAS>B(0%Z61d~-gVc8HqI>DCnJoU&G>P4Vke2t-XvP}kIMNoMAHREVgtydK?zZL!iO zl*TqHD2_QiXoi{c##pX~G&oGF*eFR7WoH$XlJ4pf%EX9vrOzMI6|T36Wf6l@9+Uwg zKlY#xppDyLG1>TAl%FLo?yd6Kl)F?+VP$LA5K)KcfD7xnIdqI$BZBw0KmzgzdI zeoJmH6*{ffC&88#b8FUj2xUUXp+iUnxOfQ70=Rz&Et|)E)y5XZt%GN0w)7+^M6r1^ zwT+{$f`%W?YF`@+O9@ogc9_RA1`nfL3?+;mMRA;}Gsn>UbP98>3n5)7u!{LsYY{9S z7a~$4X%zi&92oxfB%(32x3{K*S{GBc$Uw(pXi0upzD^##6!4=JQ*utg78Kg*ncmShngsnh(a?&!Zng0~^!cM+GRBW=sB1 zYb%st)P8_=l5wL_(0P4*Pr1&b?72J00R-&7gSPUPo_-${LvH7N6oXQMT4~PQqLnV)YjZUQ zg_=BSEpb>`K?}-Z+y91gjf)S^-b73lc1*yNjjnMx8(1{|y5{l+eY~|4 zf0IR&jbD^wL?Fh=N_+_-zi7t|5c#$pn=Q$-Te1XHpC4|sJf#C}0Pc{WVKeWNY#k5s zIXe=RS@oXt{u&O@Y|^Za_oGM)V)>Kj1T9JbHk)a`D!9 zG8f=i@x%*|lRySQ`Fa950gSNhsU(H9Cll_lJ(-AHW~7mPfG^U>^8lskBpqN~I$4k= z+X9->A*f=d(`xgmTA9o36@u^`1-{dX1~DMsLQa2O2C1A#olsDdOLyhD0zO{MDUd?h z<1hb>FNhyEmkgmv)Fs)M)TwH{sKQ^13r3!uDkRWUOr1yI z-^5_^$O!!7uu_SC?ayJ(7b;Ae=_5tL>}>r{b4DoN&}Nx zaf2ANivMTlUP8hXF!iyd1tir-bdY^8B*xFGNfDpvTdO0;vepoONv&N&e0T!o)#NOd zJbW+I_}yC4#)ng?C2c0z57+FGT4I2}Q%9}<75Bp6HOJ!ATsP#nA@R!v`?WO`eI1k##|}DXrFGc3CC4hVCajc~26Z%;!eM z9i(6a#3(sHX0b0{B&qDH>!xV7?Eon=zTQGIdD~C<0XdWec;Qu2$$cgd5y1oqJ~0yk zmmecNycN$~AbSDo-zCEU!ijMO)JC= x6)J3DI1Fy`x~hkVrYdrZ><{{@AKir4@E delta 2845 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 x6)J3DI1Fy`x~hkVrYdrZ><{{?zAiueEk diff --git a/netbox/project-static/dist/netbox.js.map b/netbox/project-static/dist/netbox.js.map index db0366f6bfeb9a2e54b5a1de6965389c35767c38..1d338086839c579d3d5e36b9e8bb1e8682914ad6 100644 GIT binary patch delta 42 wcmZqvE7Sl)EsQNpTbTWJ^EmtHxH>wA>o_|)M{JMX&FsU&n74h^aps%f08(NQG5`Po delta 45 zcmZqpE7bf~sG)_ig=q`3-)?@#Y$qL8N5^az9cM@9D%b5%yP17>7_+u7KhAvf8vugE B5k~+3 diff --git a/netbox/project-static/dist/status.js b/netbox/project-static/dist/status.js index b60da0a36e2a163ed2b509ca190bff50a7ce5ab9..2f3c2f762197cf133eb790f50336f54e34515843 100644 GIT binary patch delta 2941 zcmZ8jdvH|c6`!*S5s(Bz9uNp&vkB|H*}FFhj{sRNFY`q~lK`Pb*ald#ciHXiBkbP& zLQFy&EL4y(!bL6x8VYH((wPcwJKM*|6f8`&I>sWlcEDn3bpQb=1sNHjzq@&W{&UXW z^FH5s?a7{@Cwqn-smLIvS7z9VCzfW!(}*SB8CIW$uY%0i@TI>sYEmB4#OkoxYOV2T zs!$`Bwn^(Grr#Y^Hi2o_%As0KPm>k!d z6<<8utOX)rAtbhQPt?j4eYO02g zB(_^WBV-!4H2~=+ORfMWN)?c;fBN=hZk_QG!^h==|#X|=XAj3 z&KkgOr&P)$L}U67DPFss!LhfagLQO7q!z^^IHGtGu3vRN21ohwuL1ueS0lHK^1Bv2 zHaTA}n7l$y1Ku*Z0L-4rZZPjpzBLpTx#j9kH~r3S1iUzRc?uRLR?V9_45GUh+9CRf zh1+R3SEBAvlM9I@8lV0<**QFWMVDWx^JsoK8i|KdD1pnZ0k7s4MMarhQGwQ4T(nJJCn%NvT}ZgInRySO{pqy%F1o_b-8IH#g|O{baoDuv4} z=!HOd?bE7Ha}0hh39R*NQriRe(n!k#?)-?RMM6>o*db4JZ6MsQ-1pI^+d9ZJRTmCO z_Nz96yCxF#s!>xl6)w#8QBwMS8PpAm!AQT9-m<6yNgZ5N)x~AMY6hx2?huwBsWwNQ zh?>cPa9E9|#G&76zJ*g*mpL3_TyBZS{DKd|zIB;~n%!TPkN(Ji=3{d{zFfW_mm%bk;&<4b zkrs1aV>T47ZpE>5ZnyKqNOxWq1SbX1LW!=x1uP!DImFRE{|Md0W=iyGD@{w~JbyTo z7ieloiJ(6k_$?4?TmJ@$qVQP&@%@>SBqPG6db+g2- z-KWjK{Ck+d6`$N331X^47-xr=+B_gEkGXl1;&lza;+Z{PVV~*m?XzaFz6l6<)(d9C z-`Tejk!;vs3U<$abamq7{{NUu>6hK}LAu&K3%?x))*;cK9C)S#=+=n>(r=!~N!b3h z-0~=kNUG1LHfz;9vH4VW1`Hg3cbvJu&%SRCczSObFxERin_(W&`D>kCx39^`Fqo%$ zholuDVR^meRhXhEJQDC)E6{KZmGjAMDA>i*P0)Yh!yk_3PGyz5t;reaZ%#1Je|Qee zV`nA;esX3SeCK|2Zv;@zg;07qQ&ia#)aIMB?uoX2(?@Y-%85EKrm*(<=Y^wrv0@9y zLu=HiZ4R%lR|TFp_xTC)?S6V`{Cqxman@jWU}-46PO-W{Gfm6BKoDIn44#Jv!hQ^n zS6$!W!w$WBX{^9RSO0dDqpCOFtUjb9wG8^;x^j6wGJEcF*+~8nJ%p$G-Q_&93Eux= z3Ix)wtN>hjWdkVZu8gyANsnC0)3dIg2H{^<-vjf=wXyj9_BAyVC$+yV>J(hPFSnV= z{rSHru)gX>p5Aa{C2IVu8(Ym|IdESwWlhSW2#)1bH-B!*U;j!d=6GIB)%z6>)x|j~99RiV=a%DH=8!h`O-Plt`8;iIq`#oWAP^}5XLV;LJF#iK_RTNzz z^qn!oVHz>GgUX&je(=JH8hGI;ff$4e&hN!8f)xk z)05EMzL}O;z7c?tvxTl1W&0>EIc6&rnwF;ih(5#0 zNsiw|1?k4)n`m^hb`KpP3lAIHXOhhrx0hOA^ToY%z_4tE=A3lVv{}iTgX-ORetbKI!@_4R?U(NKBeDNE{{p7SY0nS`vXC5R1FKN#FAq!(2vn^ z$)o?K{EUH2lX&W5qcLI?braJAK7kp3yh|Uz-_Cn91;VH9k;{_F6c3iDAi7c#S!5|I oW}Vj3c5mnErcN~&Q>|=vrQI&X6}K$QacOmFJ4-GnOK{Zx0U=cP6aWAK delta 2941 zcmZ8jdvFx>9iQ(dM1mv`@_;}HmrFQzb9n520gI*80R*HJWMqJT_VNJz=li|= zzQ4ck>rVEKJlQw$NM!~wtt!Jpa$+bd=+NBhA-`{u~YMz%GZRHR&%XO zRk&KQtWDS;FzxQx^2tmUHt_9HMU6*8=4P=KTs52$a&DjBaALN`T7YiFm}i)6l2h>3C4 zEqUW1x9SgvxFFxoTv4+uX*PlX4OHoeN4%nQKxMTAGt`%kgzAU^5SYn?A zxYAw=*lQQcn1E;u|3S%PwK6#Nbab$ej<67sT%0Y6Cy}+Q_Q&9;K>Rh}U&I>ZmQiun zq{XHcXob^OX=%XQrWJzOH_Zv={b{#Gq9V5(z3GPE1cnPmG4+Ary*}#a6#Z_3^wUO{=U#Yc)04 zVX~`Xcabc$cRB|7l1B`uin+p&M(`DlC2-f&_}wnq8EBFGu?ANIw~n7*S+lOwNPLYX zixKpKKeYa7#jDzezn1ye`&6Or0eg8k@_@T2tg7Ll&$p z_ny;6V7|RFCre(@9S&fsgBWKUpV~Yitc*G37Rlone#J9;zrsG#-s>@Evw;Z+x;An~ z!{6!Ij7T=^F9W-8Ke{?`a{qsfrS!|*MIc@6or~YL0~?U&PYyg&3Uup4A!#>H*{-89=SFFzu&&5WZ|R^wne>!tM}y& zBe_5S7X{YV+{o7&Z>&a*e|2NKaV&@KE2gYPS{lZ&eCp=U4f*R|aV0XIS5;J>5*;{n zSnl$}HN-`^ZG$cE?K!FU`+7OzxcT)L*k6Bo^gDyx^1K zPFG7u2WKEGb6)UDvfc{;SUoeD*a#;0oJ?O@OgMST9mRA2PpS)M>Kx6adF>$=7ZTzE z(|=>8nU5NjfTH50GX18RL`asE(9eM0E}?E9r-d*>`g0b_19}-T1C1`FVjx>7O-;uc zX8Q6{k`Vo_Qo5K9ryU%Tk#bcp73h)ul&uYH&Jt9jSkNEZLJ7|Kw zM<(AuFs3?s3U(UmNC0ZD!$aeN>c|5FX-`l?mWe6)wQ9=OKeWHcw`oHOBPQw z9EnG;Pm_ngM`9MVKK4@|+;x7RZjFI0^;x5YNuiyZaIW=DU54r8!7e(EJ)3ktPv=RW zv6sf_{okQc`kF0-3D&!|&`Ai(Tj@#Y?%YZ%Oy3AV&)r7X^zt6cPmbSCMTVsrKcdgD za*~sFQ(?OP_!b(MtlLXR$RvmKopZ>dPuxcl*nDvx9nekNp*g>Yjy?j)^+TybRP<2> zmQ}L)720aF)0?l-QIr1aVanF+)d1TM(`1tz(3=iZu0C%qWhdV`Oe4^|djA`=0E#&Y zQiN<4lPsbOe+!vnyvh&$NyjN&j@7W_;!o-Klqbgog|BH4-9CT76IDW-BCzE63-n`j zT=M9@sUTx0(W&MG0BA`%JGhrL^heq oOIWA5tliVOwxv@E#1u1|S7o(wamgu)Vq92T*3ObE$rKp-e}bR-=l}o! diff --git a/netbox/project-static/dist/status.js.map b/netbox/project-static/dist/status.js.map index a249f738055c4ab95e23394f628ef5d480f8c7a7..fc612cec8a4f81a7f991f808e503b36200361804 100644 GIT binary patch delta 38 ucmcb+gyYr{j)pCao!@z!eRNzMox^pU9i1b#&-l*B%fVQ+ec6A;?Lq)9#SZiU delta 41 xcmcb$gyZfKj)pCao!|K#vz>HY9UZe>betWXt6aBF{m#hC!C1C^@qfncLI7Pb5D5SP diff --git a/netbox/project-static/src/device/config.ts b/netbox/project-static/src/device/config.ts index cbe70952e..c9c19e8d3 100644 --- a/netbox/project-static/src/device/config.ts +++ b/netbox/project-static/src/device/config.ts @@ -13,18 +13,26 @@ function initConfig(): void { .then(data => { if (hasError(data)) { createToast('danger', 'Error Fetching Device Config', data.error).show(); + console.error(data.error); + return; + } else if (hasError>(data.get_config)) { + createToast('danger', 'Error Fetching Device Config', data.get_config.error).show(); + console.error(data.get_config.error); return; } else { - const configTypes = [ - 'running', - 'startup', - 'candidate', - ] as (keyof DeviceConfig['get_config'])[]; + const configTypes = ['running', 'startup', 'candidate'] as DeviceConfigType[]; for (const configType of configTypes) { const element = document.getElementById(`${configType}_config`); if (element !== null) { - element.innerHTML = data.get_config[configType]; + const config = data.get_config[configType]; + if (typeof config === 'string') { + // If the returned config is a string, set the element innerHTML as-is. + element.innerHTML = config; + } else { + // If the returned config is an object (dict), convert it to JSON. + element.innerHTML = JSON.stringify(data.get_config[configType], null, 2); + } } } } diff --git a/netbox/project-static/src/global.d.ts b/netbox/project-static/src/global.d.ts index af5819c8e..bad12c795 100644 --- a/netbox/project-static/src/global.d.ts +++ b/netbox/project-static/src/global.d.ts @@ -152,12 +152,15 @@ type LLDPNeighborDetail = { type DeviceConfig = { get_config: { - candidate: string; - running: string; - startup: string; + candidate: string | Record; + running: string | Record; + startup: string | Record; + error?: string; }; }; +type DeviceConfigType = Exclude; + type DeviceEnvironment = { cpu?: { [core: string]: { '%usage': number }; diff --git a/netbox/project-static/src/util.ts b/netbox/project-static/src/util.ts index c3dd05b0e..9103a7b01 100644 --- a/netbox/project-static/src/util.ts +++ b/netbox/project-static/src/util.ts @@ -19,7 +19,9 @@ export function isApiError(data: Record): data is APIError { return 'error' in data && 'exception' in data; } -export function hasError(data: Record): data is ErrorBase { +export function hasError( + data: Record, +): data is E { return 'error' in data; } diff --git a/netbox/utilities/utils.py b/netbox/utilities/utils.py index 32880fca8..d9646f38f 100644 --- a/netbox/utilities/utils.py +++ b/netbox/utilities/utils.py @@ -1,7 +1,9 @@ import datetime import json +import urllib from collections import OrderedDict from itertools import count, groupby +from typing import Any, Dict, List, Tuple from django.core.serializers import serialize from django.db.models import Count, OuterRef, Subquery @@ -286,6 +288,45 @@ def flatten_dict(d, prefix='', separator='.'): return ret +def decode_dict(encoded_dict: Dict, *, decode_keys: bool = True) -> Dict: + """ + Recursively URL decode string keys and values of a dict. + + For example, `{'1%2F1%2F1': {'1%2F1%2F2': ['1%2F1%2F3', '1%2F1%2F4']}}` would + become: `{'1/1/1': {'1/1/2': ['1/1/3', '1/1/4']}}` + + :param encoded_dict: Dictionary to be decoded. + :param decode_keys: (Optional) Enable/disable decoding of dict keys. + """ + + def decode_value(value: Any, _decode_keys: bool) -> Any: + """ + Handle URL decoding of any supported value type. + """ + # Decode string values. + if isinstance(value, str): + return urllib.parse.unquote(value) + # Recursively decode each list item. + elif isinstance(value, list): + return [decode_value(v, _decode_keys) for v in value] + # Recursively decode each tuple item. + elif isinstance(value, Tuple): + return tuple(decode_value(v, _decode_keys) for v in value) + # Recursively decode each dict key/value pair. + elif isinstance(value, dict): + # Don't decode keys, if `decode_keys` is false. + if not _decode_keys: + return {k: decode_value(v, _decode_keys) for k, v in value.items()} + return {urllib.parse.unquote(k): decode_value(v, _decode_keys) for k, v in value.items()} + return value + + if not decode_keys: + # Don't decode keys, if `decode_keys` is false. + return {k: decode_value(v, decode_keys) for k, v in encoded_dict.items()} + + return {urllib.parse.unquote(k): decode_value(v, decode_keys) for k, v in encoded_dict.items()} + + # Taken from django.utils.functional (<3.0) def curry(_curried_func, *args, **kwargs): def _curried(*moreargs, **morekwargs):