{"id":303383,"date":"2020-05-11T21:00:09","date_gmt":"2020-05-11T21:00:09","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=303383"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=303383","title":{"rendered":"\u0412\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u0435\u0442\u0435\u0432\u044b\u0445 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0439, \u0438\u043b\u0438 \u0437\u0430\u0447\u0435\u043c \u0435\u0449\u0435 \u0441\u0435\u0442\u0435\u0432\u043e\u043c\u0443 \u0438\u043d\u0436\u0435\u043d\u0435\u0440\u0443 Python #2"},"content":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/501164\/\">\n<p>\u041f\u0440\u0438\u0432\u0435\u0442 \u0425\u0430\u0431\u0440! \u042d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0430 \u043f\u043e \u043c\u043e\u0442\u0438\u0432\u0430\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u043d\u0438\u044f \u043d\u0430 \u043d\u0435\u0434\u0430\u0432\u043d\u043e \u043f\u0440\u043e\u0448\u0435\u0434\u0448\u0435\u043c <a href=\"https:\/\/rrc.ru\/events\/onlajn-devnet-marafon-ot-cisco\" rel=\"nofollow\">\u043e\u043d\u043b\u0430\u0439\u043d-\u043c\u0430\u0440\u0430\u0444\u043e\u043d\u0435 DevNet<\/a> \u043e\u0442 Cisco. \u0423\u0447\u0430\u0441\u0442\u043d\u0438\u043a\u0430\u043c \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u043b\u043e\u0441\u044c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0430\u043d\u0430\u043b\u0438\u0437 \u0438 \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u043e\u0439 \u0441\u0435\u0442\u0435\u0432\u043e\u0439 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u0438, \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e, \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0438\u0445 \u0432 \u043d\u0435\u0439 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439. <br \/>  \u0417\u0430\u0434\u0430\u0447\u0430 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0435 \u0441\u0430\u043c\u043e\u0439 \u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u043e\u0439, \u0438 \u0432 \u0431\u043b\u043e\u0433\u043e\u0441\u0444\u0435\u0440\u0435 \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u0435\u0442\u0441\u044f \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043c\u0430\u043b\u043e \u0441\u0442\u0430\u0442\u0435\u0439 \u043d\u0430 \u044d\u0442\u0443 \u0442\u0435\u043c\u0443. \u041d\u0438\u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e \u0440\u0430\u0437\u0431\u043e\u0440 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0445 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0438 \u043f\u043e\u0434\u0445\u043e\u0434\u043e\u0432. <\/p>\n<p>  \u0412\u0441\u0435\u043c \u0437\u0430\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043e\u0432\u0430\u0432\u0448\u0438\u043c\u0441\u044f \u0434\u043e\u0431\u0440\u043e \u043f\u043e\u0436\u0430\u043b\u043e\u0432\u0430\u0442\u044c \u043f\u043e \u043a\u0430\u0442!<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/5h\/zi\/p1\/5hzip10y5vl8l71jpwwfmqp-xes.png\"><\/p>\n<p><a name=\"habracut\"><\/a>  <\/p>\n<hr>\n<p>  <\/p>\n<blockquote><p>*\u0418 <s>\u043d\u0435<\/s>\u043c\u043d\u043e\u0433\u043e Javascript.<\/p><\/blockquote>\n<p>  <\/p>\n<h3 id=\"diskleymer\">\u0414\u0438\u0441\u043a\u043b\u0435\u0439\u043c\u0435\u0440<\/h3>\n<p>  <\/p>\n<blockquote><p>\u0414\u0430\u043d\u043d\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u043d\u0435 \u043f\u0440\u0435\u0442\u0435\u043d\u0434\u0443\u0435\u0442 \u043d\u0430 \u0432\u0441\u0435\u043e\u0431\u0449\u0438\u0439 \u043e\u0445\u0432\u0430\u0442 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430\u0442\u0438\u043a\u0438 \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u0435\u0442\u0435\u0439, \u043d\u043e \u043f\u0440\u0438 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u0447\u0430\u0441\u0442\u043d\u043e\u0433\u043e \u0441\u043b\u0443\u0447\u0430\u044f \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u0443\u0435\u0442\u0441\u044f \u0438 \u043e\u0431\u0449\u0438\u043c\u0438 \u0441\u043e\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f\u043c\u0438.<br \/>  \u0412\u0441\u0435 \u043d\u0438\u0436\u0435\u0441\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0435 \u0438 \u0432\u044b\u0448\u0435\u0441\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043b\u0438\u0447\u043d\u044b\u043c \u043e\u0446\u0435\u043d\u043e\u0447\u043d\u044b\u043c \u0441\u0443\u0436\u0434\u0435\u043d\u0438\u0435\u043c \u0430\u0432\u0442\u043e\u0440\u0430, \u0435\u0441\u043b\u0438 \u043d\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u043e \u043e\u0431\u0440\u0430\u0442\u043d\u043e\u0435.<br \/>  \u041f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u0434 \u043b\u0438\u0446\u0435\u043d\u0437\u0438\u0435\u0439 <a href=\"https:\/\/github.com\/iDebugAll\/devnet_marathon_endgame\/blob\/master\/LICENSE\" rel=\"nofollow\">MIT<\/a> \u0438 \u043d\u0435 \u0434\u0430\u0435\u0442 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0439 \u043d\u0438\u043a\u0430\u043a\u043e\u0433\u043e \u0440\u043e\u0434\u0430.<\/p>\n<p>  \u041e\u0431\u0441\u0443\u0436\u0434\u0435\u043d\u0438\u0435 \u0438 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u0438\u0432\u043d\u0430\u044f \u043a\u0440\u0438\u0442\u0438\u043a\u0430 \u0432\u0441\u044f\u0447\u0435\u0441\u043a\u0438 \u043f\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0442\u0441\u044f.<\/p>\n<p>  \u0415\u0441\u043b\u0438 \u0432\u044b \u0437\u0430\u043c\u0435\u0442\u0438\u043b\u0438 \u043e\u043f\u0435\u0447\u0430\u0442\u043a\u0443, \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435\u0441\u044c \u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u0435\u0439 Ctrl+Enter \u0438\u043b\u0438 \u2318+Enter \u0434\u043b\u044f \u0435\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0430\u0432\u0442\u043e\u0440\u0443.<\/p><\/blockquote>\n<p>  <\/p>\n<h1 id=\"postanovka-zadachi\">\u041f\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0437\u0430\u0434\u0430\u0447\u0438<\/h1>\n<p>  <\/p>\n<p>\u0412 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u043c \u0432\u0438\u0434\u0435 \u0437\u0430\u0434\u0430\u043d\u0438\u0435 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<p>  <\/p>\n<blockquote><p>\u0418\u043c\u0435\u0435\u0442\u0441\u044f \u0441\u0435\u0442\u044c, \u0441\u043e\u0441\u0442\u043e\u044f\u0449\u0430\u044f \u0438\u0437 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 L2\/L3 \u0441\u0435\u0442\u0435\u0432\u044b\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u043f\u043e\u0434 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u043c IOS\/IOSXE. \u0418\u0437\u0432\u0435\u0441\u0442\u0435\u043d \u0441\u043f\u0438\u0441\u043e\u043a IP-\u0430\u0434\u0440\u0435\u0441\u043e\u0432 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432, \u0432\u0441\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u043f\u043e IP, \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0435\u0441\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u0434\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f show-\u043a\u043e\u043c\u0430\u043d\u0434. \u0414\u043b\u044f \u0432\u0430\u0441 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u043b\u044e\u0431\u044b\u0435 \u0441\u043f\u043e\u0441\u043e\u0431\u044b \u0441\u0431\u043e\u0440\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438, \u043d\u043e \u043f\u043e\u0432\u0435\u0440\u044c\u0442\u0435, \u0432\u0430\u043c \u0432\u0440\u044f\u0434 \u043b\u0438 \u043d\u0443\u0436\u0435\u043d SNMP. \u0425\u043e\u0442\u044f \u043c\u044b \u043d\u0435 \u0432 \u043f\u0440\u0430\u0432\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0432\u0430\u0442\u044c \u0432\u0430\u0448\u0443 \u0444\u0430\u043d\u0442\u0430\u0437\u0438\u044e. <\/p>\n<p>  \u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430: \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0444\u0438\u0437\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u044e \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0439 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u043f\u043e LLDP \u0438 \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0435 \u0432 \u0443\u0434\u043e\u0431\u043d\u043e\u043c \u0434\u043b\u044f \u0432\u043e\u0441\u043f\u0440\u0438\u044f\u0442\u0438\u044f \u0447\u0435\u043b\u043e\u0432\u0435\u043a\u043e\u043c \u0432\u0438\u0434\u0435 (\u0434\u0430, \u043d\u0430\u043c \u0432\u0441\u0435\u043c \u0443\u0434\u043e\u0431\u043d\u044b \u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0441\u0445\u0435\u043c\u044b). \u0412\u044b\u0431\u0440\u0430\u0442\u044c \u0444\u043e\u0440\u043c\u0430\u0442 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043e \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u0432 \u0443\u0434\u043e\u0431\u043d\u043e\u043c \u0434\u043b\u044f \u043c\u0430\u0448\u0438\u043d\u043d\u043e\u0433\u043e \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \u0432\u0438\u0434\u0435 (\u0434\u0430, \u043c\u0430\u0448\u0438\u043d\u0430\u043c \u043d\u0435\u0443\u0434\u043e\u0431\u043d\u044b \u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0441\u0445\u0435\u043c\u044b).<\/p>\n<p>  \u041d\u0430 \u0440\u0438\u0441\u0443\u043d\u043a\u0435 c \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0435\u0439 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u044b:<br \/>  \u2022 \u041f\u0438\u043a\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 (\u043a\u043e\u043c\u043c\u0443\u0442\u0430\u0442\u043e\u0440\u044b \u0438 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0442\u043e\u0440\u044b \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043e\u0442\u043c\u0435\u0447\u0435\u043d\u044b \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u043c \u0442\u0438\u043f\u043e\u043c \u043f\u0438\u043a\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u044b).<br \/>  \u2022 Hostname \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430.<br \/>  \u2022 \u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 (\u043c\u043e\u0436\u043d\u043e \u0432 \u0441\u043e\u043a\u0440\u0430\u0449\u0451\u043d\u043d\u043e\u043c \u0444\u043e\u0440\u043c\u0430\u0442\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432\u043c\u0435\u0441\u0442\u043e GigabitEthernet0\/0 \u2014 G0\/0).<\/p>\n<p>  \u0414\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432, \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0432\u0430\u044e\u0449\u0438\u0445 (\u0441\u043a\u0440\u044b\u0432\u0430\u044e\u0449\u0438\u0445) \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e.<br \/>  \u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430: \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 (\u0441\u0440\u0430\u0432\u043d\u0438\u0432 \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u0438 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u0438) \u0438 \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u0432 \u0443\u0434\u043e\u0431\u043d\u043e\u043c \u0434\u043b\u044f \u0432\u043e\u0441\u043f\u0440\u0438\u044f\u0442\u0438\u044f \u0447\u0435\u043b\u043e\u0432\u0435\u043a\u043e\u043c \u0432\u0438\u0434\u0435. <\/p><\/blockquote>\n<p>\u041d\u0430 \u0432\u0445\u043e\u0434\u0435 \u2014 IP-\u0430\u0434\u0440\u0435\u0441\u0430 \u0438 \u0443\u0447\u0435\u0442\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043d\u0430 \u043e\u0431\u043e\u0440\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u0435, \u043d\u0430 \u0432\u044b\u0445\u043e\u0434\u0435 \u2014 \u0433\u043e\u0442\u043e\u0432\u0430\u044f \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u044f. \u041e\u0433\u0440\u043e\u043c\u043d\u043e\u0435 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u0434\u043b\u044f \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u043e\u0432 \u0438 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u0433\u0434\u0435-\u0442\u043e \u043f\u043e\u0441\u0435\u0440\u0435\u0434\u0438\u043d\u0435.<\/p>\n<p>  \u0414\u043b\u044f \u0441\u0435\u0431\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u0432\u0435\u043b \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0434\u0438\u0440\u0435\u043a\u0442\u0438\u0432\u044b \u0434\u043b\u044f \u0432\u044b\u0431\u043e\u0440\u0430 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u0424\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c vs \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u0430.<br \/>  \u0414\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0441\u043e\u0431\u043b\u044e\u0434\u0435\u043d \u0431\u0430\u043b\u0430\u043d\u0441 \u043c\u0435\u0436\u0434\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u044e \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0438 \u0435\u0433\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u043e\u0439. \u0414\u043b\u044f \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f\u0430 \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0447\u0430\u0441\u0442\u044c \u0433\u043e\u0442\u043e\u0432\u044b\u0445 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u044f\u0435\u043c\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u0439.<\/li>\n<li>\u041d\u0430\u043b\u0438\u0447\u0438\u0435 \u043e\u043f\u044b\u0442\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043d\u0430\u0438\u0431\u043e\u043b\u044c\u0448\u0435\u0439 \u0447\u0430\u0441\u0442\u044c\u044e \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432.<br \/>  \u041d\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0431\u044b\u043b\u043e \u0442\u0440\u043e\u0435 \u0441\u0443\u0442\u043e\u043a, \u043e\u0434\u043d\u0438 \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0443 \u043c\u0435\u043d\u044f \u0432\u044b\u043f\u0430\u043b\u0438 \u043f\u043e \u043d\u0435\u043e\u0442\u043b\u043e\u0436\u043d\u044b\u043c \u0434\u0435\u043b\u0430\u043c. \u0427\u0442\u043e\u0431\u044b \u0443\u043b\u043e\u0436\u0438\u0442\u044c\u0441\u044f \u0432 \u0441\u0440\u043e\u043a\u0438 \u0438 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435, \u0436\u0435\u043b\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0431\u044b\u043b\u043e \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u043a\u0430\u043a\u0443\u044e-\u0442\u043e \u0447\u0430\u0441\u0442\u044c \u0443\u0436\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u044b\u0445 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432.<\/li>\n<li>\u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u044f.<br \/>  \u0417\u0430\u0434\u0430\u0447\u0430 \u0432\u043f\u043e\u043b\u043d\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043c\u0430 \u043a\u043e \u043c\u043d\u043e\u0433\u0438\u043c \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u043d\u0430\u043c, \u0441\u0442\u043e\u0438\u0442 \u044d\u0442\u043e \u0443\u0447\u0435\u0441\u0442\u044c.<\/li>\n<li>\u041c\u0443\u043b\u044c\u0442\u0438\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435\u043d\u043d\u043e\u0441\u0442\u044c. <br \/>  \u041a\u0430\u043a \u0441\u0442\u043e\u0438\u0442 \u0443\u0447\u0435\u0441\u0442\u044c \u0438 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u0440\u0430\u0437\u043d\u044b\u0445 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438.<\/li>\n<li>\u041d\u0430\u043b\u0438\u0447\u0438\u0435 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u043a \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u043c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u043c \u0432 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u0435.<br \/>  \u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0435 \u043a \u043b\u044e\u0431\u043e\u043c\u0443 \u043d\u0435\u043e\u0434\u043d\u043e\u0440\u0430\u0437\u043e\u0432\u043e\u043c\u0443 \u0440\u0435\u0448\u0435\u043d\u0438\u044e.<\/li>\n<\/ul>\n<p>  <\/p>\n<h1 id=\"gotovye-produkty\">\u0413\u043e\u0442\u043e\u0432\u044b\u0435 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u044b<\/h1>\n<p>  <\/p>\n<p>\u041f\u0435\u0440\u0435\u0434 \u0438\u0437\u043e\u0431\u0440\u0435\u0442\u0435\u043d\u0438\u0435\u043c \u0432\u0435\u043b\u043e\u0441\u0438\u043f\u0435\u0434\u0430 \u0432\u0441\u0435\u0433\u0434\u0430 \u0441\u0442\u043e\u0438\u0442 \u043f\u043e\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043e\u0432\u0430\u0442\u044c\u0441\u044f, \u043d\u0435 \u0440\u0435\u0448\u0435\u043d\u0430 \u043b\u0438 \u0437\u0430\u0434\u0430\u0447\u0430 \u0434\u043e \u043d\u0430\u0441. \u0412\u043e\u0442 \u0432 <a href=\"https:\/\/habr.com\/ru\/post\/444410\/\">\u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043d\u0430 \u0425\u0430\u0431\u0440\u0435<\/a> \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0445\u043e\u0440\u043e\u0448\u043e \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u044b \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u044b \u0434\u043b\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u0441\u0435\u0442\u0435\u0432\u044b\u0445 \u043a\u0430\u0440\u0442. \u041e\u0436\u0438\u0434\u0430\u0435\u043c\u043e, \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0435\u0433\u043e, \u0430 \u043c\u043e\u0434\u0443\u043b\u0438 \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u0438\u0434\u0443\u0442 \u043a\u0430\u043a \u0441\u043e\u0441\u0442\u0430\u0432\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433\u0430, \u0447\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u043c\u0435\u043d\u044c\u0448\u0430\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0438 \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0430\u0446\u0438\u0438.<\/p>\n<p>  <\/p>\n<h1 id=\"dekompoziciya-zadachi-i-vybor-instrumentov\">\u0414\u0435\u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446\u0438\u044f \u0437\u0430\u0434\u0430\u0447\u0438 \u0438 \u0432\u044b\u0431\u043e\u0440 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432<\/h1>\n<p>  <\/p>\n<p>\u0410\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443 \u043d\u0430 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0441\u0435\u0442\u0435\u0432\u044b\u0445 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0439 \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0443\u0440\u043e\u0432\u043d\u0438 \u0438 \u044d\u0442\u0430\u043f\u044b:<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/aw\/2a\/ze\/aw2azeunzwyyrjncffz3j9zrf6o.png\" alt=\"high_level\"><\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u043e\u0439\u0434\u0435\u043c\u0441\u044f \u043f\u043e \u043d\u0438\u043c \u0441\u043d\u0438\u0437\u0443 \u0432\u0432\u0435\u0440\u0445 \u0441 \u043e\u0433\u043b\u044f\u0434\u043a\u043e\u0439 \u043d\u0430 \u0438\u043c\u0435\u044e\u0449\u0438\u0435\u0441\u044f \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<ol>\n<li><b>\u0421\u0435\u0442\u0435\u0432\u043e\u0435 \u043e\u0431\u043e\u0440\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u0435.<\/b><br \/>  \u041f\u043e \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u043c \u043d\u0443\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 IOS \u0438 IOS-XE.<br \/>  \u041d\u043e \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c <s>\u0437\u043e\u043e\u043f\u0430\u0440\u043a<\/s> \u043d\u0430\u043c\u043d\u043e\u0433\u043e \u0431\u043e\u043b\u0435\u0435 \u0433\u0435\u0442\u0435\u0440\u043e\u0433\u0435\u043d\u043d\u0430\u044f \u0441\u0435\u0442\u044c. \u041f\u043e\u0441\u0442\u0430\u0440\u0430\u0435\u043c\u0441\u044f \u044d\u0442\u043e \u0443\u0447\u0435\u0441\u0442\u044c.   <\/li>\n<li><b>\u0418\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u043e \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438.<\/b><br \/>  \u0412 \u0437\u0430\u0434\u0430\u043d\u0438\u0438 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b <a href=\"https:\/\/en.wikipedia.org\/wiki\/Link_Layer_Discovery_Protocol\" rel=\"nofollow\">LLDP<\/a> (Link Layer Discovery Protocol), \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439, \u043a\u0430\u043a \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0438\u0437 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f, \u043d\u0430 \u043a\u0430\u043d\u0430\u043b\u044c\u043d\u043e\u043c \u0443\u0440\u043e\u0432\u043d\u0435 (L2) \u0432 \u043c\u043e\u0434\u0435\u043b\u0438 <a href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%A1%D0%B5%D1%82%D0%B5%D0%B2%D0%B0%D1%8F_%D0%BC%D0%BE%D0%B4%D0%B5%D0%BB%D1%8C_OSI\" rel=\"nofollow\">OSI<\/a>. \u042d\u0442\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b, \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u0432 IEEE 802.1AB. \u041f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e\u043c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u0435\u0439 \u0441\u0435\u0442\u0435\u0432\u043e\u0433\u043e \u043e\u0431\u043e\u0440\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u043c\u0438 \u043d\u0430 Linux \u0438 Windows, \u0447\u0442\u043e \u043d\u0430\u043c \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442.<br \/>  \u041f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u043c\u043e\u0436\u0435\u0442 \u0442\u0430\u043a\u0436\u0435 \u0431\u044b\u0442\u044c \u043e\u0431\u043e\u0433\u0430\u0449\u0435\u043d\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439 \u0438\u0437 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0434\u043b\u044f \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u0432\u044b\u0432\u043e\u0434\u043e\u0432 \u0442\u0430\u0431\u043b\u0438\u0446 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446\u0438\u0438, \u043a\u043e\u043c\u043c\u0443\u0442\u0430\u0446\u0438\u0438, \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u043e\u0432 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u0442.\u0434. \u041e\u0441\u0442\u0430\u0432\u0438\u043c \u044d\u0442\u043e \u043d\u0430 \u0431\u0443\u0434\u0443\u0449\u0435\u0435.  <\/li>\n<li><b>\u041f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u044b \u0438 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u0434\u043e\u0441\u0442\u0443\u043f\u0430.<\/b><br \/>  \u041d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u043d\u043e\u0432\u044b\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0438 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442 \u043a\u0440\u0430\u0441\u0438\u0432\u044b\u0435 \u0438 \u043c\u043e\u0434\u043d\u044b\u0435 <a href=\"https:\/\/en.wikipedia.org\/wiki\/NETCONF\" rel=\"nofollow\">NETCONF<\/a>, REST API, \u0434\u0430 <a href=\"https:\/\/www.cisco.com\/c\/en\/us\/td\/docs\/ios-xml\/ios\/prog\/configuration\/169\/b_169_programmability_cg\/restconf_programmable_interface.html\" rel=\"nofollow\">RESTCONF<\/a> \u0441 <a href=\"https:\/\/en.wikipedia.org\/wiki\/YANG\" rel=\"nofollow\">YANG<\/a> \u043c\u043e\u0434\u0435\u043b\u044f\u043c\u0438 \u0438 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u0445. \u041d\u043e \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u043b\u0435\u0433\u0430\u0441\u0438 \u0434\u0438\u043a\u0442\u0443\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f SSH, Telnet \u0438 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0433\u043e <a href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%98%D0%BD%D1%82%D0%B5%D1%80%D1%84%D0%B5%D0%B9%D1%81_%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D0%BD%D0%BE%D0%B9_%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B8\" rel=\"nofollow\">CLI<\/a>.<\/li>\n<li><b>\u041f\u0440\u043e\u0442\u043e\u043a\u043e\u043b- \u0438 \u0432\u0435\u043d\u0434\u043e\u0440-\u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u043d\u044b\u0435 \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u044b\/\u043f\u043b\u0430\u0433\u0438\u043d\u044b.<\/b><br \/>  \u041a\u0430\u043a \u0438 \u043e\u0431\u0435\u0449\u0430\u0435\u0442 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0441\u0442\u0430\u0442\u044c\u0438, \u043e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u043b\u043e\u0433\u0438\u043a\u0438 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0430 \u043d\u0430 Python, \u0442.\u043a. \u043e\u043d \u043e\u0431\u043b\u0430\u0434\u0430\u0435\u0442 \u0440\u0430\u0437\u0432\u0438\u0442\u043e\u0439 \u044d\u043a\u043e\u0441\u0438\u0441\u0442\u0435\u043c\u043e\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0441\u0435\u0442\u0435\u0432\u044b\u043c \u043e\u0431\u043e\u0440\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u0435\u043c, \u0438 \u0441 \u043d\u0438\u043c \u0443 \u043c\u0435\u043d\u044f \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043d\u0430\u0438\u0431\u043e\u043b\u044c\u0448\u0438\u0439 \u043e\u043f\u044b\u0442. <br \/>  \u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 API \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c <b>requests<\/b> \u043b\u0438\u0431\u043e \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0435 \u043c\u043e\u0434\u0443\u043b\u0438.<br \/>  \u0414\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u043e\u0431\u043e\u0440\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u044e \u0447\u0435\u0440\u0435\u0437 SSH\/Telnet \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u044b \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0438 <b>netmiko<\/b>, <b>scrapli<\/b>, <b>paramiko<\/b>. \u041e\u043d\u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u044d\u043c\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c CLI \u0438\u0437 Python \u2014 \u0442.\u0435. \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043d\u0430 \u043e\u0431\u043e\u0440\u0443\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0432 \u043e\u0442\u0432\u0435\u0442 \u043d\u0430 \u043d\u0438\u0445, \u043a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0439 \u0432\u044b\u0432\u043e\u0434 \u0442\u043e\u0439 \u0438\u043b\u0438 \u0438\u043d\u043e\u0439 \u0441\u0442\u0435\u043f\u0435\u043d\u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0441\u0442\u0438 \u0438 \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u043e\u0441\u0442\u0438.<br \/>  \u0422\u0430\u043a\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0431\u043e\u043b\u0435\u0435 \u0432\u044b\u0441\u043e\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0445 \u0441\u0435\u0442\u0435\u0432\u044b\u0445 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432, \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e\u0449\u0438\u0445 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043d\u0430\u0434 \u0443\u0436\u0435 \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u044b\u043c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u043c. \u041a \u0438\u0445 \u0447\u0438\u0441\u043b\u0443 \u043c\u043e\u0436\u043d\u043e \u043e\u0442\u043d\u0435\u0441\u0442\u0438 <a href=\"https:\/\/napalm.readthedocs.io\/en\/latest\/\" rel=\"nofollow\">NAPALM<\/a> \u0438 <a href=\"https:\/\/nornir.readthedocs.io\/en\/latest\/\" rel=\"nofollow\">Nornir<\/a>. NAPALM \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u0435\u043d\u0434\u043e\u0440-\u043d\u0435\u0439\u0442\u0440\u0430\u043b\u044c\u043d\u044b\u0435 <a href=\"https:\/\/napalm.readthedocs.io\/en\/latest\/support\/\" rel=\"nofollow\">GETTER<\/a>&#8216;\u044b \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u0442\u0438\u043f\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u043e\u0431\u043e\u0440\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u044f, \u0432\u043a\u043b\u044e\u0447\u0430\u044f LLDP. Nornir \u0436\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0438 \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u0442\u043e\u0447\u043d\u043e\u0441\u0442\u0438 \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438. <br \/>  SNMP \u043e\u0441\u0442\u0430\u0432\u0438\u043c \u0431\u043e\u043b\u0435\u0435 \u0442\u0440\u0430\u0434\u0438\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u043d\u0435\u0433\u043e \u0437\u0430\u0434\u0430\u0447\u0438 \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433\u0430.<\/li>\n<li><b>\u041d\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 -&gt; \u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u043d\u043e\u0440\u043c\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 -&gt; \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435.<\/b><br \/>  \u0414\u043e\u0441\u0442\u0443\u043f \u0447\u0435\u0440\u0435\u0437 API \u043e\u0431\u044b\u0447\u043d\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0443\u0436\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0432\u044b\u0432\u043e\u0434, \u043d\u043e \u0432\u043e\u0442 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0439 \u0432\u044b\u0432\u043e\u0434, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c\u044b\u0439 \u0447\u0435\u0440\u0435\u0437 CLI \u043e\u0442 \u0441\u0435\u0442\u0435\u0432\u044b\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0435\u043f\u0440\u0438\u0433\u043e\u0434\u043d\u044b\u043c \u0434\u043b\u044f \u043f\u0440\u044f\u043c\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u0414\u043b\u044f \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0442\u0440\u0430\u0434\u0438\u0446\u0438\u043e\u043d\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c <b>re<\/b> \u0438 \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u044b\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f. \u0411\u043e\u043b\u0435\u0435 \u043d\u043e\u0432\u044b\u043c \u043f\u043e\u0434\u0445\u043e\u0434\u043e\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a <a href=\"https:\/\/pyneng.readthedocs.io\/ru\/latest\/book\/22_textfsm\/\" rel=\"nofollow\">TextFSM<\/a> \u043e\u0442 Google \u0441 \u0431\u043e\u043b\u0435\u0435 \u0443\u0434\u043e\u0431\u043d\u044b\u043c\u0438 \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0448\u0430\u0431\u043b\u043e\u043d\u0430\u043c\u0438.<br \/>  \u0423\u0436\u0435 \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u044b\u0439 \u0432\u044b\u0448\u0435 NAPALM \u0434\u043b\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u044b\u0445 GETTER&#8217;\u043e\u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 \u0432\u0441\u044e \u044d\u0442\u0443 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0443 \u0432\u043d\u0443\u0442\u0440\u0438 \u0441\u0435\u0431\u044f \u0438 \u043d\u0430 \u0432\u044b\u0445\u043e\u0434\u0435 \u043e\u0442\u0434\u0430\u0435\u0442 \u0443\u0436\u0435 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0432\u044b\u0432\u043e\u0434, \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u0431\u043b\u0435\u0433\u0447\u0438\u0442\u044c \u0437\u0430\u0434\u0430\u0447\u0443.<\/li>\n<li><b>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u0432 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430\u0445 \u0434\u0430\u043d\u043d\u044b\u0445. <\/b><br \/>  \u0418\u043c\u0435\u044f \u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u0441\u043e \u0432\u0441\u0435\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432, \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u0438\u0445 \u043a \u043e\u0431\u0449\u0435\u043c\u0443 \u0432\u0438\u0434\u0443, \u043f\u0440\u043e\u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438 \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0438\u0442\u043e\u0433\u043e\u0432\u044b\u0439 \u043f\u0430\u0437\u043b.<\/li>\n<li><b>\u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430 \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438.<\/b><br \/>  \u0412 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0432\u044b\u0431\u043e\u0440\u0430 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430 \u0434\u043b\u044f \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0438\u0442\u043e\u0433\u043e\u0432\u043e\u0439 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442 \u0434\u0430\u043d\u043d\u044b\u0445, \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u043c\u044b\u0439 \u0438\u043c \u043d\u0430 \u0432\u0445\u043e\u0434.<\/li>\n<li><b>\u0414\u0432\u0438\u0436\u043e\u043a \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438<\/b><br \/>  \u0421\u0430\u043c\u044b\u0439 \u043d\u0435\u043e\u0447\u0435\u0432\u0438\u0434\u043d\u044b\u0439 \u0434\u043b\u044f \u043c\u0435\u043d\u044f \u043f\u0443\u043d\u043a\u0442, \u0440\u0430\u043d\u044c\u0448\u0435 \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u043e\u043f\u044b\u0442\u0430 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043d\u0435 \u0431\u044b\u043b\u043e. \u0418\u0437\u0443\u0447\u0435\u043d\u0438\u0435 \u0433\u0443\u0433\u043b\u0430 \u0438 \u0441\u043e\u0432\u0435\u0442\u044b \u043a\u043e\u043b\u043b\u0435\u0433 \u043d\u0430\u043c\u0435\u0442\u0438\u043b\u0438 \u043f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 \u043f\u043e\u0434 Python (pygraphviz, matplotlib, networkx) \u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0438 \u043f\u043e\u0434 JS D3.js, vis.js. \u0410 \u0432 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u0437\u0430\u043c\u0435\u0442\u043a\u0430\u0445 \u043d\u0430 \u043f\u043e\u043b\u044f\u0445 \u043d\u0430\u0448\u0435\u043b\u0441\u044f JS+HTML5 Toolkit <a href=\"https:\/\/developer.cisco.com\/site\/neXt\/\" rel=\"nofollow\">NeXt UI<\/a>, \u0432\u0438\u0434\u0435\u043d\u043d\u044b\u0439 \u0440\u0430\u043d\u0435\u0435 \u043d\u0430 \u043f\u0440\u043e\u0441\u0442\u043e\u0440\u0430\u0445 \u043b\u0430\u0431 Cisco DevNet \u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u044b\u0439 \u0438\u043c\u0438 \u0436\u0435. \u041e\u043d \u043d\u0435\u043f\u043b\u043e\u0445\u043e <a href=\"https:\/\/github.com\/NeXt-UI\/next-tutorials\" rel=\"nofollow\">\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d<\/a>, \u0437\u0430\u0442\u043e\u0447\u0435\u043d \u043d\u0430 \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0441\u0435\u0442\u0435\u0439 \u0438 \u0443\u043c\u0435\u0435\u0442 \u043c\u043d\u043e\u0433\u043e\u0435 \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438.<\/li>\n<li><b>\u0412\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u044f<\/b><br \/>  \u041d\u0430\u0448\u0430 \u043a\u043e\u043d\u0435\u0447\u043d\u0430\u044f \u0446\u0435\u043b\u044c. \u041c\u043e\u0436\u0435\u0442 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0438\u0437 \u0441\u0435\u0431\u044f \u043a\u0430\u043a \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0438\u043b\u0438 HTML-\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442, \u0442\u0430\u043a \u0438 \u0447\u0442\u043e-\u0442\u043e \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u043e\u0435 \u0438 \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0435.<\/li>\n<\/ol>\n<p>  <\/p>\n<p>\u0421\u0443\u043c\u043c\u0438\u0440\u0443\u044f, \u0434\u0430\u043b\u0435\u043a\u043e \u043d\u0435 \u043f\u043e\u043b\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432:<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/jk\/v7\/a1\/jkv7a1wlcznhgvjvc0u43fpzora.png\" alt=\"detailed\"><\/p>\n<p>  <\/p>\n<p>\u0412 \u0438\u0442\u043e\u0433\u0435 \u0432\u044b\u0431\u043e\u0440 \u043f\u0430\u043b \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0441\u0442\u0435\u043a:<\/p>\n<p>  <\/p>\n<ul>\n<li>LLDP \u043a\u0430\u043a \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438.<\/li>\n<li>SSH \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043d\u0430 \u043e\u0431\u043e\u0440\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u0435.<\/li>\n<li><a href=\"https:\/\/nornir.readthedocs.io\/en\/latest\/\" rel=\"nofollow\">Nornir<\/a> \u0434\u043b\u044f \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u0442\u043e\u0447\u043d\u043e\u0441\u0442\u0438, \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u0438 \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u0431 \u043e\u0431\u043e\u0440\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u0438 \u0432 inventory.<\/li>\n<li><a href=\"https:\/\/napalm.readthedocs.io\/en\/latest\/\" rel=\"nofollow\">NAPALM<\/a> \u0434\u043b\u044f \u0430\u0431\u0441\u0442\u0440\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u0442 \u0437\u0430\u0434\u0430\u0447 \u0440\u0443\u0447\u043d\u043e\u0433\u043e \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430 CLI.<\/li>\n<li>Python3 \u0434\u043b\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438.<\/li>\n<li><a href=\"https:\/\/developer.cisco.com\/site\/neXt\/\" rel=\"nofollow\">NeXt UI<\/a> (JS+HTML5) \u0434\u043b\u044f \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u0447\u0435\u0440\u0435\u0437 Python \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>NAPALM \u0438 Nornir \u0434\u043e \u044d\u0442\u043e\u0433\u043e \u0443\u0436\u0435 \u0434\u043e\u0432\u043e\u0434\u0438\u043b\u043e\u0441\u044c \u0432\u043f\u043e\u043b\u043d\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0437\u0430\u0434\u0430\u0447 \u0441\u0435\u0442\u0435\u0432\u043e\u0433\u043e \u0430\u0443\u0434\u0438\u0442\u0430 \u0441\u043e \u0441\u0431\u043e\u0440\u043e\u043c \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0441\u043e\u0442\u0435\u043d \u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432. NAPALM \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438 \u0443\u043c\u0435\u0435\u0442 \u0432 LLDP \u043d\u0430 Cisco IOS\/IOSXE, IOS-XR, NX-OS, Juniper JunOS \u0438 Arista EOS.<br \/>  \u041a \u0442\u043e\u043c\u0443 \u0436\u0435, \u0441 \u0443\u0447\u0435\u0442\u043e\u043c \u0437\u0430\u0434\u0443\u043c\u0430\u043d\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043b\u043e\u0433\u0438\u043a\u0438 \u0432\u044b\u0448\u0435, \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440\u044b \u043a \u043d\u0438\u043c \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u044b \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e \u0438 \u0443\u0447\u0442\u0435\u043d\u044b \u043f\u0440\u0438 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u0441\u0432\u0435\u0434\u0435\u043d\u0438\u0438 \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0434\u0430\u043d\u043d\u044b\u0445.<br \/>  \u0421 Next UI \u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u043e\u044f\u043b\u043e \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0445\u043e\u0434\u0443, \u043d\u043e \u0443\u0436 \u0431\u043e\u043b\u044c\u043d\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b\u0438 <a href=\"https:\/\/developer.cisco.com\/site\/neXt\/discover\/demo\/\" rel=\"nofollow\">\u043f\u0440\u0438\u043c\u0435\u0440\u044b<\/a>.<\/p>\n<p>  <\/p>\n<h1 id=\"predvaritelnaya-podgotovka\">\u041f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430<\/h1>\n<p>  <\/p>\n<h3 id=\"testovyy-stend-s-oborudovaniem\">\u0422\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u0441\u0442\u0435\u043d\u0434 \u0441 \u043e\u0431\u043e\u0440\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u0435\u043c<\/h3>\n<p>  <\/p>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u0441\u0442\u0435\u043d\u0434\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0441\u044f \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440 <a href=\"https:\/\/devnetsandbox.cisco.com\/RM\/Diagram\/Index\/685f774a-a5d6-4df5-a324-3774217d0e6b?diagramType=Topology\" rel=\"nofollow\">Cisco Modeling Labs<\/a>. \u042d\u0442\u043e \u043d\u043e\u0432\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u0430 VIRL. \u0412 Cisco DevNet Sandbox \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0439 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043b\u0430\u0431\u0435 \u0441 \u043d\u0438\u043c, \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0437\u0430\u0440\u0435\u0437\u0435\u0440\u0432\u0438\u0440\u043e\u0432\u0430\u0432 \u0432\u0440\u0435\u043c\u044f (\u0432 \u043f\u0430\u0440\u0443 \u043a\u043b\u0438\u043a\u043e\u0432) \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0432 VPN-\u0434\u043e\u0441\u0442\u0443\u043f (\u0447\u0435\u0440\u0435\u0437 AnyConnect). \u0410 \u043a\u043e\u0433\u0434\u0430-\u0442\u043e \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c\u0438 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430\u043c\u0438 \u0431\u044b\u043b\u0438 \u0436\u0435\u043b\u0435\u0437\u043e \u0434\u043e\u043c\u0430 \u0438\u043b\u0438 <s>\u043f\u0440\u043e\u0434\u0430\u043a\u0448\u043d<\/s> \u043f\u0440\u0438\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0441 GNS3. \ud83d\ude42<\/p>\n<p>  \u0412\u0438\u0434 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0439 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u0432 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0435 CML, \u043d\u0430 \u0432\u044b\u0445\u043e\u0434\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u0447\u0442\u043e-\u0442\u043e \u043f\u043e\u0445\u043e\u0436\u0435\u0435:<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/x5\/ib\/hu\/x5ibhuvg2oem-vjb-x3q0aq_66w.png\"><br \/>  \u0418\u043c\u0435\u044e\u0442\u0441\u044f \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u043d\u0430 IOS (edge-sw01), IOSXE (internet-rtr01, distr-rtr01, distr-rtr02), NXOS (dist-sw01, dist-sw02), IOSXR (core-rtr01, core-rtr02) \u0438 ASA (edge-firewall01). \u041d\u0430 \u0432\u0441\u0435\u0445 \u043a\u043e\u043c\u043c\u0443\u0442\u0430\u0442\u043e\u0440\u0430\u0445 \u0438 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0442\u043e\u0440\u0430\u0445 \u0432\u043a\u043b\u044e\u0447\u0435\u043d LLDP. \u0414\u043e\u0441\u0442\u0443\u043f \u043f\u043e SSH \u0432\u043a\u043b\u044e\u0447\u0435\u043d \u043d\u0430 IOS, IOSXE \u0438 NXOS \u043d\u043e\u0434\u0430\u0445.<\/p>\n<p>  <\/p>\n<h3 id=\"ustanovka-i-inicializaciya-nornir\">\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f Nornir<\/h3>\n<p>  <\/p>\n<p>Nornir \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u043c Python-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u043c. \u0420\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 PyPI, \u0442\u0440\u0435\u0431\u0443\u0435\u0442 Python \u0432\u0435\u0440\u0441\u0438\u0438 3.6.2 \u0438 \u0432\u044b\u0448\u0435. \u0417\u0430 \u0441\u043e\u0431\u043e\u0439 \u0442\u044f\u043d\u0435\u0442 \u0432\u0435\u0440\u0435\u043d\u0438\u0446\u0443 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439, \u0432\u043a\u043b\u044e\u0447\u0430\u044f NAPALM \u0438 netmiko. \u041f\u0440\u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0435 \u043d\u0435 \u043d\u0430 \u0447\u0438\u0441\u0442\u0443\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 Python (<a href=\"https:\/\/docs.python.org\/3\/library\/venv.html\" rel=\"nofollow\">venv<\/a>) \u0434\u043b\u044f \u0438\u0437\u043e\u043b\u044f\u0446\u0438\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439. \u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0432\u0435\u043b\u0438\u0441\u044c \u043d\u0430 MacOS, \u043d\u043e Linux-\u0434\u0438\u0441\u0442\u0440\u0438\u0431\u0443\u0442\u0438\u0432\u044b \u0438 Windows \u0442\u043e\u0436\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c\u0441\u044f.<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">$ mkdir ~\/testenv $ python3.7 -m venv ~\/testenv\/ $ source ~\/testenv\/bin\/activate (testenv)$ pip install nornir<\/code><\/pre>\n<p>  <\/p>\n<p>Nornir \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 <a href=\"https:\/\/nornir.readthedocs.io\/en\/stable\/plugins\/inventory\/index.html\" rel=\"nofollow\">\u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b<\/a> \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 inventory \u0434\u043b\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e\u0431 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u0445 \u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u0445 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043d\u0430 \u043d\u0438\u0445.<br \/>  \u0412 \u044d\u0442\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c\u0441\u044f \u043d\u0430 \u0435\u0433\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u043c \u043c\u043e\u0434\u0443\u043b\u0435 SimpleInventory.<br \/>  \u041e\u0431\u0449\u0438\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 Nornir \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0432 yaml \u0444\u0430\u0439\u043b\u0435, \u0438\u043c\u044f \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u043c, \u043d\u043e \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0435\u0433\u043e \u043f\u0440\u0438 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0439 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432 Python-\u0441\u043a\u0440\u0438\u043f\u0442\u0435.<br \/>  <b>nornir_config.yaml:<\/b><\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">--- core:     num_workers: 20 inventory:     plugin: nornir.plugins.inventory.simple.SimpleInventory     options:         host_file: &quot;inventory\/hosts_devnet_sb_cml.yml&quot;         group_file: &quot;inventory\/groups.yml&quot;<\/code><\/pre>\n<p>  <\/p>\n<p>\u041a\u0430\u043a \u0432\u0438\u0434\u043d\u043e \u0432 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0432\u044b\u0448\u0435, \u0432 \u043e\u043f\u0446\u0438\u044f\u0445 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u044b \u0435\u0449\u0435 \u0434\u0432\u0430 yaml-\u0444\u0430\u0439\u043b\u0430: \u0444\u0430\u0439\u043b \u0445\u043e\u0441\u0442\u043e\u0432 \u0438 \u0433\u0440\u0443\u043f\u043f. \u0412 \u043f\u0435\u0440\u0432\u043e\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e\u0431 \u0438\u043d\u0434\u0438\u0432\u0438\u0434\u0443\u0430\u043b\u044c\u043d\u044b\u0445 \u0445\u043e\u0441\u0442\u0430\u0445 \u0438 \u0438\u0445 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430\u0445. \u0412\u043e \u0432\u0442\u043e\u0440\u043e\u043c \u2014 \u0441\u043f\u0438\u0441\u043e\u043a \u0433\u0440\u0443\u043f\u043f \u0438 \u0438\u0445 \u0441\u0432\u043e\u0439\u0441\u0442\u0432. \u0425\u043e\u0441\u0442 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u0442\u043d\u0435\u0441\u0435\u043d \u043a \u043e\u0434\u043d\u043e\u0439 \u0438\u043b\u0438 \u0431\u043e\u043b\u0435\u0435 \u0433\u0440\u0443\u043f\u043f \u0438 \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0432\u0441\u0435 \u0438\u0445 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430, \u0447\u0442\u043e \u0443\u043c\u0435\u043d\u044c\u0448\u0430\u0435\u0442 \u0440\u0430\u0437\u043c\u0435\u0440 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438. \u0418\u043c\u0435\u043d\u0430 \u0444\u0430\u0439\u043b\u043e\u0432 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u043c\u0438, \u043d\u043e \u0442\u043e\u0436\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u0442\u044c \u0441 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u043c\u0438 \u0432 \u043e\u0441\u0432\u043d\u043e\u0432\u043d\u043e\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435.<br \/>  \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 num_workers \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 Nornir \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043f\u043e\u0442\u043e\u043a\u043e\u0432, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0434\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u0441\u0435\u0442\u0435\u0432\u044b\u043c \u043e\u0431\u043e\u0440\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u0435\u043c. \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e 20.<\/p>\n<p>  <b>inventory\/hosts_devnet_sb_cml.yml<\/b> \u0438\u043c\u0435\u0435\u0442 \u043e\u0431\u0449\u0438\u0439 \u0432\u0438\u0434:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">---  internet-rtr01:     hostname: 10.10.20.181     platform: ios     groups:         - devnet-cml-lab  dist-sw01:     hostname: 10.10.20.177     platform: nxos_ssh     transport: ssh     groups:         - devnet-cml-lab<\/code><\/pre>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0443\u043a\u0430\u0437\u0430\u043d\u044b \u0434\u0432\u0430 \u0445\u043e\u0441\u0442\u0430. \u0412 \u043d\u0438\u0445 \u0437\u0430\u0434\u0430\u043d\u044b IP-\u0430\u0434\u0440\u0435\u0441\u0430 \u0438 \u0442\u0438\u043f \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0439 \u0432 \u0441\u0443\u043c\u043c\u0435 \u0441 \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u043e\u043c (\u0434\u043b\u044f IOS \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e SSH) \u0434\u043b\u044f \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0433\u043e \u0432\u044b\u0431\u043e\u0440\u0430 \u041d\u043e\u0440\u043d\u0438\u0440\u043e\u043c \u0438 \u0435\u0433\u043e \u043f\u043b\u0430\u0433\u0438\u043d\u0430\u043c\u0438 \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440\u0430 \u043a \u043e\u0431\u043e\u0440\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u044e. \u041e\u0431\u0430 \u0445\u043e\u0441\u0442\u0430 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u044b \u0432 \u0433\u0440\u0443\u043f\u043f\u0443 &#8216;devnet-cml-lab&#8217;.<\/p>\n<p>  \u0412 <b>groups.yml<\/b> \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0433\u0440\u0443\u043f\u043f\u043e\u0432\u044b\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0434\u043b\u044f \u043d\u0438\u0445:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">---  devnet-cml-lab:     username: cisco     password: cisco     connection_options:         napalm:             extras:                 optional_args:                     secret: cisco<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412\u044b\u0448\u0435 \u0437\u0430\u0434\u0430\u043d\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u043b\u043e\u0433\u0438\u043d, \u043f\u0430\u0440\u043e\u043b\u044c \u0438 \u043f\u0430\u0440\u043e\u043b\u044c \u043d\u0430 enable \u0440\u0435\u0436\u0438\u043c \u0434\u043b\u044f \u043e\u0431\u043e\u0440\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u044f Cisco. \u041e\u043d\u0438 \u0431\u0443\u0434\u0443\u0442 \u0443\u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u044b \u0432\u0441\u0435\u043c\u0438 \u0447\u043b\u0435\u043d\u0430\u043c\u0438 \u0433\u0440\u0443\u043f\u043f\u044b.<br \/>  <strong>\u0412\u0430\u0436\u043d\u043e!<\/strong> \u041d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u0434\u0435\u043b\u0430\u0439\u0442\u0435 \u0442\u0430\u043a \u0432 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u043d\u0435 \u0438 \u043d\u0435 \u0445\u0440\u0430\u043d\u0438\u0442\u0435 \u043f\u0430\u0440\u043e\u043b\u0438 \u0438 \u043b\u043e\u0433\u0438\u043d\u044b \u0432 \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u043c \u0432\u0438\u0434\u0435, \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u044b \u0434\u043b\u044f \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u0438.<br \/>  \u042d\u0442\u043e \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438, \u0434\u0430\u043b\u0435\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c Nornir \u0432 Python-\u0441\u043a\u0440\u0438\u043f\u0442\u0435 \u0438 \u043d\u0430\u0447\u0430\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u043d\u0438\u043c.<\/p>\n<p>  <\/p>\n<h3 id=\"skachivanie-next-ui\">\u0421\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0435 NeXt UI<\/h3>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0441\u043a\u0430\u0447\u0430\u0442\u044c \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u0441 <a href=\"https:\/\/github.com\/NeXt-UI\/next-bower\" rel=\"nofollow\">GitHub<\/a>, \u0447\u0442\u043e \u043c\u044b \u0438 \u0441\u0434\u0435\u043b\u0430\u0435\u043c. \u0415\u0433\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0431\u0443\u0434\u0443\u0442 \u043b\u0435\u0436\u0430\u0442\u044c \u0432 .\/next_sources.<\/p>\n<p>  <\/p>\n<hr>\n<p>  <\/p>\n<p>\u0418 \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0438\u043c\u0435\u0435\u043c:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">$ tree . -L 2 . \u251c\u2500\u2500 inventory \u2502\u00a0\u00a0 \u251c\u2500\u2500 groups.yml \u2502\u00a0\u00a0 \u2514\u2500\u2500 hosts_devnet_sb_cml.yml \u251c\u2500\u2500 next_sources \u2502\u00a0\u00a0 \u251c\u2500\u2500 css \u2502\u00a0\u00a0 \u251c\u2500\u2500 doc \u2502\u00a0\u00a0 \u251c\u2500\u2500 fonts \u2502\u00a0\u00a0 \u2514\u2500\u2500 js \u251c\u2500\u2500 nornir_config.yml<\/code><\/pre>\n<p>  <\/p>\n<h1 id=\"ot-sbora-dannyh-do-vizualizacii-ne-za-80-dney\">\u041e\u0442 \u0441\u0431\u043e\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043e \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043d\u0435 \u0437\u0430 80 \u0434\u043d\u0435\u0439<\/h1>\n<p>  <\/p>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443 \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442 <b>generate_topology.py<\/b>.  <\/p>\n<p>  <\/p>\n<h3 id=\"finalnyy-shtrih-dlya-inicializacii-nornir\">\u0424\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0448\u0442\u0440\u0438\u0445 \u0434\u043b\u044f \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 Nornir<\/h3>\n<p>  <\/p>\n<p>\u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c Nornir \u0432 Python:<\/p>\n<p>  <\/p>\n<pre><code class=\"python\">from nornir import InitNornir from nornir.plugins.tasks.networking import napalm_get  NORNIR_CONFIG_FILE = &quot;nornir_config.yml&quot;  nr = InitNornir(config_file=NORNIR_CONFIG_FILE)<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043e\u043d \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0433\u043e\u0442\u043e\u0432 \u043a \u0440\u0430\u0431\u043e\u0442\u0435.<br \/>  \u0418\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 napalm_get \u0434\u0430\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043a NAPALM \u0447\u0435\u0440\u0435\u0437 Nornir.  <\/p>\n<p>  <\/p>\n<h3 id=\"minutka-lldp\">\u041c\u0438\u043d\u0443\u0442\u043a\u0430 LLDP<\/h3>\n<p>  <\/p>\n<p>\u041f\u043e LLDP \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u043e\u0431\u043c\u0435\u043d\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0441 \u043f\u0440\u044f\u043c\u044b\u043c\u0438 \u0441\u043e\u0441\u0435\u0434\u044f\u043c\u0438 \u0444\u0440\u0435\u0439\u043c\u0430\u043c\u0438, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u043c\u0438 \u043d\u0430\u0431\u043e\u0440 <a href=\"https:\/\/en.wikipedia.org\/wiki\/Type-length-value\" rel=\"nofollow\">TLV<\/a> \u043f\u043e\u043b\u0435\u0439. LLDP-\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043d\u0435 \u0440\u0435\u0442\u0440\u0430\u043d\u0441\u043b\u0438\u0440\u0443\u044e\u0442\u0441\u044f.<br \/>  \u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 TLV: Chassis ID, Port ID \u0438 Time-to-Live<br \/>  \u041e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0435: System name and description; Port name and description; VLAN name; IP management address; System capabilities (switching, routing, etc.) \u0438 \u043f\u0440\u043e\u0447\u0438\u0435.<br \/>  \u0422.\u043a. \u0441\u0435\u0442\u044c \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043f\u043e\u0434 \u043d\u0430\u0448\u0438\u043c \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u043c, \u0432\u043a\u043b\u044e\u0447\u0438\u043c System name \u0438 Port name \u0432 \u043d\u0430\u0431\u043e\u0440 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 TLV.<br \/>  \u042d\u0442\u043e \u043d\u0435 \u043d\u0435\u0441\u0435\u0442 \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0440\u0438\u0441\u043a\u043e\u0432 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438, \u043d\u043e \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043e\u0434\u043d\u043e\u0437\u043d\u0430\u0447\u043d\u043e \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043c\u0443\u043b\u044c\u0442\u0438-\u0448\u0430\u0441\u0441\u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0441 \u0435\u0434\u0438\u043d\u044b\u043c control plane (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441\u0442\u0435\u043a\u0438) \u0438 \u0441\u0432\u044f\u0437\u0438 \u043c\u0435\u0436\u0434\u0443 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438.<\/p>\n<p>  \u0417\u0430\u0434\u0430\u0447\u0430 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u0432 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0441\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u043a \u0441\u0431\u043e\u0440\u0443 \u0438\u043d\u0434\u0438\u0432\u0438\u0434\u0443\u0430\u043b\u044c\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u043e\u0431 \u0438\u0445 \u0441\u043e\u0441\u0435\u0434\u0441\u0442\u0432\u0430\u0445 \u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0438 \u043d\u0430 \u0438\u0445 \u043e\u0441\u043d\u043e\u0432\u0435 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u0438 \u0441\u0432\u044f\u0437\u0435\u0439 \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438 (\u0442.\u0435. \u0432\u0435\u0440\u0448\u0438\u043d \u0438 \u0440\u0435\u0431\u0435\u0440 \u0441\u043e\u0432\u043e\u043a\u0443\u043f\u043d\u043e\u0433\u043e \u0433\u0440\u0430\u0444\u0430).<br \/>  <i>\u0421\u0445\u043e\u0436\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, OSPF \u043f\u0440\u0438 \u0441\u0431\u043e\u0440\u0435 \u0438 \u0430\u043d\u0430\u043b\u0438\u0437\u0435 \u0438\u043d\u0434\u0438\u0432\u0438\u0434\u0443\u0430\u043b\u044c\u043d\u044b\u0445 LSA. \u0418 \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u0432\u044f\u0437\u043d\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u043e\u0432 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u2014 \u0442\u043e\u0436\u0435 \u0432\u043f\u043e\u043b\u043d\u0435 \u0441\u0435\u0431\u0435 \u043a\u0435\u0439\u0441. \u041d\u043e \u0432\u0435\u0440\u043d\u0435\u043c\u0441\u044f \u043f\u043e\u043a\u0430 \u043a LLPD.<\/i><\/p>\n<p>  \u0412 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0439 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u0432\u0441\u0435 edge, core \u0438 distribution \u0434\u043e\u043b\u0436\u043d\u044b \u0432\u0438\u0434\u0435\u0442\u044c \u0441\u0432\u043e\u0438\u0445 \u043f\u0440\u044f\u043c\u044b\u0445 \u0441\u043e\u0441\u0435\u0434\u0435\u0439. internet-rtr01 \u0438\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d \u043e\u0442 \u0432\u0441\u0435\u0445 \u0438 \u043d\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u0438\u043c\u0435\u0442\u044c LLDP-\u0441\u043e\u0441\u0435\u0434\u0441\u0442\u0432. <br \/>  \u041a \u043f\u0440\u0438\u043c\u0435\u0440\u0443, \u0441\u0443\u043c\u043c\u0430\u0440\u043d\u044b\u0439 \u0432\u044b\u0432\u043e\u0434 \u0441\u043e\u0441\u0435\u0434\u0441\u0442\u0432 \u0441 dist-rtr01:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">dist-rtr01#sh lldp nei Capability codes:     (R) Router, (B) Bridge, (T) Telephone, (C) DOCSIS Cable Device     (W) WLAN Access Point, (P) Repeater, (S) Station, (O) Other  Device ID           Local Intf     Hold-time  Capability      Port ID dist-rtr02.devnet.laGi6            120        R               Gi6 dist-sw01.devnet.labGi4            120        B,R             Ethernet1\/3 dist-sw02.devnet.labGi5            120        B,R             Ethernet1\/3 core-rtr02.devnet.laGi3            120        R               Gi0\/0\/0\/2 core-rtr01.devnet.laGi2            120        R               Gi0\/0\/0\/2  Total entries displayed: 5<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u044f\u0442\u044c \u0441\u043e\u0441\u0435\u0434\u0435\u0439, \u0432\u0441\u0435 \u0432\u0435\u0440\u043d\u043e.<br \/>  \u0418 \u0441 core-rtr02:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">RP\/0\/0\/CPU0:core-rtr02#sh lldp nei Sun May 10 22:07:05.776 UTC Capability codes:         (R) Router, (B) Bridge, (T) Telephone, (C) DOCSIS Cable Device         (W) WLAN Access Point, (P) Repeater, (S) Station, (O) Other  Device ID       Local Intf          Hold-time  Capability     Port ID core-rtr01.devnet.la Gi0\/0\/0\/0           120        R               Gi0\/0\/0\/0 edge-sw01.devnet.lab Gi0\/0\/0\/1           120        R               Gi0\/3 dist-rtr01.devnet.la Gi0\/0\/0\/2           120        R               Gi3 dist-rtr02.devnet.la Gi0\/0\/0\/3           120        R               Gi3  Total entries displayed: 4<\/code><\/pre>\n<p>  <\/p>\n<p>4 \u0441\u043e\u0441\u0435\u0434\u0441\u0442\u0432\u0430, \u0442\u043e\u0436\u0435 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e.<br \/>  \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0432 \u043e\u0431\u043e\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435 \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0442 \u043e\u0431\u0440\u0435\u0437\u0430\u043d\u043d\u044b\u0435 \u0445\u043e\u0441\u0442\u043d\u0435\u0439\u043c\u044b \u0432 \u0441\u0442\u043e\u043b\u0431\u0446\u0435 Device ID.<br \/>  \u0422\u0430\u043a\u0438\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u2014 \u0438\u0437\u0432\u0435\u0447\u043d\u044b\u0435 \u0441\u043f\u0443\u0442\u043d\u0438\u043a\u0438 CLI-\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438.<br \/>  \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043e\u0431\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043f\u0443\u0442\u0438 \u0431\u0443\u0434\u0435\u043c \u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u044b\u0439 \u0432\u044b\u0432\u043e\u0434 \u0441 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0438\u0437 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432.<br \/>  \u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430:<\/p>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">&#39;show lldp neighbors detail&#39; \u0441 dist-rtr01 \u043d\u0430 IOSXE<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"plaintext\">dist-rtr01#sh lldp nei det ------------------------------------------------ Local Intf: Gi6 Chassis id: 001e.e57c.cf00 Port id: Gi6 Port Description: L3 Link to dist-rtr01 System Name: dist-rtr02.devnet.lab  System Description:  Cisco IOS Software [Gibraltar], Virtual XE Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Version 16.11.1b, RELEASE SOFTWARE (fc2) Technical Support: http:\/\/www.cisco.com\/techsupport Copyright (c) 1986-2019 by Cisco Systems, Inc. Compiled Tue 28-May-19 12:45  Time remaining: 91 seconds System Capabilities: B,R Enabled Capabilities: R Management Addresses:     IP: 172.16.252.18 Auto Negotiation - not supported Physical media capabilities - not advertised Media Attachment Unit type - not advertised Vlan ID: - not advertised  ------------------------------------------------ Local Intf: Gi4 Chassis id: 5254.0007.5d59 Port id: Ethernet1\/3 Port Description: L3 link to dist-rtr01 System Name: dist-sw01.devnet.lab  System Description:  Cisco Nexus Operating System (NX-OS) Software 9.2(3) TAC support: http:\/\/www.cisco.com\/tac Copyright (c) 2002-2019, Cisco Systems, Inc. All rights reserved.  Time remaining: 108 seconds System Capabilities: B,R Enabled Capabilities: B,R Management Addresses:     IP: 10.10.20.177     Other: 52 54 00 07 5D 59 00 Auto Negotiation - not supported Physical media capabilities - not advertised Media Attachment Unit type - not advertised Vlan ID: - not advertised  ------------------------------------------------ Local Intf: Gi5 Chassis id: 5254.0007.b7e6 Port id: Ethernet1\/3 Port Description: L3 link to dist-rtr01 System Name: dist-sw02.devnet.lab  System Description:  Cisco Nexus Operating System (NX-OS) Software 9.2(3) TAC support: http:\/\/www.cisco.com\/tac Copyright (c) 2002-2019, Cisco Systems, Inc. All rights reserved.  Time remaining: 97 seconds System Capabilities: B,R Enabled Capabilities: B,R Management Addresses:     IP: 10.10.20.178     Other: 52 54 00 07 FF FF 00 Auto Negotiation - not supported Physical media capabilities - not advertised Media Attachment Unit type - not advertised Vlan ID: - not advertised  ------------------------------------------------ Local Intf: Gi3 Chassis id: 02c7.9dc0.0c06 Port id: Gi0\/0\/0\/2 Port Description: L3 Link to dist-rtr01 System Name: core-rtr02.devnet.lab  System Description:  Cisco IOS XR Software, Version 6.3.1[Default] Copyright (c) 2017 by Cisco Systems, Inc., IOS XRv Series  Time remaining: 94 seconds System Capabilities: R Enabled Capabilities: R Management Addresses:     IP: 172.16.252.26 Auto Negotiation - not supported Physical media capabilities - not advertised Media Attachment Unit type - not advertised Vlan ID: - not advertised  ------------------------------------------------ Local Intf: Gi2 Chassis id: 0288.15c0.0c06 Port id: Gi0\/0\/0\/2 Port Description: L3 Link to dist-rtr01 System Name: core-rtr01.devnet.lab  System Description:  Cisco IOS XR Software, Version 6.3.1[Default] Copyright (c) 2017 by Cisco Systems, Inc., IOS XRv Series  Time remaining: 110 seconds System Capabilities: R Enabled Capabilities: R Management Addresses:     IP: 172.16.252.22 Auto Negotiation - not supported Physical media capabilities - not advertised Media Attachment Unit type - not advertised Vlan ID: - not advertised  Total entries displayed: 5<\/code><\/pre>\n<\/div><\/div>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">show lldp neighbors detail c dist-sw01 \u043d\u0430 NXOS<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"plaintext\">dist-sw01# sh lldp nei det Capability codes:   (R) Router, (B) Bridge, (T) Telephone, (C) DOCSIS Cable Device   (W) WLAN Access Point, (P) Repeater, (S) Station, (O) Other Device ID            Local Intf      Hold-time  Capability  Port ID    Chassis id: 5254.0007.b7e4 Port id: Ethernet1\/1 Local Port id: Eth1\/1 Port Description: VPC Peer Link System Name: dist-sw02.devnet.lab System Description: Cisco Nexus Operating System (NX-OS) Software 9.2(3) TAC support: http:\/\/www.cisco.com\/tac Copyright (c) 2002-2019, Cisco Systems, Inc. All rights reserved. Time remaining: 112 seconds System Capabilities: B, R Enabled Capabilities: B, R Management Address: 10.10.20.178 Management Address IPV6: not advertised Vlan ID: 1  Chassis id: 5254.0007.b7e5 Port id: Ethernet1\/2 Local Port id: Eth1\/2 Port Description: VPC Peer Link System Name: dist-sw02.devnet.lab System Description: Cisco Nexus Operating System (NX-OS) Software 9.2(3) TAC support: http:\/\/www.cisco.com\/tac Copyright (c) 2002-2019, Cisco Systems, Inc. All rights reserved. Time remaining: 112 seconds System Capabilities: B, R Enabled Capabilities: B, R Management Address: 10.10.20.178 Management Address IPV6: not advertised Vlan ID: 1  Chassis id: 001e.7a2a.3900 Port id: Gi4 Local Port id: Eth1\/3 Port Description: L3 Link to dist-sw01 System Name: dist-rtr01.devnet.lab System Description: Cisco IOS Software [Gibraltar], Virtual XE Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Version 16.11.1b, RELEASE SOFTWARE (fc2) Technical Support: http:\/\/www.cisco.com\/techsupport Copyright (c) 1986-2019 by Cisco Systems, Inc. Compiled Tue 28-May-19 12:45 Time remaining: 109 seconds System Capabilities: B, R Enabled Capabilities: R Management Address: 172.16.252.2 Management Address IPV6: not advertised Vlan ID: not advertised  Chassis id: 001e.e57c.cf00 Port id: Gi4 Local Port id: Eth1\/4 Port Description: L3 Link to dist-sw01 System Name: dist-rtr02.devnet.lab System Description: Cisco IOS Software [Gibraltar], Virtual XE Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Version 16.11.1b, RELEASE SOFTWARE (fc2) Technical Support: http:\/\/www.cisco.com\/techsupport Copyright (c) 1986-2019 by Cisco Systems, Inc. Compiled Tue 28-May-19 12:45 Time remaining: 108 seconds System Capabilities: B, R Enabled Capabilities: R Management Address: 172.16.252.6 Management Address IPV6: not advertised Vlan ID: not advertised  Total entries displayed: 4<\/code><\/pre>\n<\/div><\/div>\n<p>  <\/p>\n<h3 id=\"poluchenie-dannyh-s-oborudovaniya\">\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u043e\u0431\u043e\u0440\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u044f<\/h3>\n<p>  <\/p>\n<p>\u0414\u0430\u043d\u043d\u044b\u0435 \u0431\u0443\u0434\u0435\u043c \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u043d\u0430 IOS (edge-sw01), IOSXE (internet-rtr01, distr-rtr01, distr-rtr02) \u0438 NXOS (dist-sw01, dist-sw02).<br \/>  \u041d\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u0445 \u043d\u0430 IOSXR (core-rtr01, core-rtr02) \u0434\u043e\u0441\u0442\u0443\u043f \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043a\u0440\u044b\u0442.<br \/>  \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0431\u0443\u0434\u0443\u0442 \u043f\u043e\u043a\u0440\u044b\u0442\u044b \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0438:<\/p>\n<p>  <\/p>\n<ol>\n<li>\u0410\u043d\u0430\u043b\u0438\u0437\u0430 \u043f\u043e\u043b\u043d\u043e\u0439 \u0441\u0432\u044f\u0437\u043d\u043e\u0441\u0442\u0438 \u0434\u043b\u044f distribution \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432.<br \/>  \u0414\u043e\u043b\u0436\u043d\u044b \u0432\u0435\u0440\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c\u0441\u044f \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0435 \u043d\u043e\u0434\u044b \u0438 \u043b\u0438\u043d\u043a\u0438.<\/li>\n<li>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043e\u0448\u0438\u0431\u043e\u043a \u043f\u0440\u0438 \u043e\u0442\u0441\u0443\u0442\u0432\u0438\u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u0434\u043b\u044f core-rtr01 \u0438 core-rtr02.<br \/>  \u042d\u0442\u043e \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0432\u043b\u0438\u044f\u0442\u044c \u043d\u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043e\u0441\u0442\u0430\u0432\u0448\u0438\u043c\u0438\u0441\u044f \u0443\u0441\u0442\u0440\u043e\u0439\u0442\u0441\u0432\u0430\u043c\u0438.<\/li>\n<li>\u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0447\u0430\u0441\u0442\u0438 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u0431\u0435\u0437 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043d\u0430 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430.<br \/>  \u0418 edge-sw01, \u0438 distr-rtr01 \u0441 distr-sw02 \u0432\u0438\u0434\u044f\u0442 core-rtr01 \u0438 core-rtr02 \u0441 \u0440\u0430\u0437\u043d\u044b\u0445 \u0441\u0442\u043e\u0440\u043e\u043d \u043f\u043e LLDP.<br \/>  \u0412 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u044f \u0434\u043e\u043b\u0436\u043d\u0430 \u0441\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0432 \u0435\u0434\u0438\u043d\u043e\u0435 \u0446\u0435\u043b\u043e\u0435.<\/li>\n<\/ol>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0424\u0430\u0439\u043b \u0445\u043e\u0441\u0442\u043e\u0432 inventory\/hosts_devnet_sb_cml.yml<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"plaintext\">---  internet-rtr01:     hostname: 10.10.20.181     platform: ios     site: devnet_sandbox     groups:         - devnet-cml-lab  edge-sw01:     hostname: 10.10.20.172     platform: ios     site: devnet_sandbox     groups:         - devnet-cml-lab  core-rtr01:     # \u0434\u043e\u0441\u0442\u0443\u043f \u043d\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0435 \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0430     hostname: 10.10.20.173     platform: iosxr     groups:         - devnet-cml-lab  core-rtr02:     # \u0434\u043e\u0441\u0442\u0443\u043f \u043d\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0435 \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0430     hostname: 10.10.20.174     platform: iosxr     groups:         - devnet-cml-lab  dist-rtr01:     hostname: 10.10.20.175     platform: ios     groups:         - devnet-cml-lab  dist-rtr02:     hostname: 10.10.20.176     platform: ios     groups:         - devnet-cml-lab  dist-sw01:     hostname: 10.10.20.177     platform: nxos_ssh     transport: ssh     groups:         - devnet-cml-lab  dist-sw02:     hostname: 10.10.20.178     platform: nxos_ssh     transport: ssh     groups:         - devnet-cml-lab <\/code><\/pre>\n<\/div><\/div>\n<p>  <\/p>\n<p>\u0417\u0430\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u043c \u0434\u0432\u0430 \u0433\u0435\u0442\u0442\u0435\u0440\u0430 NAPALM:<\/p>\n<p>  <\/p>\n<ul>\n<li>GET_LLDP_NEIGHBORS_DETAILS (\u0441\u0431\u043e\u0440 LLDP-\u0441\u043e\u0441\u0435\u0434\u0441\u0442\u0432).<br \/>  \u0412\u044b\u0431\u0440\u0430\u043d \u0434\u0435\u0442\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0432\u044b\u0432\u043e\u0434, \u0442.\u043a. \u0432 CLI-\u0432\u044b\u0432\u043e\u0434\u0430\u0445 \u0441\u0443\u043c\u043c\u0430\u0440\u043d\u043e\u0433\u043e \u043c\u043e\u0433\u0443\u0442 \u043e\u0431\u0440\u0435\u0437\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u0438\u043d\u043d\u044b\u0435 \u0445\u043e\u0441\u0442\u043d\u0435\u0439\u043c\u044b.<\/li>\n<li>GET_FACTS (\u043e\u0431\u0449\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0431 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0435).<br \/>  \u042d\u0442\u043e\u0442 \u0433\u0435\u0442\u0442\u0435\u0440 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e \u0445\u043e\u0441\u0442\u043d\u0435\u0439\u043c\u0435 \u0438 FQDN, \u043e\u043d\u0438 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u044f\u0442\u0441\u044f.<br \/>  \u041f\u043e\u043c\u0438\u043c\u043e \u043d\u0438\u0445, \u0432\u044b\u0432\u043e\u0434 \u043c\u043e\u0436\u0435\u0442 \u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043c\u043e\u0434\u0435\u043b\u0438 \u0438 \u0441\u0435\u0440\u0438\u0439\u043d\u043e\u043c \u043d\u043e\u043c\u0435\u0440\u0435. \u041c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u043f\u0440\u0438 \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438.  <\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0421\u0431\u043e\u0440 \u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u0431\u0435\u0440\u043d\u0435\u043c \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e-Task \u0434\u043b\u044f Nornir.<br \/>  \u042d\u0442\u043e \u043e\u0434\u0438\u043d \u0438\u0437 \u0435\u0433\u043e \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u043e\u0432 \u0434\u043b\u044f \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u0438 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u043d\u0430 \u0438\u043d\u0434\u0438\u0432\u0438\u0434\u0443\u0430\u043b\u044c\u043d\u044b\u0445 \u0445\u043e\u0441\u0442\u0430\u0445.<br \/>  \u0422\u0430\u0441\u043a\u0438 \u043f\u0440\u0438 \u043c\u0430\u0441\u0441\u0432\u043e\u0432\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043d\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u0445 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0432 <i>num_workers<\/i> \u043f\u043e\u0442\u043e\u043a\u043e\u0432.<\/p>\n<p>  <\/p>\n<pre><code class=\"python\">def get_host_data(task):     &quot;&quot;&quot;Nornir Task \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0446\u0435\u043b\u0435\u0432\u044b\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432.&quot;&quot;&quot;     task.run(         task=napalm_get,         getters=['facts', 'lldp_neighbors_detail']     )  # \u0417\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0442\u0430\u0441\u043a \u043d\u0430 \u0432\u0441\u0435\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u0445 \u0432 \u0438\u043d\u0432\u0435\u043d\u0442\u043e\u0440\u0438. # \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u043c \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e \u0434\u043b\u044f \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0433\u043e \u0440\u0430\u0437\u0431\u043e\u0440\u0430. get_host_data_result = nr.run(get_host_data)<\/code><\/pre>\n<p>  <\/p>\n<p>\u0415\u0441\u043b\u0438 \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0442\u0430\u0441\u043a \u043d\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u0445\u043e\u0441\u0442\u0430\u0445 \u0438\u043b\u0438 \u0433\u0440\u0443\u043f\u043f\u0430\u0445, Nornir \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c <a href=\"https:\/\/nornir.readthedocs.io\/en\/latest\/tutorials\/intro\/inventory.html#Filtering-the-inventory\" rel=\"nofollow\">\u043f\u0440\u043e\u0441\u0442\u044b\u0445<\/a> \u0438 <a href=\"https:\/\/nornir.readthedocs.io\/en\/latest\/howto\/advanced_filtering.html\" rel=\"nofollow\">\u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0441\u043d\u044b\u0445<\/a> \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432 \u043d\u0430\u0434 \u0438\u043d\u0432\u0435\u043d\u0442\u043e\u0440\u0438.<\/p>\n<p>  <\/p>\n<h3 id=\"razbor-poluchennyh-ot-ustroystv-dannyh\">\u0420\u0430\u0437\u0431\u043e\u0440 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0445 \u043e\u0442 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u0434\u0430\u043d\u043d\u044b\u0445<\/h3>\n<p>  <\/p>\n<p>\u0412 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 get_host_data_result \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0442\u0430\u0441\u043a\u0430 get_host_data \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u0438\u0437 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432.<\/p>\n<p>  <\/p>\n<pre><code class=\"python\">&gt;&gt;&gt; get_host_data_result AggregatedResult (get_host_data): {'internet-rtr01': MultiResult: [Result: &quot;get_host_data&quot;, Result: &quot;napalm_get&quot;], 'edge-sw01': MultiResult: [Result: &quot;get_host_data&quot;, Result: &quot;napalm_get&quot;], 'core-rtr01': MultiResult: [Result: &quot;get_host_data&quot;, Result: &quot;napalm_get&quot;], 'core-rtr02': MultiResult: [Result: &quot;get_host_data&quot;, Result: &quot;napalm_get&quot;], 'dist-rtr01': MultiResult: [Result: &quot;get_host_data&quot;, Result: &quot;napalm_get&quot;], 'dist-rtr02': MultiResult: [Result: &quot;get_host_data&quot;, Result: &quot;napalm_get&quot;], 'dist-sw01': MultiResult: [Result: &quot;get_host_data&quot;, Result: &quot;napalm_get&quot;], 'dist-sw02': MultiResult: [Result: &quot;get_host_data&quot;, Result: &quot;napalm_get&quot;]}<\/code><\/pre>\n<p>  <\/p>\n<p>\u041e\u0431\u044a\u0435\u043a\u0442\u044b \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442 \u043c\u0435\u0442\u043e\u0434 failed, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0438\u0439 \u0431\u0443\u043b\u0435\u0432\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435, \u043f\u043e \u043d\u0435\u043c\u0443 \u043c\u043e\u0436\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c, \u0443\u0434\u0430\u0447\u043d\u043e \u043b\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043b\u0441\u044f \u0442\u0430\u0441\u043a.<br \/>  \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043c\u043e\u0436\u043d\u043e \u0438\u0442\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u0430\u043a \u0441\u043b\u043e\u0432\u0430\u0440\u044c:<\/p>\n<p>  <\/p>\n<pre><code class=\"python\">&gt;&gt;&gt; for device, result in get_host_data_result.items(): ...     print(f'{device} failed: {result.failed}') ...  internet-rtr01 failed: False edge-sw01 failed: False core-rtr01 failed: True core-rtr02 failed: True dist-rtr01 failed: False dist-rtr02 failed: False dist-sw01 failed: False dist-sw02 failed: False<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u043e.  <\/p>\n<p>  <\/p>\n<p>\u041f\u043e\u043b\u043d\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430:<\/p>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0421\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u0441 dist-rtr01<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">&gt;&gt;&gt; get_host_data_result['dist-rtr01'][1].result {'facts': {'uptime': 6120, 'vendor': 'Cisco', 'os_version': 'Virtual XE Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Version 16.11.1b, RELEASE SOFTWARE (fc2)', 'serial_number': '9JDCOVUDSWN', 'model': 'CSR1000V', 'hostname': 'dist-rtr01', 'fqdn': 'dist-rtr01.devnet.lab', 'interface_list': ['GigabitEthernet1', 'GigabitEthernet2', 'GigabitEthernet3', 'GigabitEthernet4', 'GigabitEthernet5', 'GigabitEthernet6', 'Loopback0']}, 'lldp_neighbors_detail': {'GigabitEthernet6': [{'remote_chassis_id': '001e.e57c.cf00', 'remote_port': 'Gi6', 'remote_port_description': 'L3 Link to dist-rtr01', 'remote_system_name': 'dist-rtr02.devnet.lab', 'remote_system_description': 'Cisco IOS Software [Gibraltar], Virtual XE Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Version 16.11.1b, RELEASE SOFTWARE (fc2)', 'remote_system_capab': ['bridge', 'router'], 'remote_system_enable_capab': ['router'], 'parent_interface': ''}], 'GigabitEthernet4': [{'remote_chassis_id': '5254.0007.5d59', 'remote_port': 'Ethernet1\/3', 'remote_port_description': 'L3 link to dist-rtr01', 'remote_system_name': 'dist-sw01.devnet.lab', 'remote_system_description': 'Cisco Nexus Operating System (NX-OS) Software 9.2(3)', 'remote_system_capab': ['bridge', 'router'], 'remote_system_enable_capab': ['bridge', 'router'], 'parent_interface': ''}], 'GigabitEthernet5': [{'remote_chassis_id': '5254.0007.b7e6', 'remote_port': 'Ethernet1\/3', 'remote_port_description': 'L3 link to dist-rtr01', 'remote_system_name': 'dist-sw02.devnet.lab', 'remote_system_description': 'Cisco Nexus Operating System (NX-OS) Software 9.2(3)', 'remote_system_capab': ['bridge', 'router'], 'remote_system_enable_capab': ['bridge', 'router'], 'parent_interface': ''}], 'GigabitEthernet3': [{'remote_chassis_id': '02c7.9dc0.0c06', 'remote_port': 'Gi0\/0\/0\/2', 'remote_port_description': 'L3 Link to dist-rtr01', 'remote_system_name': 'core-rtr02.devnet.lab', 'remote_system_description': 'Cisco IOS XR Software, Version 6.3.1[Default]', 'remote_system_capab': ['router'], 'remote_system_enable_capab': ['router'], 'parent_interface': ''}], 'GigabitEthernet2': [{'remote_chassis_id': '0288.15c0.0c06', 'remote_port': 'Gi0\/0\/0\/2', 'remote_port_description': 'L3 Link to dist-rtr01', 'remote_system_name': 'core-rtr01.devnet.lab', 'remote_system_description': 'Cisco IOS XR Software, Version 6.3.1[Default]', 'remote_system_capab': ['router'], 'remote_system_enable_capab': ['router'], 'parent_interface': ''}]}}<\/code><\/pre>\n<\/div><\/div>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0421\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u0441 dist-sw01<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">&gt;&gt;&gt; get_host_data_result['dist-sw01'][1].result {'facts': {'uptime': 6090, 'vendor': 'Cisco', 'os_version': '9.2(3)', 'serial_number': '9P5OMCCMSQ4', 'model': 'Nexus9000 9000v Chassis', 'hostname': 'dist-sw01', 'fqdn': 'dist-sw01.devnet.lab', 'interface_list': ['mgmt0', 'Ethernet1\/1', 'Ethernet1\/2', 'Ethernet1\/3', 'Ethernet1\/4', 'Ethernet1\/5', 'Ethernet1\/6', 'Ethernet1\/7', 'Ethernet1\/8', 'Ethernet1\/9', 'Ethernet1\/10', 'Ethernet1\/11', 'Ethernet1\/12', 'Ethernet1\/13', 'Ethernet1\/14', 'Ethernet1\/15', 'Ethernet1\/16', 'Ethernet1\/17', 'Ethernet1\/18', 'Ethernet1\/19', 'Ethernet1\/20', 'Ethernet1\/21', 'Ethernet1\/22', 'Ethernet1\/23', 'Ethernet1\/24', 'Ethernet1\/25', 'Ethernet1\/26', 'Ethernet1\/27', 'Ethernet1\/28', 'Ethernet1\/29', 'Ethernet1\/30', 'Ethernet1\/31', 'Ethernet1\/32', 'Ethernet1\/33', 'Ethernet1\/34', 'Ethernet1\/35', 'Ethernet1\/36', 'Ethernet1\/37', 'Ethernet1\/38', 'Ethernet1\/39', 'Ethernet1\/40', 'Ethernet1\/41', 'Ethernet1\/42', 'Ethernet1\/43', 'Ethernet1\/44', 'Ethernet1\/45', 'Ethernet1\/46', 'Ethernet1\/47', 'Ethernet1\/48', 'Ethernet1\/49', 'Ethernet1\/50', 'Ethernet1\/51', 'Ethernet1\/52', 'Ethernet1\/53', 'Ethernet1\/54', 'Ethernet1\/55', 'Ethernet1\/56', 'Ethernet1\/57', 'Ethernet1\/58', 'Ethernet1\/59', 'Ethernet1\/60', 'Ethernet1\/61', 'Ethernet1\/62', 'Ethernet1\/63', 'Ethernet1\/64', 'Ethernet1\/65', 'Ethernet1\/66', 'Ethernet1\/67', 'Ethernet1\/68', 'Ethernet1\/69', 'Ethernet1\/70', 'Ethernet1\/71', 'Ethernet1\/72', 'Ethernet1\/73', 'Ethernet1\/74', 'Ethernet1\/75', 'Ethernet1\/76', 'Ethernet1\/77', 'Ethernet1\/78', 'Ethernet1\/79', 'Ethernet1\/80', 'Ethernet1\/81', 'Ethernet1\/82', 'Ethernet1\/83', 'Ethernet1\/84', 'Ethernet1\/85', 'Ethernet1\/86', 'Ethernet1\/87', 'Ethernet1\/88', 'Ethernet1\/89', 'Ethernet1\/90', 'Ethernet1\/91', 'Ethernet1\/92', 'Ethernet1\/93', 'Ethernet1\/94', 'Ethernet1\/95', 'Ethernet1\/96', 'Ethernet1\/97', 'Ethernet1\/98', 'Ethernet1\/99', 'Ethernet1\/100', 'Ethernet1\/101', 'Ethernet1\/102', 'Ethernet1\/103', 'Ethernet1\/104', 'Ethernet1\/105', 'Ethernet1\/106', 'Ethernet1\/107', 'Ethernet1\/108', 'Ethernet1\/109', 'Ethernet1\/110', 'Ethernet1\/111', 'Ethernet1\/112', 'Ethernet1\/113', 'Ethernet1\/114', 'Ethernet1\/115', 'Ethernet1\/116', 'Ethernet1\/117', 'Ethernet1\/118', 'Ethernet1\/119', 'Ethernet1\/120', 'Ethernet1\/121', 'Ethernet1\/122', 'Ethernet1\/123', 'Ethernet1\/124', 'Ethernet1\/125', 'Ethernet1\/126', 'Ethernet1\/127', 'Ethernet1\/128', 'Port-channel1', 'Loopback0', 'Vlan1', 'Vlan101', 'Vlan102', 'Vlan103', 'Vlan104', 'Vlan105']}, 'lldp_neighbors_detail': {'Ethernet1\/1': [{'remote_chassis_id': '5254.0007.b7e4', 'remote_port': 'Ethernet1\/1', 'remote_port_description': 'VPC Peer Link', 'remote_system_name': 'dist-sw02.devnet.lab', 'remote_system_description': 'Cisco Nexus Operating System (NX-OS) Software 9.2(3)', 'remote_system_capab': ['bridge', 'router'], 'remote_system_enable_capab': ['bridge', 'router'], 'parent_interface': ''}], 'Ethernet1\/2': [{'remote_chassis_id': '5254.0007.b7e5', 'remote_port': 'Ethernet1\/2', 'remote_port_description': 'VPC Peer Link', 'remote_system_name': 'dist-sw02.devnet.lab', 'remote_system_description': 'Cisco Nexus Operating System (NX-OS) Software 9.2(3)', 'remote_system_capab': ['bridge', 'router'], 'remote_system_enable_capab': ['bridge', 'router'], 'parent_interface': ''}], 'Ethernet1\/3': [{'remote_chassis_id': '001e.7a2a.3900', 'remote_port': 'Gi4', 'remote_port_description': 'L3 Link to dist-sw01', 'remote_system_name': 'dist-rtr01.devnet.lab', 'remote_system_description': 'Cisco IOS Software [Gibraltar], Virtual XE Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Version 16.11.1b, RELEASE SOFTWARE (fc2)', 'remote_system_capab': ['bridge', 'router'], 'remote_system_enable_capab': ['router'], 'parent_interface': ''}], 'Ethernet1\/4': [{'remote_chassis_id': '001e.e57c.cf00', 'remote_port': 'Gi4', 'remote_port_description': 'L3 Link to dist-sw01', 'remote_system_name': 'dist-rtr02.devnet.lab', 'remote_system_description': 'Cisco IOS Software [Gibraltar], Virtual XE Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Version 16.11.1b, RELEASE SOFTWARE (fc2)', 'remote_system_capab': ['bridge', 'router'], 'remote_system_enable_capab': ['router'], 'parent_interface': ''}]}}<\/code><\/pre>\n<\/div><\/div>\n<p>  <\/p>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u0437 \u0441\u0435\u0431\u044f \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u0441 \u043a\u043b\u044e\u0447\u0430\u043c\u0438 &#8216;facts&#8217; &#8216;lldp_neighbors_detail&#8217; \u043f\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0433\u0435\u0442\u0442\u0435\u0440\u043e\u0432.<br \/>  \u0412\u043d\u0443\u0442\u0440\u0438 \u0432\u0441\u0435 \u0443\u0436\u0435 \u0440\u0430\u0437\u043b\u043e\u0436\u0435\u043d\u043e NAPALM&#8217;\u043e\u043c \u043f\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430\u043c \u0434\u0430\u043d\u043d\u044b\u0445.<br \/>  \u0421\u0432\u0435\u0440\u0438\u043c \u0441\u043e\u0441\u0435\u0434\u0441\u0442\u0432\u0430:<\/p>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0421\u043e\u0441\u0435\u0434\u0438 dist-rtr01<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">&gt;&gt;&gt; for neighbor in get_host_data_result['dist-rtr01'][1].result['lldp_neighbors_detail'].items(): ...     print(neighbor) ...     print('\\n') ...  ('GigabitEthernet6', [{'remote_chassis_id': '001e.e57c.cf00', 'remote_port': 'Gi6', 'remote_port_description': 'L3 Link to dist-rtr01', 'remote_system_name': 'dist-rtr02.devnet.lab', 'remote_system_description': 'Cisco IOS Software [Gibraltar], Virtual XE Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Version 16.11.1b, RELEASE SOFTWARE (fc2)', 'remote_system_capab': ['bridge', 'router'], 'remote_system_enable_capab': ['router'], 'parent_interface': ''}])  ('GigabitEthernet4', [{'remote_chassis_id': '5254.0007.5d59', 'remote_port': 'Ethernet1\/3', 'remote_port_description': 'L3 link to dist-rtr01', 'remote_system_name': 'dist-sw01.devnet.lab', 'remote_system_description': 'Cisco Nexus Operating System (NX-OS) Software 9.2(3)', 'remote_system_capab': ['bridge', 'router'], 'remote_system_enable_capab': ['bridge', 'router'], 'parent_interface': ''}])  ('GigabitEthernet5', [{'remote_chassis_id': '5254.0007.b7e6', 'remote_port': 'Ethernet1\/3', 'remote_port_description': 'L3 link to dist-rtr01', 'remote_system_name': 'dist-sw02.devnet.lab', 'remote_system_description': 'Cisco Nexus Operating System (NX-OS) Software 9.2(3)', 'remote_system_capab': ['bridge', 'router'], 'remote_system_enable_capab': ['bridge', 'router'], 'parent_interface': ''}])  ('GigabitEthernet3', [{'remote_chassis_id': '02c7.9dc0.0c06', 'remote_port': 'Gi0\/0\/0\/2', 'remote_port_description': 'L3 Link to dist-rtr01', 'remote_system_name': 'core-rtr02.devnet.lab', 'remote_system_description': 'Cisco IOS XR Software, Version 6.3.1[Default]', 'remote_system_capab': ['router'], 'remote_system_enable_capab': ['router'], 'parent_interface': ''}])  ('GigabitEthernet2', [{'remote_chassis_id': '0288.15c0.0c06', 'remote_port': 'Gi0\/0\/0\/2', 'remote_port_description': 'L3 Link to dist-rtr01', 'remote_system_name': 'core-rtr01.devnet.lab', 'remote_system_description': 'Cisco IOS XR Software, Version 6.3.1[Default]', 'remote_system_capab': ['router'], 'remote_system_enable_capab': ['router'], 'parent_interface': ''}])<\/code><\/pre>\n<\/div><\/div>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0421\u043e\u0441\u0435\u0434\u0438 dist-sw01<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">&gt;&gt;&gt; for neighbor in get_host_data_result['dist-sw01'][1].result['lldp_neighbors_detail'].items(): ...     print(neighbor) ...     print('\\n') ...  ('Ethernet1\/1', [{'remote_chassis_id': '5254.0007.b7e4', 'remote_port': 'Ethernet1\/1', 'remote_port_description': 'VPC Peer Link', 'remote_system_name': 'dist-sw02.devnet.lab', 'remote_system_description': 'Cisco Nexus Operating System (NX-OS) Software 9.2(3)', 'remote_system_capab': ['bridge', 'router'], 'remote_system_enable_capab': ['bridge', 'router'], 'parent_interface': ''}])  ('Ethernet1\/2', [{'remote_chassis_id': '5254.0007.b7e5', 'remote_port': 'Ethernet1\/2', 'remote_port_description': 'VPC Peer Link', 'remote_system_name': 'dist-sw02.devnet.lab', 'remote_system_description': 'Cisco Nexus Operating System (NX-OS) Software 9.2(3)', 'remote_system_capab': ['bridge', 'router'], 'remote_system_enable_capab': ['bridge', 'router'], 'parent_interface': ''}])  ('Ethernet1\/3', [{'remote_chassis_id': '001e.7a2a.3900', 'remote_port': 'Gi4', 'remote_port_description': 'L3 Link to dist-sw01', 'remote_system_name': 'dist-rtr01.devnet.lab', 'remote_system_description': 'Cisco IOS Software [Gibraltar], Virtual XE Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Version 16.11.1b, RELEASE SOFTWARE (fc2)', 'remote_system_capab': ['bridge', 'router'], 'remote_system_enable_capab': ['router'], 'parent_interface': ''}])  ('Ethernet1\/4', [{'remote_chassis_id': '001e.e57c.cf00', 'remote_port': 'Gi4', 'remote_port_description': 'L3 Link to dist-sw01', 'remote_system_name': 'dist-rtr02.devnet.lab', 'remote_system_description': 'Cisco IOS Software [Gibraltar], Virtual XE Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Version 16.11.1b, RELEASE SOFTWARE (fc2)', 'remote_system_capab': ['bridge', 'router'], 'remote_system_enable_capab': ['router'], 'parent_interface': ''}])<\/code><\/pre>\n<\/div><\/div>\n<p>  <\/p>\n<p>5 \u0441\u043e\u0441\u0435\u0434\u0435\u0439 \u0443 dist-rtr01, \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u0435\u0442 \u0441 \u0432\u044b\u0432\u043e\u0434\u043e\u043c \u0438\u0437 CLI \u0432\u044b\u0448\u0435.<br \/>  4 \u0441\u043e\u0441\u0435\u0434\u0430 \u0443 dist-sw01, \u0442\u043e\u0436\u0435 \u0432\u0441\u0435 \u0441\u0445\u043e\u0434\u0438\u0442\u0441\u044f.<br \/>  \u0422\u0430\u043a \u0436\u0435 \u0438 \u043d\u0430 \u0434\u0440\u0443\u0433\u0438\u0445 \u0445\u043e\u0441\u0442\u0430\u0445.  <\/p>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u043e\u0441\u0442\u0430\u043d\u0435\u043c \u0438\u0437 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043f\u043e LLDP \u0438 \u0444\u0430\u043a\u0442\u0430\u043c.<br \/>  \u0414\u043b\u044f \u0441\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0437\u0430 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u043f\u0440\u0438\u043c\u0435\u043c \u0432 \u043f\u043e\u0440\u044f\u0434\u043a\u0435 \u0443\u0431\u044b\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442\u0430:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u0415\u0433\u043e FQDN, \u0435\u0441\u043b\u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d (\u0434\u0430\u043b\u0435\u0435 \u043f\u043e \u0442\u0435\u043a\u0441\u0442\u0443 \u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0445\u043e\u0441\u0442\u043d\u0435\u0439\u043c\u043e\u043c \u0434\u043b\u044f \u0443\u043f\u0440\u043e\u0449\u0435\u043d\u0438\u044f).<\/li>\n<li>\u0415\u0433\u043e hostname, \u0435\u0441\u043b\u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d.<\/li>\n<li>\u0415\u0433\u043e \u0438\u043c\u044f \u0432 \u0445\u043e\u0441\u0442-\u043e\u0431\u044a\u0435\u043a\u0442\u0435 inventory Nornir.<br \/>  \u041f\u0435\u0440\u0432\u044b\u043c\u0438 \u0434\u0432\u0443\u043c\u044f \u043f\u0443\u043d\u043a\u0442\u0430\u043c\u0438 \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u0443\u0435\u0442\u0441\u044f \u0438 LLDP.<br \/> \n<pre><code class=\"python\">def normalize_result(nornir_job_result): &quot;&quot;&quot; \u041f\u0430\u0440\u0441\u0435\u0440 \u0434\u043b\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u0440\u0430\u0431\u043e\u0442\u044b get_host_data. \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u043b\u043e\u0432\u0430\u0440\u0438 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 LLDP \u0438 FACTS \u0441 \u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u0435\u043c \u043f\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c \u0441 \u043a\u043b\u044e\u0447\u0430\u043c\u0438 \u0432 \u0432\u0438\u0434\u0435 \u0445\u043e\u0441\u0442\u043d\u0435\u0439\u043c\u043e\u0432. &quot;&quot;&quot; global_lldp_data = {} global_facts = {} for device, output in nornir_job_result.items():     if output[0].failed:         # \u0415\u0441\u043b\u0438 \u0442\u0430\u0441\u043a \u0434\u043b\u044f \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0445\u043e\u0441\u0442\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043b\u0441\u044f \u043e\u0448\u0438\u0431\u043a\u043e\u0439,         # \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0434\u043b\u044f \u043d\u0435\u0433\u043e \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043f\u0443\u0441\u0442\u044b\u0435 \u0441\u043f\u0438\u0441\u043a\u0438.         # \u041a\u043b\u044e\u0447\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u044f\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0438\u043c\u044f \u0435\u0433\u043e host-\u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0432 \u0438\u043d\u0432\u0435\u043d\u0442\u043e\u0440\u0438.         global_lldp_data[device] = {}         global_facts[device] = {             'nr_ip': nr.inventory.hosts[device].get('hostname', 'n\/a'),         }         continue     # \u0414\u043b\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u0435\u043d\u0438\u044f \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u0432 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u043f\u0440\u0438 \u0435\u0435 \u0430\u043d\u0430\u043b\u0438\u0437\u0435     # \u0437\u0430 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f FQDN \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430, \u043a\u0430\u043a \u0438 \u0432 LLDP TLV.     device_fqdn = output[1].result['facts']['fqdn']     if not device_fqdn:         # \u0415\u0441\u043b\u0438 FQDN \u043d\u0435 \u0437\u0430\u0434\u0430\u043d, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0445\u043e\u0441\u0442\u043d\u0435\u0439\u043c.         device_fqdn = output[1].result['facts']['hostname']     if not device_fqdn:         # \u0415\u0441\u043b\u0438 \u0438 \u0445\u043e\u0441\u0442\u043d\u0435\u0439\u043c \u043d\u0435 \u0437\u0430\u0434\u0430\u043d,         # \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0438\u043c\u044f host-\u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0432 \u0438\u043d\u0432\u0435\u043d\u0442\u043e\u0440\u0438.         device_fqdn = device     global_facts[device_fqdn] = output[1].result['facts']     # \u0414\u043e\u043f\u0438\u0448\u0435\u043c \u0432 facts IP-\u0430\u0434\u0440\u0435\u0441 \u043e\u0431\u043e\u0440\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u044f     global_facts[device_fqdn]['nr_ip'] = nr.inventory.hosts[device].get('hostname', 'n\/a')     global_lldp_data[device_fqdn] = output[1].result['lldp_neighbors_detail'] return global_lldp_data, global_facts<\/code><\/pre>\n<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0418\u0437 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e LLDP \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u0437\u0432\u043b\u0435\u0447\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u0441\u0435\u0445 \u0441\u043e\u0441\u0435\u0434\u0441\u0442\u0432 \u0441\u043e \u0432\u0441\u0435\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u0438 \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0435\u0433\u043e \u043e\u0441\u043d\u043e\u0432\u0435:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u0421\u043f\u0438\u0441\u043e\u043a \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u0445\u043e\u0441\u0442\u043e\u0432.<\/li>\n<li>\u0421\u043f\u0438\u0441\u043e\u043a \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u043b\u0438\u043d\u043a\u043e\u0432 \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043e\u0434\u043d\u043e\u0437\u043d\u0430\u0447\u043d\u043e\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u043b\u0438\u043d\u043a\u043e\u0432 \u0431\u0443\u0434\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0438\u0445 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435:<br \/>  ((source_device_id, source_port_name), (destination_device_id, destination_port_name))  <\/p>\n<p>  <\/p>\n<p>\u0421\u0442\u043e\u0438\u0442 \u0442\u0430\u043a\u0436\u0435 \u0443\u0447\u0435\u0441\u0442\u044c, \u0447\u0442\u043e:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u041e\u0434\u0438\u043d \u0438 \u0442\u043e\u0442 \u0436\u0435 \u043b\u0438\u043d\u043a \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0432\u0438\u0434\u0435\u043d \u0441 \u0440\u0430\u0437\u043d\u044b\u0445 \u0441\u0442\u043e\u0440\u043e\u043d \u0441 \u0434\u0432\u0443\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432, \u0435\u0441\u043b\u0438 \u043d\u0430 \u043e\u0431\u0430 \u0435\u0441\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f.<br \/>  \u041d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0438 \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u043d\u043e\u0432\u044b\u0445 \u043b\u0438\u043d\u043a\u043e\u0432.<\/li>\n<li>\u041b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0435 \u0438\u043c\u044f \u043f\u043e\u0440\u0442\u0430 \u0438 \u0430\u043d\u043e\u043d\u0441\u0438\u0440\u0443\u0435\u043c\u043e\u0435 \u043f\u043e LLDP \u043c\u043e\u0436\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0440\u0430\u0437\u043d\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, GigabitEthernet4 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e, \u043d\u043e Gi4 \u0432 \u0430\u043d\u043e\u043d\u0441\u0435.\n<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043e\u0434\u043d\u043e\u0437\u043d\u0430\u0447\u043d\u043e\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0431\u0443\u0434\u0435\u043c \u0442\u0440\u0430\u043d\u0441\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u0432 \u043f\u043e\u043b\u043d\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442. \u0418 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0434\u043b\u044f \u0442\u0440\u0430\u043d\u0441\u043b\u044f\u0446\u0438\u0438 \u0432 \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u043d\u044b\u0439 \u0432\u0438\u0434 \u0434\u043b\u044f \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0433\u043e \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438.<br \/>  \u0414\u043b\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0432\u044b\u0431\u043e\u0440\u0430 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0439 \u043f\u0438\u043a\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u043f\u0440\u0438 \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0431\u0443\u0434\u0435\u043c \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c \u0435\u0433\u043e capabilities, \u0430\u043d\u043e\u043d\u0441\u0438\u0440\u0443\u0435\u043c\u044b\u0435 \u043f\u043e LLDP. \u0421\u0432\u0435\u0434\u0435\u043c \u0438\u0445 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u043f\u043e \u0445\u043e\u0441\u0442\u043d\u0435\u0439\u043c\u0430\u043c.<br \/>  \u041a\u043e\u0434:<\/p>\n<p>  <\/p>\n<pre><code class=\"python\">interface_full_name_map = {     'Eth': 'Ethernet',     'Fa': 'FastEthernet',     'Gi': 'GigabitEthernet',     'Te': 'TenGigabitEthernet', }  def if_fullname(ifname):     for k, v in interface_full_name_map.items():         if ifname.startswith(v):             return ifname         if ifname.startswith(k):             return ifname.replace(k, v)     return ifname  def if_shortname(ifname):     for k, v in interface_full_name_map.items():         if ifname.startswith(v):             return ifname.replace(v, k)     return ifname  def extract_lldp_details(lldp_data_dict):     &quot;&quot;&quot;     \u041f\u0430\u0440\u0441\u0435\u0440 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 \u0441\u043b\u043e\u0432\u0430\u0440\u044f LLDP-\u0434\u0430\u043d\u043d\u044b\u0445.     \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u0435\u0442 \u0438\u0437 \u0432\u0441\u0435\u0445 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u043d\u044b\u0445 \u0432 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u0445\u043e\u0441\u0442\u043e\u0432,     \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u043d\u044b\u0445 LLDP capabilities \u0441 \u043a\u043b\u044e\u0447\u0430\u043c\u0438 \u0432 \u0432\u0438\u0434\u0435     \u0445\u043e\u0441\u0442\u043d\u0435\u0439\u043c\u043e\u0432 \u0438 \u0441\u043f\u0438\u0441\u043e\u043a \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u0441\u0432\u044f\u0437\u043d\u043e\u0441\u0442\u0435\u0439 \u043c\u0435\u0436\u0434\u0443 \u0445\u043e\u0441\u0442\u0430\u043c\u0438.     &quot;&quot;&quot;     discovered_hosts = set()     lldp_capabilities_dict = {}     global_interconnections = []     for host, lldp_data in lldp_data_dict.items():         if not host:             continue         discovered_hosts.add(host)         if not lldp_data:             continue         for interface, neighbors in lldp_data.items():             for neighbor in neighbors:                 if not neighbor['remote_system_name']:                     continue                 discovered_hosts.add(neighbor['remote_system_name'])                 if neighbor['remote_system_enable_capab']:                     # \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0430\u043b\u0438\u0447\u0438\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 enable capabilities                     # \u0432 \u0440\u0430\u0441\u0447\u0435\u0442 \u0431\u0435\u0440\u0435\u0442\u0441\u044f \u043f\u0435\u0440\u0432\u0430\u044f \u043f\u043e \u0441\u043f\u0438\u0441\u043a\u0443                     lldp_capabilities_dict[neighbor['remote_system_name']] = (                         neighbor['remote_system_enable_capab'][0]                     )                 else:                     lldp_capabilities_dict[neighbor['remote_system_name']] = ''                 # \u0421\u0432\u044f\u0437\u0438 \u043c\u0435\u0436\u0434\u0443 \u0445\u043e\u0441\u0442\u0430\u043c\u0438 \u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044e\u0442\u0441\u044f \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435:                 # ((\u0445\u043e\u0441\u0442\u043d\u0435\u0439\u043c_\u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430, \u043f\u043e\u0440\u0442 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430), (\u0445\u043e\u0441\u0442\u043d\u0435\u0439\u043c \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u043f\u043e\u0440\u0442_\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f))                 # \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0432 \u043e\u0431\u0449\u0438\u0439 \u0441\u043f\u0438\u0441\u043e\u043a.                 local_end = (host, interface)                 remote_end = (                     neighbor['remote_system_name'],                     if_fullname(neighbor['remote_port'])                 )                 # \u041f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f, \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043b\u0438 \u043b\u0438\u043d\u043a \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u043e\u0439                 # \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0438 \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438\u043b\u0438 \u0434\u0443\u0431\u043b\u0435\u043c.                 link_is_already_there = (                     (local_end, remote_end) in global_interconnections                     or (remote_end, local_end) in global_interconnections                 )                 if link_is_already_there:                     continue                 global_interconnections.append((                     (host, interface),                     (neighbor['remote_system_name'], if_fullname(neighbor['remote_port']))                 ))     return [discovered_hosts, global_interconnections, lldp_capabilities_dict]<\/code><\/pre>\n<p>  <\/p>\n<h3 id=\"inicializaciya-prilozheniya-next-ui\">\u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f NeXt UI<\/h3>\n<p>  <\/p>\n<p>\u0417\u0430 \u0432\u0441\u044e \u043b\u043e\u0433\u0438\u043a\u0443 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u0432\u0435\u0447\u0430\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442 <b>next_app.js<\/b> \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 NeXt UI.<br \/>  \u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u0432\u0435\u0449\u0435\u0439:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">(function (nx) {     \/**      * \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 NeXt UI      *\/     \/\/ \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438     var topo = new nx.graphic.Topology({         \/\/ \u0428\u0438\u0440\u0438\u043d\u0430 \u0438 \u0432\u044b\u0441\u043e\u0442\u0430 view \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f         width: 1200,         height: 700,         \/\/ \u041f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440 \u0434\u0430\u043d\u043d\u044b\u0445, \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0440\u0430\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0443 \u043d\u043e\u0434.         \/\/ 'force' \u0441\u0442\u0440\u0435\u043c\u0438\u0442\u0441\u044f \u0440\u0430\u0441\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u0434\u044b \u043d\u0430 \u0440\u0430\u0432\u043d\u043e\u043c          \/\/ \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0438 \u0434\u0440\u0443\u0433 \u043e\u0442 \u0434\u0440\u0443\u0433\u0430. 'quick' \u0440\u0430\u0441\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u0445         \/\/ \u0432 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u0445 \u043c\u0435\u0441\u0442\u0430\u0445         dataProcessor: 'force',         \/\/ \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u043d\u043e\u0434 \u0438 \u043b\u0438\u043d\u043a\u043e\u0432         identityKey: 'id',         \/\/ \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u043d\u043e\u0434         nodeConfig: {             label: 'model.name',             iconType:'model.icon',         },         \/\/ \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u043b\u0438\u043d\u043a\u043e\u0432         linkConfig: {             \/\/ \u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u043b\u0438\u043d\u043a\u043e\u0432 \u0434\u0443\u0433\u0430\u043c\u0438,             \/\/ \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043c\u0435\u043d\u044f\u0442\u044c \u043d\u0430 'parallel'             linkType: 'curve',         },         \/\/ \u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u043f\u0438\u043a\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u043d\u043e\u0434, \u043f\u0440\u0438 false \u043e\u0442\u0440\u0438\u0441\u0443\u0435\u0442 \u0442\u043e\u0447\u043a\u0443         showIcon: true,     });      var Shell = nx.define(nx.ui.Application, {         methods: {             start: function () {                 \/\/ \u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u0438\u0437 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439                 topo.data(topologyData);                 \/\/ \u0438 \u043f\u0440\u0438\u043a\u0440\u0435\u043f\u0438\u0442\u044c \u0438\u0445 \u043a \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0443                 topo.attach(this);             }         }     });      \/\/ \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0438\u043d\u0441\u0442\u0430\u043d\u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f     var shell = new Shell();     \/\/ \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435     shell.start(); })(nx);<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u043e\u043f\u043e\u043b\u043e\u043b\u043e\u0433\u0438\u044f \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0438\u0437 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 <b>topologyData<\/b>, \u0432\u044b\u043d\u0435\u0441\u0435\u043c \u0435\u0435 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0444\u0430\u0439\u043b <b>topology.js<\/b>. \u0415\u0435 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0438\u0436\u0435.  <\/p>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u0430\u044f HTML \u0444\u043e\u0440\u043c\u0430, \u043a\u0443\u0434\u0430 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043c \u0432\u0441\u0435 \u0441\u043e\u0441\u0442\u0430\u0432\u043d\u044b\u0435 \u0447\u0430\u0441\u0442\u0438:<\/p>\n<p>  <\/p>\n<pre><code class=\"html\">&lt;!DOCTYPE html&gt;  &lt;html&gt;     &lt;head&gt;         &lt;meta charset=&quot;utf-8&quot;&gt;         &lt;link rel=&quot;stylesheet&quot; href=&quot;next_sources\/css\/next.css&quot;&gt;         &lt;link rel=&quot;stylesheet&quot; href=&quot;styles_main_page.css&quot;&gt;         &lt;script src=&quot;next_sources\/js\/next.js&quot;&gt;&lt;\/script&gt;         &lt;script src=&quot;topology.js&quot;&gt;&lt;\/script&gt;         &lt;script src=&quot;next_app.js&quot;&gt;&lt;\/script&gt;     &lt;\/head&gt;     &lt;body&gt;     &lt;\/body&gt; &lt;\/html&gt;<\/code><\/pre>\n<p>  <\/p>\n<h3 id=\"formirovanie-topologii-dlya-next-ui-v-python\">\u0424\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u0434\u043b\u044f NeXT UI \u0432 Python<\/h3>\n<p>  <\/p>\n<p>\u0420\u0430\u043d\u0435\u0435 \u043c\u044b \u0443\u0436\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u0431\u0430\u0437\u043e\u0432\u043e\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u0432 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 Python.<br \/>  \u041f\u0440\u0438\u043c\u0435\u043d\u0438\u043c \u0438\u0445 \u0432 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0438:<\/p>\n<p>  <\/p>\n<pre><code class=\"python\">GLOBAL_LLDP_DATA, GLOBAL_FACTS = normalize_result(get_host_data_result) TOPOLOGY_DETAILS = extract_lldp_details(GLOBAL_LLDP_DATA)<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u0434\u043b\u044f NeXt UI \u0438\u043c\u0435\u0435\u0442 \u0432\u0438\u0434:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ \u0434\u0432\u0435 \u043d\u043e\u0434\u044b \u0438 \u0434\u0432\u0430 \u043b\u0438\u043d\u043a\u0430 \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438 var topologyData = {     &quot;links&quot;: [         {             &quot;id&quot;: 0,             &quot;source&quot;: 0,             &quot;target&quot;: 1,         }, {             &quot;id&quot;: 1,             &quot;source&quot;: 0,             &quot;target&quot;: 1,         }     ],     &quot;nodes&quot;: [         {             &quot;icon&quot;: &quot;router&quot;,             &quot;id&quot;: 0,         },         {             &quot;icon&quot;: &quot;router&quot;,             &quot;id&quot;: 1,         }     ]<\/code><\/pre>\n<p>  <\/p>\n<p>\u041a\u0430\u043a \u0432\u0438\u0434\u043d\u043e, \u044d\u0442\u043e JSON \u043e\u0431\u044a\u0435\u043a\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u043c\u0430\u043f\u043f\u0438\u0442\u0441\u044f \u0432 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0441\u043b\u043e\u0432\u0430\u0440\u044f \u0432\u0438\u0434\u0430:<br \/>  {&#8216;nodes&#8217;: [], &#8216;links&#8217;: []} \u043d\u0430 Python.<br \/>  \u0421\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0435\u0433\u043e \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0438\u043c\u0435\u044e\u0449\u0438\u0445\u0441\u044f \u0434\u0430\u043d\u043d\u044b\u0445. <br \/>  \u0414\u043b\u044f \u0432\u044b\u0431\u043e\u0440\u0430 \u0442\u0438\u043f\u0430 \u043f\u0438\u043a\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0434\u043b\u044f \u043d\u043e\u0434 \u0442\u0430\u043a\u0436\u0435 \u0443\u0447\u0442\u0435\u043c \u043c\u043e\u0434\u0435\u043b\u044c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430, \u0435\u0441\u043b\u0438 capabilities \u0432 LLDP \u0431\u044b\u043b\u0438 \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u043d\u0438\u043a\u043e\u043c\u0443 \u0438\u0437 \u0441\u043e\u0441\u0435\u0434\u0435\u0439, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0435\u0441\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f. <br \/>  \u0412 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u043d\u043e\u0434 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u044b\u0435 \u0438\u0437 FACTS \u0434\u0430\u043d\u043d\u044b\u0435 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043c\u043e\u0434\u0435\u043b\u044c \u0438 \u0441\u0435\u0440\u0438\u0439\u043d\u044b\u0439 \u043d\u043e\u043c\u0435\u0440), \u0438\u0445 \u043f\u043e\u0442\u043e\u043c \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438.<\/p>\n<p>  <\/p>\n<pre><code class=\"python\">icon_capability_map = {     'router': 'router',     'switch': 'switch',     'bridge': 'switch',     'station': 'host' }  icon_model_map = {     'CSR1000V': 'router',     'Nexus': 'switch',     'IOSXRv': 'router',     'IOSv': 'switch',     '2901': 'router',     '2911': 'router',     '2921': 'router',     '2951': 'router',     '4321': 'router',     '4331': 'router',     '4351': 'router',     '4421': 'router',     '4431': 'router',     '4451': 'router',     '2960': 'switch',     '3750': 'switch',     '3850': 'switch', }  def get_icon_type(device_cap_name, device_model=''):     &quot;&quot;&quot;     \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0442\u0438\u043f\u0430 \u043f\u0438\u043a\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430.     \u041f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442 \u0438\u043c\u0435\u0435\u0442 \u043c\u0430\u043f\u043f\u0438\u043d\u0433 LLDP capabilities.     \u0415\u0441\u043b\u0438 \u043f\u043e \u043d\u0438\u043c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0442\u0438\u043f \u043f\u0438\u043a\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c,     \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u043e \u043c\u043e\u0434\u0435\u043b\u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430.     \u041f\u0440\u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0442\u0438\u043f \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e 'unknown'.     &quot;&quot;&quot;     if device_cap_name:         icon_type = icon_capability_map.get(device_cap_name)         if icon_type:             return icon_type     if device_model:         # \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f \u0432\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u0435 \u043f\u043e\u0434\u0441\u0442\u0440\u043e\u043a\u0438 \u0438\u0437 \u043a\u043b\u044e\u0447\u0435\u0439 icon_model_map         # \u0412 \u0441\u0442\u0440\u043e\u043a\u0435 \u043c\u043e\u0434\u0435\u043b\u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0434\u043e \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u044f         for model_shortname, icon_type in icon_model_map.items():             if model_shortname in device_model:                 return icon_type     return 'unknown'  def generate_topology_json(*args):     &quot;&quot;&quot;     \u0413\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440 JSON-\u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438.     \u041d\u0430 \u0432\u0445\u043e\u0434 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0441\u0435\u0442 \u0438\u0437 \u0432\u0441\u0435\u0445 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u043d\u044b\u0445 \u0432 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u0445\u043e\u0441\u0442\u043e\u0432,     \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u043d\u044b\u0445 LLDP capabilities \u0441 \u043a\u043b\u044e\u0447\u0430\u043c\u0438 \u0432 \u0432\u0438\u0434\u0435     \u0445\u043e\u0441\u0442\u043d\u0435\u0439\u043c\u043e\u0432, \u0441\u043f\u0438\u0441\u043e\u043a \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u0441\u0432\u044f\u0437\u043d\u043e\u0441\u0442\u0435\u0439 \u043c\u0435\u0436\u0434\u0443 \u0445\u043e\u0441\u0442\u0430\u043c\u0438 \u0438 \u0441\u043b\u043e\u0432\u0430\u0440\u044c     \u0441 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043e\u0431 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u0445 \u0441 \u043a\u043b\u044e\u0447\u0430\u043c\u0438 \u0432 \u0432\u0438\u0434\u0435 \u0445\u043e\u0441\u0442\u043d\u0435\u0439\u043c\u043e\u0432.     &quot;&quot;&quot;     discovered_hosts, interconnections, lldp_capabilities_dict, facts = args     host_id = 0     host_id_map = {}     topology_dict = {'nodes': [], 'links': []}     for host in discovered_hosts:         device_model = 'n\/a'         device_serial = 'n\/a'         device_ip = 'n\/a'         if facts.get(host):             device_model = facts[host].get('model', 'n\/a')             device_serial = facts[host].get('serial_number', 'n\/a')             device_ip = facts[host].get('nr_ip', 'n\/a')         host_id_map[host] = host_id         topology_dict['nodes'].append({             'id': host_id,             'name': host,             'primaryIP': device_ip,             'model': device_model,             'serial_number': device_serial,             'icon': get_icon_type(                 lldp_capabilities_dict.get(host, ''),                 device_model             )         })         host_id += 1     link_id = 0     for link in interconnections:         topology_dict['links'].append({             'id': link_id,             'source': host_id_map[link[0][0]],             'target': host_id_map[link[1][0]],             'srcIfName': if_shortname(link[0][1]),             'srcDevice': link[0][0],             'tgtIfName': if_shortname(link[1][1]),             'tgtDevice': link[1][0],         })         link_id += 1     return topology_dict<\/code><\/pre>\n<p>  <\/p>\n<p>\u0414\u0430\u043b\u044c\u0448\u0435 \u0434\u0435\u043b\u043e \u0437\u0430 \u043c\u0430\u043b\u044b\u043c, \u0437\u0430\u043f\u0438\u0448\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0432\u0448\u0438\u0439\u0441\u044f \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u0432 \u0444\u0430\u0439\u043b <b>topology.js<\/b>, \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u043c \u043c\u043e\u0434\u0443\u043b\u0435\u043c <b>json<\/b> \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0447\u0438\u0442\u0430\u0431\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0438 \u0437\u0430\u043f\u0438\u0441\u0438:<\/p>\n<p>  <\/p>\n<pre><code class=\"python\">import json  OUTPUT_TOPOLOGY_FILENAME = 'topology.js' TOPOLOGY_FILE_HEAD = &quot;\\n\\nvar topologyData = &quot;  def write_topology_file(topology_json, header=TOPOLOGY_FILE_HEAD, dst=OUTPUT_TOPOLOGY_FILENAME):     with open(dst, 'w') as topology_file:         topology_file.write(header)         topology_file.write(json.dumps(topology_json, indent=4, sort_keys=True))         topology_file.write(';')  TOPOLOGY_DICT = generate_topology_json(*TOPOLOGY_DETAILS) write_topology_file(TOPOLOGY_DICT)<\/code><\/pre>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041f\u043e\u043b\u0443\u0447\u0438\u0432\u0448\u0438\u0439\u0441\u044f \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 topology.js<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\"> var topologyData = {     &quot;links&quot;: [         {             &quot;id&quot;: 0,             &quot;source&quot;: 7,             &quot;srcDevice&quot;: &quot;edge-sw01.devnet.lab&quot;,             &quot;srcIfName&quot;: &quot;Gi0\/2&quot;,             &quot;target&quot;: 5,             &quot;tgtDevice&quot;: &quot;core-rtr01.devnet.lab&quot;,             &quot;tgtIfName&quot;: &quot;Gi0\/0\/0\/1&quot;         },         {             &quot;id&quot;: 1,             &quot;source&quot;: 7,             &quot;srcDevice&quot;: &quot;edge-sw01.devnet.lab&quot;,             &quot;srcIfName&quot;: &quot;Gi0\/3&quot;,             &quot;target&quot;: 3,             &quot;tgtDevice&quot;: &quot;core-rtr02.devnet.lab&quot;,             &quot;tgtIfName&quot;: &quot;Gi0\/0\/0\/1&quot;         },         {             &quot;id&quot;: 2,             &quot;source&quot;: 4,             &quot;srcDevice&quot;: &quot;dist-rtr01.devnet.lab&quot;,             &quot;srcIfName&quot;: &quot;Gi3&quot;,             &quot;target&quot;: 3,             &quot;tgtDevice&quot;: &quot;core-rtr02.devnet.lab&quot;,             &quot;tgtIfName&quot;: &quot;Gi0\/0\/0\/2&quot;         },         {             &quot;id&quot;: 3,             &quot;source&quot;: 4,             &quot;srcDevice&quot;: &quot;dist-rtr01.devnet.lab&quot;,             &quot;srcIfName&quot;: &quot;Gi4&quot;,             &quot;target&quot;: 1,             &quot;tgtDevice&quot;: &quot;dist-sw01.devnet.lab&quot;,             &quot;tgtIfName&quot;: &quot;Eth1\/3&quot;         },         {             &quot;id&quot;: 4,             &quot;source&quot;: 4,             &quot;srcDevice&quot;: &quot;dist-rtr01.devnet.lab&quot;,             &quot;srcIfName&quot;: &quot;Gi6&quot;,             &quot;target&quot;: 0,             &quot;tgtDevice&quot;: &quot;dist-rtr02.devnet.lab&quot;,             &quot;tgtIfName&quot;: &quot;Gi6&quot;         },         {             &quot;id&quot;: 5,             &quot;source&quot;: 4,             &quot;srcDevice&quot;: &quot;dist-rtr01.devnet.lab&quot;,             &quot;srcIfName&quot;: &quot;Gi5&quot;,             &quot;target&quot;: 2,             &quot;tgtDevice&quot;: &quot;dist-sw02.devnet.lab&quot;,             &quot;tgtIfName&quot;: &quot;Eth1\/3&quot;         },         {             &quot;id&quot;: 6,             &quot;source&quot;: 4,             &quot;srcDevice&quot;: &quot;dist-rtr01.devnet.lab&quot;,             &quot;srcIfName&quot;: &quot;Gi2&quot;,             &quot;target&quot;: 5,             &quot;tgtDevice&quot;: &quot;core-rtr01.devnet.lab&quot;,             &quot;tgtIfName&quot;: &quot;Gi0\/0\/0\/2&quot;         },         {             &quot;id&quot;: 7,             &quot;source&quot;: 0,             &quot;srcDevice&quot;: &quot;dist-rtr02.devnet.lab&quot;,             &quot;srcIfName&quot;: &quot;Gi3&quot;,             &quot;target&quot;: 3,             &quot;tgtDevice&quot;: &quot;core-rtr02.devnet.lab&quot;,             &quot;tgtIfName&quot;: &quot;Gi0\/0\/0\/3&quot;         },         {             &quot;id&quot;: 8,             &quot;source&quot;: 0,             &quot;srcDevice&quot;: &quot;dist-rtr02.devnet.lab&quot;,             &quot;srcIfName&quot;: &quot;Gi4&quot;,             &quot;target&quot;: 1,             &quot;tgtDevice&quot;: &quot;dist-sw01.devnet.lab&quot;,             &quot;tgtIfName&quot;: &quot;Eth1\/4&quot;         },         {             &quot;id&quot;: 9,             &quot;source&quot;: 0,             &quot;srcDevice&quot;: &quot;dist-rtr02.devnet.lab&quot;,             &quot;srcIfName&quot;: &quot;Gi5&quot;,             &quot;target&quot;: 2,             &quot;tgtDevice&quot;: &quot;dist-sw02.devnet.lab&quot;,             &quot;tgtIfName&quot;: &quot;Eth1\/4&quot;         },         {             &quot;id&quot;: 10,             &quot;source&quot;: 0,             &quot;srcDevice&quot;: &quot;dist-rtr02.devnet.lab&quot;,             &quot;srcIfName&quot;: &quot;Gi2&quot;,             &quot;target&quot;: 5,             &quot;tgtDevice&quot;: &quot;core-rtr01.devnet.lab&quot;,             &quot;tgtIfName&quot;: &quot;Gi0\/0\/0\/3&quot;         },         {             &quot;id&quot;: 11,             &quot;source&quot;: 1,             &quot;srcDevice&quot;: &quot;dist-sw01.devnet.lab&quot;,             &quot;srcIfName&quot;: &quot;Eth1\/1&quot;,             &quot;target&quot;: 2,             &quot;tgtDevice&quot;: &quot;dist-sw02.devnet.lab&quot;,             &quot;tgtIfName&quot;: &quot;Eth1\/1&quot;         },         {             &quot;id&quot;: 12,             &quot;source&quot;: 1,             &quot;srcDevice&quot;: &quot;dist-sw01.devnet.lab&quot;,             &quot;srcIfName&quot;: &quot;Eth1\/2&quot;,             &quot;target&quot;: 2,             &quot;tgtDevice&quot;: &quot;dist-sw02.devnet.lab&quot;,             &quot;tgtIfName&quot;: &quot;Eth1\/2&quot;         }     ],     &quot;nodes&quot;: [         {             &quot;icon&quot;: &quot;router&quot;,             &quot;id&quot;: 0,             &quot;model&quot;: &quot;CSR1000V&quot;,             &quot;name&quot;: &quot;dist-rtr02.devnet.lab&quot;,             &quot;serial_number&quot;: &quot;9YZKNQKQ566&quot;,             &quot;layerSortPreference&quot;: 7,             &quot;primaryIP&quot;: &quot;10.10.20.176&quot;,             &quot;dcimDeviceLink&quot;: &quot;http:\/\/localhost:32768\/dcim\/devices\/?q=dist-rtr02.devnet.lab&quot;         },         {             &quot;icon&quot;: &quot;switch&quot;,             &quot;id&quot;: 1,             &quot;model&quot;: &quot;Nexus9000 9000v Chassis&quot;,             &quot;name&quot;: &quot;dist-sw01.devnet.lab&quot;,             &quot;serial_number&quot;: &quot;9MZLNM0ZC9Z&quot;,         },         {             &quot;icon&quot;: &quot;switch&quot;,             &quot;id&quot;: 2,             &quot;model&quot;: &quot;Nexus9000 9000v Chassis&quot;,             &quot;name&quot;: &quot;dist-sw02.devnet.lab&quot;,             &quot;serial_number&quot;: &quot;93LCGCRUJA5&quot;,         },         {             &quot;icon&quot;: &quot;router&quot;,             &quot;id&quot;: 3,             &quot;model&quot;: &quot;n\/a&quot;,             &quot;name&quot;: &quot;core-rtr02.devnet.lab&quot;,             &quot;serial_number&quot;: &quot;n\/a&quot;,         },         {             &quot;icon&quot;: &quot;router&quot;,             &quot;id&quot;: 4,             &quot;model&quot;: &quot;CSR1000V&quot;,             &quot;name&quot;: &quot;dist-rtr01.devnet.lab&quot;,             &quot;serial_number&quot;: &quot;9S78ZRF2V2B&quot;,         },         {             &quot;icon&quot;: &quot;router&quot;,             &quot;id&quot;: 5,             &quot;model&quot;: &quot;n\/a&quot;,             &quot;name&quot;: &quot;core-rtr01.devnet.lab&quot;,             &quot;serial_number&quot;: &quot;n\/a&quot;,         },         {             &quot;icon&quot;: &quot;router&quot;,             &quot;id&quot;: 6,             &quot;model&quot;: &quot;CSR1000V&quot;,             &quot;name&quot;: &quot;internet-rtr01.virl.info&quot;,             &quot;serial_number&quot;: &quot;9LGWPM8GTV6&quot;,         },         {             &quot;icon&quot;: &quot;switch&quot;,             &quot;id&quot;: 7,             &quot;model&quot;: &quot;IOSv&quot;,             &quot;name&quot;: &quot;edge-sw01.devnet.lab&quot;,             &quot;serial_number&quot;: &quot;927A4RELIGI&quot;,         }     ] };<\/code><\/pre>\n<\/div><\/div>\n<p>  <\/p>\n<p>\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u043c main.html \u0438 \u0443\u0432\u0438\u0434\u0438\u043c \u043d\u0430\u0448 \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 Hello World:<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/h_\/bo\/k-\/h_bok-ejmfmzhxj9ppjhrjub2hk.png\"><br \/>  \u041f\u043e\u0445\u043e\u0436\u0435 \u043d\u0430 \u043f\u0440\u0430\u0432\u0434\u0443. \u0412\u0441\u0435 \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u044b\u0435 \u043d\u043e\u0434\u044b \u0438 \u043b\u0438\u043d\u043a\u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u044b.<br \/>  \u041d\u043e\u0434\u044b \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u0434\u0435\u043b\u044f\u0442\u044c \u0438 \u043f\u0435\u0440\u0435\u0442\u0430\u0441\u043a\u0438\u0432\u0430\u0442\u044c \u043c\u044b\u0448\u044c\u044e \u0432 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u043e\u043c \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0438, \u043f\u0440\u0438 \u043a\u043b\u0438\u043a\u0435 \u043d\u0430 \u043d\u043e\u0434\u044b \u0438 \u043b\u0438\u043d\u043a\u0438 \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u0430\u044f \u0432 NeXt UI \u0444\u043e\u0440\u043c\u0430 \u0441 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u043b\u0438 \u0432 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u043d\u043e\u0434 \u0432 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u044e:<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/d8\/hn\/j1\/d8hnj1fe0u5xduawmcw5ce2t720.png\"><br \/>  \u0423\u0436\u0435 \u043d\u0435\u043f\u043b\u043e\u0445\u043e, \u043d\u043e \u043c\u043e\u0436\u043d\u043e \u043b\u0443\u0447\u0448\u0435. \u0412\u0435\u0440\u043d\u0435\u043c\u0441\u044f \u043a \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044e \u043f\u043e\u0437\u0436\u0435, \u0430 \u043f\u043e\u043a\u0430 \u0437\u0430\u0439\u043c\u0435\u043c\u0441\u044f \u0432\u0442\u043e\u0440\u043e\u0439 \u0447\u0430\u0441\u0442\u044c\u044e \u0437\u0430\u0434\u0430\u0447\u0438.<\/p>\n<p>  <\/p>\n<h1 id=\"poisk-i-vizualizaciya-izmeneniy-v-topologii\">\u041f\u043e\u0438\u0441\u043a \u0438 \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438<\/h1>\n<p>  <\/p>\n<p>\u041f\u043e \u0443\u0441\u043b\u043e\u0432\u0438\u044e \u0431\u044b\u043b\u0430 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u043d\u0430 \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438.<br \/>  \u0420\u0435\u0448\u0438\u043c \u0438 \u0435\u0435. \u0421\u043f\u0435\u0440\u0432\u0430, \u0432\u0432\u0435\u0434\u0435\u043c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u0424\u0430\u0439\u043b <b>cached_topology.json<\/b> \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438.<br \/>  \u041e\u043d \u0431\u0443\u0434\u0435\u0442 \u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0441\u0442\u0430\u0440\u0442\u0435 <strong>generate_topology.py<\/strong> \u0434\u043b\u044f \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u0438 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u043e\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0435\u0439 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438.<\/li>\n<li>\u0424\u0430\u0439\u043b <strong>diff_topology.js<\/strong> \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u0441 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f\u043c\u0438.<\/li>\n<li>\u0424\u0430\u0439\u043b <strong>diff_page.html<\/strong> \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>HTML-\u0444\u043e\u0440\u043c\u0430 \u0434\u043b\u044f \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438:<\/p>\n<p>  <\/p>\n<pre><code class=\"html\">&lt;!DOCTYPE html&gt;  &lt;html&gt;     &lt;head&gt;         &lt;meta charset=&quot;utf-8&quot;&gt;         &lt;link rel=&quot;stylesheet&quot; href=&quot;next_sources\/css\/next.css&quot;&gt;         &lt;link rel=&quot;stylesheet&quot; href=&quot;styles_main_page.css&quot;&gt;         &lt;script src=&quot;next_sources\/js\/next.js&quot;&gt;&lt;\/script&gt;         &lt;script src=&quot;diff_topology.js&quot;&gt;&lt;\/script&gt;         &lt;script src=&quot;next_app.js&quot;&gt;&lt;\/script&gt;     &lt;\/head&gt;     &lt;body&gt;         &lt;a href=&quot;main.html&quot;&gt;&lt;button&gt;\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u044e&lt;\/button&gt;&lt;\/a&gt;         &lt;\/p&gt;     &lt;\/body&gt; &lt;\/html&gt;<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0435 \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u0438 \u0437\u0430\u043f\u0438\u0441\u0438 \u043a\u044d\u0448\u0430 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438:<\/p>\n<p>  <\/p>\n<pre><code class=\"python\">CACHED_TOPOLOGY_FILENAME = 'cached_topology.json'  def write_topology_cache(topology_json, dst=CACHED_TOPOLOGY_FILENAME):     with open(dst, 'w') as cached_file:         cached_file.write(json.dumps(topology_json, indent=4, sort_keys=True))  def read_cached_topology(filename=CACHED_TOPOLOGY_FILENAME):     if not os.path.exists(filename):         return {}     if not os.path.isfile(filename):         return {}     cached_topology = {}     with open(filename, 'r') as file:         try:             cached_topology = json.loads(file.read())         except:             return {}     return cached_topology<\/code><\/pre>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u0438 \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438:<\/p>\n<p>  <\/p>\n<ol>\n<li>\u0418\u0437 \u0441\u043b\u043e\u0432\u0430\u0440\u0435\u0439 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0438 \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u043b\u044f \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b \u043d\u043e\u0434 \u0438 \u043b\u0438\u043d\u043a\u043e\u0432.<br \/>  \u0424\u043e\u0440\u043c\u0430\u0442 \u0434\u043b\u044f \u043d\u043e\u0434:<br \/>  (\u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u043e\u0434\u044b \u0441 \u043f\u043e\u043b\u043d\u044b\u043c \u043d\u0430\u0431\u043e\u0440\u043e\u043c \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u0432, (\u0445\u043e\u0441\u0442\u043d\u0435\u0439\u043c,))<br \/>  \u0424\u043e\u0440\u043c\u0430\u0442 \u0434\u043b\u044f \u043b\u0438\u043d\u043a\u043e\u0432:<br \/>  (\u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043b\u0438\u043d\u043a\u0430 \u0441 \u043f\u043e\u043b\u043d\u044b\u043c \u043d\u0430\u0431\u043e\u0440\u043e\u043c \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u0432, (\u0445\u043e\u0441\u0442\u043d\u0435\u0439\u043c_\u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430, \u043f\u043e\u0440\u0442 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430), (\u0445\u043e\u0441\u0442\u043d\u0435\u0439\u043c \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u043f\u043e\u0440\u0442_\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f))<br \/>  \u0424\u043e\u0440\u043c\u0430\u0442 \u0432\u044b\u0431\u0440\u0430\u043d \u0434\u043b\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u0432 \u0434\u043b\u044f \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u0438 \u0431\u043e\u043b\u0435\u0435 \u0433\u0438\u0431\u043a\u043e\u0433\u043e \u043f\u043e\u0438\u0441\u043a\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439.<\/li>\n<li>\u041f\u043e \u044d\u0442\u0438\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043c \u043f\u043e\u0438\u0441\u043a \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u043f\u043e \u043d\u043e\u0434\u0430\u043c \u0438 \u043b\u0438\u043d\u043a\u0430\u043c (\u0441 \u0443\u0447\u0435\u0442\u043e\u043c \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043d\u043e\u0432\u043e\u043a \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a-\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435).<br \/>  \u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043f\u043e \u043d\u043e\u0434\u0430\u043c \u0431\u0443\u0434\u0443\u0442 \u0437\u0430\u043f\u0438\u0441\u0430\u043d\u044b \u0432 \u0434\u0432\u0430 \u0441\u043b\u043e\u0432\u0430\u0440\u044f \u0444\u043e\u0440\u043c\u0430\u0442\u0430:<br \/> \n<ul>\n<li>diff_nodes = {&#8216;added&#8217;: [], &#8216;deleted&#8217;: []}<\/li>\n<li>diff_links = {&#8216;added&#8217;: [], &#8216;deleted&#8217;: []}<\/li>\n<\/ul>\n<\/li>\n<li>\u0412 \u0445\u043e\u0434\u0435 \u043f\u043e\u0438\u0441\u043a\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043c \u0441\u043b\u0438\u044f\u043d\u0438\u0435 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0438 \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438.<br \/>  \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0430\u044f \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c\u0441\u044f \u0432 \u0441\u043b\u043e\u0432\u0430\u0440\u0435 diff_merged_topology.<br \/>  \u0414\u043b\u044f \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u043f\u0440\u0438 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u0438\u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u044b\u0445 \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u043d\u043e\u0434 \u0438 \u043b\u0438\u043d\u043a\u043e\u0432 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430\u043c\u0438 \u0441 \u0433\u043e\u0432\u043e\u0440\u044f\u0449\u0438\u043c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c is_new \u0438 is_dead.<br \/>  \u0414\u043b\u044f \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u044b\u0445 \u043d\u043e\u0434 \u0434\u043b\u044f \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438 \u0442\u0430\u043a\u0436\u0435 \u0432\u0432\u0435\u0434\u0435\u043c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0442\u0438\u043f \u043f\u0438\u043a\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u044b &#8216;dead_node&#8217; (\u0432 NeXt UI \u0443\u0447\u0442\u0435\u043c \u044d\u0442\u043e \u043d\u0438\u0436\u0435).  <\/li>\n<\/ol>\n<p>  <\/p>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443 \u0432 \u043a\u043e\u0434\u0435:<\/p>\n<p>  <\/p>\n<pre><code class=\"python\">def get_topology_diff(cached, current):     &quot;&quot;&quot;     \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438.     \u041d\u0430 \u0432\u0445\u043e\u0434 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0434\u0432\u0430 \u0441\u043b\u043e\u0432\u0430\u0440\u044f \u0441 \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u0438 \u0442\u0435\u043a\u0443\u0449\u0435\u0439     \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u044f\u043c\u0438. \u041d\u0430 \u0432\u044b\u0445\u043e\u0434\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0441\u043b\u043e\u0432\u0430\u0440\u0435\u0439 \u0441 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f\u043c\u0438     \u043f\u043e \u0445\u043e\u0441\u0442\u0430\u043c \u0438 \u043b\u0438\u043d\u043a\u0430\u043c, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u0441 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u043c \u0441\u043b\u0438\u044f\u043d\u0438\u044f     \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u043c\u044b\u0445 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0439 \u0441 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u044b\u043c\u0438 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430\u043c\u0438     \u0434\u043b\u044f \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439.     &quot;&quot;&quot;     diff_nodes = {'added': [], 'deleted': []}     diff_links = {'added': [], 'deleted': []}     diff_merged_topology = {'nodes': [], 'links': []}     # \u041b\u0438\u043d\u043a\u0438 \u043f\u0430\u0440\u0441\u044f\u0442\u0441\u044f \u0438\u0437 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442:     # (\u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a, (\u0445\u043e\u0441\u0442\u043d\u0435\u0439\u043c_\u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430, \u043f\u043e\u0440\u0442 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430), (\u0445\u043e\u0441\u0442\u043d\u0435\u0439\u043c \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u043f\u043e\u0440\u0442_\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f))     cached_links = [(x, ((x['srcDevice'], x['srcIfName']), (x['tgtDevice'], x['tgtIfName']))) for x in cached['links']]     links = [(x, ((x['srcDevice'], x['srcIfName']), (x['tgtDevice'], x['tgtIfName']))) for x in current['links']]     # \u0425\u043e\u0441\u0442\u044b \u043f\u0430\u0440\u0441\u044f\u0442\u0441\u044f \u0438\u0437 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442:     # (\u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435, (\u0445\u043e\u0441\u0442\u043d\u0435\u0439\u043c,))     # \u0412 \u043a\u043e\u0440\u0442\u0435\u0436 \u043f\u0440\u0438 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043c\u043e\u0433\u0443\u0442 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0434\u043b\u044f \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f.     cached_nodes = [(x, (x['name'],)) for x in cached['nodes']]     nodes = [(x, (x['name'],)) for x in current['nodes']]     # \u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u0438\u0441\u043a \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u044b\u0445 \u0445\u043e\u0441\u0442\u043d\u0435\u0439\u043c\u043e\u0432 \u0432 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438.     node_id = 0     host_id_map = {}     for raw_data, node in nodes:         if node in [x[1] for x in cached_nodes]:             raw_data['id'] = node_id             host_id_map[raw_data['name']] = node_id             raw_data['is_new'] = 'no'             raw_data['is_dead'] = 'no'             diff_merged_topology['nodes'].append(raw_data)             node_id += 1             continue         diff_nodes['added'].append(node)         raw_data['id'] = node_id         host_id_map[raw_data['name']] = node_id         raw_data['is_new'] = 'yes'         raw_data['is_dead'] = 'no'         diff_merged_topology['nodes'].append(raw_data)         node_id += 1     for raw_data, cached_node in cached_nodes:         if cached_node in [x[1] for x in nodes]:             continue         diff_nodes['deleted'].append(cached_node)         raw_data['id'] = node_id         host_id_map[raw_data['name']] = node_id         raw_data['is_new'] = 'no'         raw_data['is_dead'] = 'yes'         raw_data['icon'] = 'dead_node'         diff_merged_topology['nodes'].append(raw_data)         node_id += 1     # \u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u0438\u0441\u043a \u043d\u043e\u0432\u044b\u0445 \u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u044b\u0445 \u0441\u0432\u044f\u0437\u0435\u0439 \u043c\u0435\u0436\u0434\u0443 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438.     # \u0421\u043c\u0435\u043d\u0430 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u043c\u0435\u0436\u0434\u0443 \u043f\u0430\u0440\u043e\u0439 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u0442\u0441\u044f     # \u043a\u0430\u043a \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043e\u0434\u043d\u043e\u0439 \u0441\u0432\u044f\u0437\u0438 \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0434\u0440\u0443\u0433\u043e\u0439.     # \u041f\u0440\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0435 \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0444\u043e\u0440\u043c\u0430\u0442 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438     # \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0438 \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f:     # ((h1, Gi1), (h2, Gi2)) \u0438 ((h2, Gi2), (h1, Gi1)) - \u043e\u0434\u043d\u043e \u0438 \u0442\u043e\u0436\u0435.     link_id = 0     for raw_data, link in links:         src, dst = link         if not (src, dst) in [x[1] for x in cached_links] and not (dst, src) in [x[1] for x in cached_links]:             diff_links['added'].append((src, dst))             raw_data['id'] = link_id             link_id += 1             raw_data['source'] = host_id_map[src[0]]             raw_data['target'] = host_id_map[dst[0]]             raw_data['is_new'] = 'yes'             raw_data['is_dead'] = 'no'             diff_merged_topology['links'].append(raw_data)             continue         raw_data['id'] = link_id         link_id += 1         raw_data['source'] = host_id_map[src[0]]         raw_data['target'] = host_id_map[dst[0]]         raw_data['is_new'] = 'no'         raw_data['is_dead'] = 'no'         diff_merged_topology['links'].append(raw_data)     for raw_data, link in cached_links:         src, dst = link         if not (src, dst) in [x[1] for x in links] and not (dst, src) in [x[1] for x in links]:             diff_links['deleted'].append((src, dst))             raw_data['id'] = link_id             link_id += 1             raw_data['source'] = host_id_map[src[0]]             raw_data['target'] = host_id_map[dst[0]]             raw_data['is_new'] = 'no'             raw_data['is_dead'] = 'yes'             diff_merged_topology['links'].append(raw_data)     return diff_nodes, diff_links, diff_merged_topology<\/code><\/pre>\n<p>  <\/p>\n<p>get_topology_diff \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435 \u0434\u0432\u0443\u0445 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u0445 \u0441\u043b\u043e\u0432\u0430\u0440\u0435\u0439 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u0432\u0430\u043b\u0438\u0434\u043d\u043e\u0433\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0430.<br \/>  \u0421 \u0443\u0447\u0435\u0442\u043e\u043c \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043b\u0435\u0433\u043a\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0435\u0440\u0441\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u044d\u0448\u0430 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0439.<br \/>  \u041d\u0430\u043f\u0438\u0448\u0435\u043c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0434\u043b\u044f \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0432\u044b\u0432\u043e\u0434\u0430 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u044c:<\/p>\n<p>  <\/p>\n<pre><code class=\"python\">def print_diff(diff_result):     &quot;&quot;&quot;     \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0432\u044b\u0432\u043e\u0434\u0430     \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 get_topology_diff \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u044c.     &quot;&quot;&quot;     diff_nodes, diff_links, *ignore = diff_result     if not (diff_nodes['added'] or diff_nodes['deleted'] or diff_links['added'] or diff_links['deleted']):         print('\u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u043d\u0435 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u043e.')         return     print('\u041e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u044b \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438:')     if diff_nodes['added']:         print('')         print('^^^^^^^^^^^^^^^^^^^^^^^^^^^^^')         print('\u041d\u043e\u0432\u044b\u0435 \u0441\u0435\u0442\u0435\u0432\u044b\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430:')         print('vvvvvvvvvvvvvvvvvvvvvvvvvvvvv')         for node in diff_nodes['added']:             print(f'\u0418\u043c\u044f \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430: {node[0]}')     if diff_nodes['deleted']:         print('')         print('^^^^^^^^^^^^^^^^^^^^^^^^^^^^^')         print('\u0423\u0434\u0430\u043b\u0435\u043d\u043d\u044b\u0435 \u0441\u0435\u0442\u0435\u0432\u044b\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430:')         print('vvvvvvvvvvvvvvvvvvvvvvvvvvvvv')         for node in diff_nodes['deleted']:             print(f'\u0418\u043c\u044f \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430: {node[0]}')     if diff_links['added']:         print('')         print('^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^')         print('\u041d\u043e\u0432\u044b\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u043c\u0435\u0436\u0434\u0443 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438:')         print('vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv')         for src, dst in diff_links['added']:             print(f'\u041e\u0442 {src[0]}({src[1]}) \u043a {dst[0]}({dst[1]})')     if diff_links['deleted']:         print('')         print('^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^')         print('\u0423\u0434\u0430\u043b\u0435\u043d\u043d\u044b\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u043c\u0435\u0436\u0434\u0443 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438:')         print('vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv')         for src, dst in diff_links['deleted']:             print(f'\u041e\u0442 {src[0]}({src[1]}) \u043a {dst[0]}({dst[1]})')     print('')<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u0432\u0435\u0434\u0435\u043c \u0432\u043e\u0435\u0434\u0438\u043d\u043e \u0432\u0441\u044e \u0440\u0430\u043d\u0435\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443 \u0432 \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u043d\u0443\u044e main() \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0441\u0430\u043c\u043e\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u0434:<\/p>\n<p>  <\/p>\n<pre><code class=\"python\">def good_luck_have_fun():     &quot;&quot;&quot;\u0424\u0443\u043d\u043a\u0446\u0438\u044f, \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e\u0449\u0430\u044f \u0438\u0442\u043e\u0433\u043e\u0432\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443.&quot;&quot;&quot;     get_host_data_result = nr.run(get_host_data)     GLOBAL_LLDP_DATA, GLOBAL_FACTS = normalize_result(get_host_data_result)     TOPOLOGY_DETAILS = extract_lldp_details(GLOBAL_LLDP_DATA)     TOPOLOGY_DETAILS.append(GLOBAL_FACTS)     TOPOLOGY_DICT = generate_topology_json(*TOPOLOGY_DETAILS)     CACHED_TOPOLOGY = read_cached_topology()     write_topology_file(TOPOLOGY_DICT)     write_topology_cache(TOPOLOGY_DICT)     print(f'\u0414\u043b\u044f \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u043e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 \u0444\u0430\u0439\u043b main.html')     if CACHED_TOPOLOGY:         DIFF_DATA = get_topology_diff(CACHED_TOPOLOGY, TOPOLOGY_DICT)         print_diff(DIFF_DATA)         write_topology_file(DIFF_DATA[2], dst='diff_topology.js')     else:         # \u0435\u0441\u043b\u0438 \u043a\u044d\u0448\u0430 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u043d\u0435\u0442, \u0444\u0430\u0439\u043b \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u044e         write_topology_file(TOPOLOGY_DICT, dst='diff_topology.js')  if __name__ == '__main__':     good_luck_have_fun()<\/code><\/pre>\n<p>  <\/p>\n<h3 id=\"testirovanie\">\u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/h3>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0442\u0435\u0441\u0442\u0430 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u043c \u0434\u043e\u0441\u0442\u0443\u043f \u043d\u0430 dist-rtr01 \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0438\u0441\u0445\u043e\u0434\u043d\u0443\u044e \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u044e:<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/en\/o9\/n_\/eno9n_hfmleczhlhik2oye3l0ew.png\"><\/p>\n<p>  \u041f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u0432\u0435\u0440\u043d\u0435\u043c \u0434\u043e\u0441\u0442\u0443\u043f \u043d\u0430 dist-rtr02, \u043d\u043e \u0437\u0430\u043a\u0440\u043e\u0435\u043c \u043d\u0430 edge-sw01.<br \/>  \u041f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u043e\u043a\u0430\u0436\u0435\u0442\u0441\u044f \u0437\u0430\u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439, \u0430 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0431\u0443\u0434\u0435\u0442 \u0442\u0430\u043a\u0430\u044f:<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/wl\/7e\/pe\/wl7epeuciuox-6deptnauipayzo.png\"><\/p>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0430\u044f diff_topology.js \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0438\u0445 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f.<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"plaintext\">var topologyData = {     &quot;links&quot;: [         {             &quot;id&quot;: 0,             &quot;is_dead&quot;: &quot;no&quot;,             &quot;is_new&quot;: &quot;yes&quot;,             &quot;source&quot;: 4,             &quot;srcDevice&quot;: &quot;dist-rtr01.devnet.lab&quot;,             &quot;srcIfName&quot;: &quot;Gi3&quot;,             &quot;target&quot;: 3,             &quot;tgtDevice&quot;: &quot;core-rtr02.devnet.lab&quot;,             &quot;tgtIfName&quot;: &quot;Gi0\/0\/0\/2&quot;         },         {             &quot;id&quot;: 1,             &quot;is_dead&quot;: &quot;no&quot;,             &quot;is_new&quot;: &quot;yes&quot;,             &quot;source&quot;: 4,             &quot;srcDevice&quot;: &quot;dist-rtr01.devnet.lab&quot;,             &quot;srcIfName&quot;: &quot;Gi4&quot;,             &quot;target&quot;: 1,             &quot;tgtDevice&quot;: &quot;dist-sw01.devnet.lab&quot;,             &quot;tgtIfName&quot;: &quot;Eth1\/3&quot;         },         {             &quot;id&quot;: 2,             &quot;is_dead&quot;: &quot;no&quot;,             &quot;is_new&quot;: &quot;yes&quot;,             &quot;source&quot;: 4,             &quot;srcDevice&quot;: &quot;dist-rtr01.devnet.lab&quot;,             &quot;srcIfName&quot;: &quot;Gi6&quot;,             &quot;target&quot;: 0,             &quot;tgtDevice&quot;: &quot;dist-rtr02.devnet.lab&quot;,             &quot;tgtIfName&quot;: &quot;Gi6&quot;         },         {             &quot;id&quot;: 3,             &quot;is_dead&quot;: &quot;no&quot;,             &quot;is_new&quot;: &quot;yes&quot;,             &quot;source&quot;: 4,             &quot;srcDevice&quot;: &quot;dist-rtr01.devnet.lab&quot;,             &quot;srcIfName&quot;: &quot;Gi5&quot;,             &quot;target&quot;: 2,             &quot;tgtDevice&quot;: &quot;dist-sw02.devnet.lab&quot;,             &quot;tgtIfName&quot;: &quot;Eth1\/3&quot;         },         {             &quot;id&quot;: 4,             &quot;is_dead&quot;: &quot;no&quot;,             &quot;is_new&quot;: &quot;yes&quot;,             &quot;source&quot;: 4,             &quot;srcDevice&quot;: &quot;dist-rtr01.devnet.lab&quot;,             &quot;srcIfName&quot;: &quot;Gi2&quot;,             &quot;target&quot;: 5,             &quot;tgtDevice&quot;: &quot;core-rtr01.devnet.lab&quot;,             &quot;tgtIfName&quot;: &quot;Gi0\/0\/0\/2&quot;         },         {             &quot;id&quot;: 5,             &quot;is_dead&quot;: &quot;no&quot;,             &quot;is_new&quot;: &quot;no&quot;,             &quot;source&quot;: 0,             &quot;srcDevice&quot;: &quot;dist-rtr02.devnet.lab&quot;,             &quot;srcIfName&quot;: &quot;Gi3&quot;,             &quot;target&quot;: 3,             &quot;tgtDevice&quot;: &quot;core-rtr02.devnet.lab&quot;,             &quot;tgtIfName&quot;: &quot;Gi0\/0\/0\/3&quot;         },         {             &quot;id&quot;: 6,             &quot;is_dead&quot;: &quot;no&quot;,             &quot;is_new&quot;: &quot;no&quot;,             &quot;source&quot;: 0,             &quot;srcDevice&quot;: &quot;dist-rtr02.devnet.lab&quot;,             &quot;srcIfName&quot;: &quot;Gi4&quot;,             &quot;target&quot;: 1,             &quot;tgtDevice&quot;: &quot;dist-sw01.devnet.lab&quot;,             &quot;tgtIfName&quot;: &quot;Eth1\/4&quot;         },         {             &quot;id&quot;: 7,             &quot;is_dead&quot;: &quot;no&quot;,             &quot;is_new&quot;: &quot;no&quot;,             &quot;source&quot;: 0,             &quot;srcDevice&quot;: &quot;dist-rtr02.devnet.lab&quot;,             &quot;srcIfName&quot;: &quot;Gi5&quot;,             &quot;target&quot;: 2,             &quot;tgtDevice&quot;: &quot;dist-sw02.devnet.lab&quot;,             &quot;tgtIfName&quot;: &quot;Eth1\/4&quot;         },         {             &quot;id&quot;: 8,             &quot;is_dead&quot;: &quot;no&quot;,             &quot;is_new&quot;: &quot;no&quot;,             &quot;source&quot;: 0,             &quot;srcDevice&quot;: &quot;dist-rtr02.devnet.lab&quot;,             &quot;srcIfName&quot;: &quot;Gi2&quot;,             &quot;target&quot;: 5,             &quot;tgtDevice&quot;: &quot;core-rtr01.devnet.lab&quot;,             &quot;tgtIfName&quot;: &quot;Gi0\/0\/0\/3&quot;         },         {             &quot;id&quot;: 9,             &quot;is_dead&quot;: &quot;no&quot;,             &quot;is_new&quot;: &quot;no&quot;,             &quot;source&quot;: 1,             &quot;srcDevice&quot;: &quot;dist-sw01.devnet.lab&quot;,             &quot;srcIfName&quot;: &quot;Eth1\/1&quot;,             &quot;target&quot;: 2,             &quot;tgtDevice&quot;: &quot;dist-sw02.devnet.lab&quot;,             &quot;tgtIfName&quot;: &quot;Eth1\/1&quot;         },         {             &quot;id&quot;: 10,             &quot;is_dead&quot;: &quot;no&quot;,             &quot;is_new&quot;: &quot;no&quot;,             &quot;source&quot;: 1,             &quot;srcDevice&quot;: &quot;dist-sw01.devnet.lab&quot;,             &quot;srcIfName&quot;: &quot;Eth1\/2&quot;,             &quot;target&quot;: 2,             &quot;tgtDevice&quot;: &quot;dist-sw02.devnet.lab&quot;,             &quot;tgtIfName&quot;: &quot;Eth1\/2&quot;         },         {             &quot;id&quot;: 11,             &quot;is_dead&quot;: &quot;yes&quot;,             &quot;is_new&quot;: &quot;no&quot;,             &quot;source&quot;: 7,             &quot;srcDevice&quot;: &quot;edge-sw01.devnet.lab&quot;,             &quot;srcIfName&quot;: &quot;Gi0\/2&quot;,             &quot;target&quot;: 5,             &quot;tgtDevice&quot;: &quot;core-rtr01.devnet.lab&quot;,             &quot;tgtIfName&quot;: &quot;Gi0\/0\/0\/1&quot;         },         {             &quot;id&quot;: 12,             &quot;is_dead&quot;: &quot;yes&quot;,             &quot;is_new&quot;: &quot;no&quot;,             &quot;source&quot;: 7,             &quot;srcDevice&quot;: &quot;edge-sw01.devnet.lab&quot;,             &quot;srcIfName&quot;: &quot;Gi0\/3&quot;,             &quot;target&quot;: 3,             &quot;tgtDevice&quot;: &quot;core-rtr02.devnet.lab&quot;,             &quot;tgtIfName&quot;: &quot;Gi0\/0\/0\/1&quot;         }     ],     &quot;nodes&quot;: [         {             &quot;icon&quot;: &quot;router&quot;,             &quot;id&quot;: 0,             &quot;is_dead&quot;: &quot;no&quot;,             &quot;is_new&quot;: &quot;no&quot;,             &quot;model&quot;: &quot;CSR1000V&quot;,             &quot;name&quot;: &quot;dist-rtr02.devnet.lab&quot;,             &quot;serial_number&quot;: &quot;9YZKNQKQ566&quot;,         },         {             &quot;icon&quot;: &quot;switch&quot;,             &quot;id&quot;: 1,             &quot;is_dead&quot;: &quot;no&quot;,             &quot;is_new&quot;: &quot;no&quot;,             &quot;model&quot;: &quot;Nexus9000 9000v Chassis&quot;,             &quot;name&quot;: &quot;dist-sw01.devnet.lab&quot;,             &quot;serial_number&quot;: &quot;9MZLNM0ZC9Z&quot;,         },         {             &quot;icon&quot;: &quot;switch&quot;,             &quot;id&quot;: 2,             &quot;is_dead&quot;: &quot;no&quot;,             &quot;is_new&quot;: &quot;no&quot;,             &quot;model&quot;: &quot;Nexus9000 9000v Chassis&quot;,             &quot;name&quot;: &quot;dist-sw02.devnet.lab&quot;,             &quot;serial_number&quot;: &quot;93LCGCRUJA5&quot;,         },         {             &quot;icon&quot;: &quot;router&quot;,             &quot;id&quot;: 3,             &quot;is_dead&quot;: &quot;no&quot;,             &quot;is_new&quot;: &quot;no&quot;,             &quot;model&quot;: &quot;n\/a&quot;,             &quot;name&quot;: &quot;core-rtr02.devnet.lab&quot;,             &quot;serial_number&quot;: &quot;n\/a&quot;,         },         {             &quot;icon&quot;: &quot;router&quot;,             &quot;id&quot;: 4,             &quot;is_dead&quot;: &quot;no&quot;,             &quot;is_new&quot;: &quot;yes&quot;,             &quot;model&quot;: &quot;CSR1000V&quot;,             &quot;name&quot;: &quot;dist-rtr01.devnet.lab&quot;,             &quot;serial_number&quot;: &quot;9S78ZRF2V2B&quot;,         },         {             &quot;icon&quot;: &quot;router&quot;,             &quot;id&quot;: 5,             &quot;is_dead&quot;: &quot;no&quot;,             &quot;is_new&quot;: &quot;no&quot;,             &quot;model&quot;: &quot;n\/a&quot;,             &quot;name&quot;: &quot;core-rtr01.devnet.lab&quot;,             &quot;serial_number&quot;: &quot;n\/a&quot;,         },         {             &quot;icon&quot;: &quot;unknown&quot;,             &quot;id&quot;: 6,             &quot;is_dead&quot;: &quot;no&quot;,             &quot;is_new&quot;: &quot;no&quot;,             &quot;model&quot;: &quot;CSR1000V&quot;,             &quot;name&quot;: &quot;internet-rtr01.virl.info&quot;,             &quot;serial_number&quot;: &quot;9LGWPM8GTV6&quot;,         },         {             &quot;icon&quot;: &quot;dead_node&quot;,             &quot;id&quot;: 7,             &quot;is_dead&quot;: &quot;yes&quot;,             &quot;is_new&quot;: &quot;no&quot;,             &quot;model&quot;: &quot;IOSv&quot;,             &quot;name&quot;: &quot;edge-sw01.devnet.lab&quot;,             &quot;serial_number&quot;: &quot;927A4RELIGI&quot;,         }     ] };<\/code><\/pre>\n<\/div><\/div>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0435\u0435 \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043d\u0438\u0436\u0435 \u0432\u043d\u0435\u0441\u0435\u043c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 NeXt UI \u0432 next_app.js.<br \/>  \u0410 \u043f\u043e\u043a\u0430 \u043a\u043e\u043d\u0441\u043e\u043b\u044c\u043d\u044b\u0439 \u0432\u044b\u0432\u043e\u0434:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">$ python3.7 generate_topology.py  \u0414\u043b\u044f \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u043e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 \u0444\u0430\u0439\u043b main.html  \u041e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u044b \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438:  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ \u041d\u043e\u0432\u044b\u0435 \u0441\u0435\u0442\u0435\u0432\u044b\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430: vvvvvvvvvvvvvvvvvvvvvvvvvvvvv \u0418\u043c\u044f \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430: dist-rtr01.devnet.lab  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ \u0423\u0434\u0430\u043b\u0435\u043d\u043d\u044b\u0435 \u0441\u0435\u0442\u0435\u0432\u044b\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430: vvvvvvvvvvvvvvvvvvvvvvvvvvvvv \u0418\u043c\u044f \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430: edge-sw01.devnet.lab  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ \u041d\u043e\u0432\u044b\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u043c\u0435\u0436\u0434\u0443 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438: vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv \u041e\u0442 dist-rtr01.devnet.lab(Gi3) \u043a core-rtr02.devnet.lab(Gi0\/0\/0\/2) \u041e\u0442 dist-rtr01.devnet.lab(Gi4) \u043a dist-sw01.devnet.lab(Eth1\/3) \u041e\u0442 dist-rtr01.devnet.lab(Gi6) \u043a dist-rtr02.devnet.lab(Gi6) \u041e\u0442 dist-rtr01.devnet.lab(Gi5) \u043a dist-sw02.devnet.lab(Eth1\/3) \u041e\u0442 dist-rtr01.devnet.lab(Gi2) \u043a core-rtr01.devnet.lab(Gi0\/0\/0\/2)  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ \u0423\u0434\u0430\u043b\u0435\u043d\u043d\u044b\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u043c\u0435\u0436\u0434\u0443 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438: vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv \u041e\u0442 edge-sw01.devnet.lab(Gi0\/2) \u043a core-rtr01.devnet.lab(Gi0\/0\/0\/1) \u041e\u0442 edge-sw01.devnet.lab(Gi0\/3) \u043a core-rtr02.devnet.lab(Gi0\/0\/0\/1)  \u0414\u043b\u044f \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u0441 \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u043e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 \u0444\u0430\u0439\u043b diff_page.html \u041b\u0438\u0431\u043e \u043e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 \u0444\u0430\u0439\u043b main.html \u0438 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 '\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412\u0441\u0435 \u0441\u043e\u0433\u043b\u0430\u0441\u043d\u043e \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u043d\u044b\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f\u043c.<\/p>\n<p>  <\/p>\n<h1 id=\"dorabotka-prilozheniya-na-next-ui\">\u0414\u043e\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 NeXt UI<\/h1>\n<p>  <\/p>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0434\u043e\u0440\u0430\u0431\u043e\u0442\u043e\u043a \u0442\u0432\u043e\u0440\u0447\u0435\u0441\u043a\u0438 \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0430 \u0438\u0437 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u0438 \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u043e\u0432 \u043f\u043e NeXt UI.<\/p>\n<p>  <\/p>\n<h3 id=\"otobrazhenie-linkov\">\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043b\u0438\u043d\u043a\u043e\u0432<\/h3>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u0435\u0439 \u043a \u043b\u0438\u043d\u043a\u0430\u043c \u0440\u0430\u0441\u0448\u0438\u0440\u0438\u043c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 nx.graphic.Topology.Link:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">    nx.define('CustomLinkClass', nx.graphic.Topology.Link, {         properties: {             sourcelabel: null,             targetlabel: null         },         view: function(view) {             view.content.push({                 name: 'source',                 type: 'nx.graphic.Text',                 props: {                     'class': 'sourcelabel',                     'alignment-baseline': 'text-after-edge',                     'text-anchor': 'start'                 }             }, {                 name: 'target',                 type: 'nx.graphic.Text',                 props: {                     'class': 'targetlabel',                     'alignment-baseline': 'text-after-edge',                     'text-anchor': 'end'                 }             });             return view;         },         methods: {             update: function() {                 this.inherited();                 var el, point;                 var line = this.line();                 var angle = line.angle();                 var stageScale = this.stageScale();                 line = line.pad(18 * stageScale, 18 * stageScale);                 if (this.sourcelabel()) {                     el = this.view('source');                     point = line.start;                     el.set('x', point.x);                     el.set('y', point.y);                     el.set('text', this.sourcelabel());                     el.set('transform', 'rotate(' + angle + ' ' + point.x + ',' + point.y + ')');                     el.setStyle('font-size', 12 * stageScale);                 }                 if (this.targetlabel()) {                     el = this.view('target');                     point = line.end;                     el.set('x', point.x);                     el.set('y', point.y);                     el.set('text', this.targetlabel());                     el.set('transform', 'rotate(' + angle + ' ' + point.x + ',' + point.y + ')');                     el.setStyle('font-size', 12 * stageScale);                 }             }         }     });<\/code><\/pre>\n<p>  <\/p>\n<p>\u0418 \u0443\u043a\u0430\u0436\u0435\u043c \u0435\u0433\u043e \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e \u0432 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 <strong>topo<\/strong>.<br \/>  \u041f\u043e\u043c\u0438\u043c\u043e \u044d\u0442\u043e\u0433\u043e, \u043d\u043e\u0432\u044b\u0435 \u043b\u0438\u043d\u043a\u0438 \u043f\u043e\u043a\u0440\u0430\u0441\u0438\u043c \u0432 \u0437\u0435\u043b\u0435\u043d\u044b\u0439 \u0446\u0432\u0435\u0442, \u0430 \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u044b\u0435 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u043a\u0440\u0430\u0441\u043d\u044b\u043c\u0438 \u043f\u0443\u043d\u043a\u0442\u0438\u0440\u043d\u044b\u043c\u0438.<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">linkConfig: {     \/\/ \u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u043b\u0438\u043d\u043a\u043e\u0432 \u0434\u0443\u0433\u0430\u043c\u0438,     \/\/ \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043c\u0435\u043d\u044f\u0442\u044c \u043d\u0430 'parallel'     linkType: 'curve',     sourcelabel: 'model.srcIfName',     targetlabel: 'model.tgtIfName',     style: function(model) {         if (model._data.is_dead === 'yes') {             return { 'stroke-dasharray': '5' }         }     },     color: function(model) {         if (model._data.is_dead === 'yes') {             return '#E40039'         }         if (model._data.is_new === 'yes') {             return '#148D09'         }     }, },<\/code><\/pre>\n<p>  <\/p>\n<h3 id=\"dobavlenie-kastomnyh-piktogramm\">\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0445 \u043f\u0438\u043a\u0442\u043e\u0433\u0440\u0430\u043c\u043c<\/h3>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0441\u0435\u0442\u0435\u0432\u043e\u0433\u043e \u043e\u0431\u043e\u0440\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u044f NeXt \u0443\u0436\u0435 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0432 \u0441\u0435\u0431\u044f \u043d\u0430\u0431\u043e\u0440 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0445 \u043f\u0438\u043a\u0442\u043e\u0433\u0440\u0430\u043c\u043c.<br \/>  \u041d\u043e \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0445. \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0442\u0430\u043a\u0443\u044e \u0434\u043b\u044f \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u044b\u0445 \u043d\u043e\u0434.<br \/>  \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u0438\u043b\u0438 \u043f\u043e\u0441\u043b\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ \u043f\u0438\u043a\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0430 \u0432 .\/img\/dead_node.png topo.registerIcon(&quot;dead_node&quot;, &quot;img\/dead_node.png&quot;, 49, 49);<\/code><\/pre>\n<p>  <\/p>\n<h3 id=\"minutka-vizualizacii-izmeneniy\">\u041c\u0438\u043d\u0443\u0442\u043a\u0430 \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439<\/h3>\n<p>  <\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441 \u0443\u0447\u0435\u0442\u043e\u043c \u043f\u0440\u043e\u0434\u0435\u043b\u0430\u043d\u043d\u044b\u0445 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u043c\u043e\u0436\u0435\u043c \u043e\u0442\u043a\u0440\u044b\u0442\u044c <strong>diff_page.html<\/strong> \u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043d\u0430 \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0432\u044b\u0448\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439:<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/yw\/v6\/zk\/ywv6zkwkzsfn8euzb_rmlqmabq4.png\"><br \/>  \u041d\u0430\u0433\u043b\u044f\u0434\u043d\u043e. \u041a\u0430\u043a \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0435?<\/p>\n<p>  <\/p>\n<h3 id=\"izmenenie-otobrazheniya-vypadayuschih-menyu\">\u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0432\u044b\u043f\u0430\u0434\u0430\u044e\u0449\u0438\u0445 \u043c\u0435\u043d\u044e<\/h3>\n<p>  <\/p>\n<p>\u041c\u0435\u043d\u044e \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432\u044b\u0434\u0430\u0435\u0442 \u043c\u043d\u043e\u0433\u043e \u043b\u0438\u0448\u043d\u0435\u0439 \u0441\u043b\u0443\u0436\u0435\u0431\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438.<br \/>  \u041e\u043d\u043e \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043e \u0432 NeXt UI.<br \/>  \u0417\u0430\u043b\u043e\u0436\u0438\u043c \u0432 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0445\u043e\u0441\u0442\u043d\u0435\u0439\u043c\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430.<\/li>\n<li>\u041f\u0435\u0440\u0435\u0445\u043e\u0434 \u043d\u0430 \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u0439 \u043b\u0438\u043d\u043a (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0432 NetBox) \u043f\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u044e \u043d\u0430 \u0445\u043e\u0441\u0442\u043d\u0435\u0439\u043c \u0432 \u043c\u0435\u043d\u044e.<br \/>  \u0421\u0441\u044b\u043b\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0438\u0437 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430 \u043d\u043e\u0434\u044b dcimDeviceLink.<br \/>  \u0415\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u0440\u0438 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0444\u0430\u0439\u043b\u0430 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438. \u041f\u0440\u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0438 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c\u0441\u044f \u043f\u0440\u043e\u0441\u0442\u043e \u0445\u043e\u0441\u0442\u043d\u0435\u0439\u043c.<\/li>\n<li>\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 IP-\u0430\u0434\u0440\u0435\u0441\u0430, \u0441\u0435\u0440\u0438\u0439\u043d\u043e\u0433\u043e \u043d\u043e\u043c\u0435\u0440\u0430 \u0438 \u043c\u043e\u0434\u0435\u043b\u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u0438\u043c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 nx.ui.Component \u0438 \u0441\u0432\u0435\u0440\u0441\u0442\u0430\u0435\u043c \u0432\u043d\u0443\u0442\u0440\u0438 \u043d\u043e\u0432\u0443\u044e \u0444\u043e\u0440\u043c\u0443:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">    nx.define('CustomNodeTooltip', nx.ui.Component, {         properties: {             node: {},             topology: {}         },         view: {             content: [{                 tag: 'div',                 content: [{                     tag: 'h5',                     content: [{                         tag: 'a',                         content: '{#node.model.name}',                         props: {&quot;href&quot;: &quot;{#node.model.dcimDeviceLink}&quot;}                     }],                     props: {                         &quot;style&quot;: &quot;border-bottom: dotted 1px; font-size:90%; word-wrap:normal; color:#003688&quot;                     }                 }, {                     tag: 'p',                     content: [                         {                         tag: 'label',                         content: 'IP: ',                     }, {                         tag: 'label',                         content: '{#node.model.primaryIP}',                     }                     ],                     props: {                         &quot;style&quot;: &quot;font-size:80%;&quot;                     }                 },{                     tag: 'p',                     content: [                         {                         tag: 'label',                         content: 'Model: ',                     }, {                         tag: 'label',                         content: '{#node.model.model}',                     }                     ],                     props: {                         &quot;style&quot;: &quot;font-size:80%;&quot;                     }                 }, {                     tag: 'p',                     content: [{                         tag: 'label',                         content: 'S\/N: ',                     }, {                         tag: 'label',                         content: '{#node.model.serial_number}',                     }],                     props: {                         &quot;style&quot;: &quot;font-size:80%; padding:0&quot;                     }                 },             ],             props: {                 &quot;style&quot;: &quot;width: 150px;&quot;             }         }]         }     });      nx.define('Tooltip.Node', nx.ui.Component, {         view: function(view){             view.content.push({             });             return view;         },         methods: {             attach: function(args) {                 this.inherited(args);                 this.model();             }         }     });<\/code><\/pre>\n<p>  <\/p>\n<p>\u0423\u043a\u0430\u0436\u0435\u043c \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 <strong>topo<\/strong>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">tooltipManagerConfig: {     \/\/ \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 tooltip content (\u043c\u0435\u043d\u044e \u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u043d\u0430 \u043d\u043e\u0434\u0443)     nodeTooltipContentClass: 'CustomNodeTooltip' },<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u043d\u0430 \u043d\u043e\u0434\u0443 \u043f\u043e\u043b\u0443\u0447\u0438\u043c:<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/hx\/he\/kl\/hxheklf6kvjmz29kq48g38lu6qu.png\"><\/p>\n<p>  <\/p>\n<h3 id=\"izmenenie-orientacii-nod-v-prostranstve\">\u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043e\u0440\u0438\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u043d\u043e\u0434 \u0432 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0435<\/h3>\n<p>  <\/p>\n<p>\u041a\u0430\u043a \u0443\u0436\u0435 \u0431\u044b\u043b\u043e \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u043e, \u0434\u043b\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f &#8216;force&#8217; \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 NeXt UI. \u0415\u0433\u043e \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0439 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u0441\u0442\u0440\u0435\u043c\u0438\u0442\u0441\u044f \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0438\u0442\u044c \u043d\u043e\u0434\u044b \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u0441\u043e\u0441\u0435\u0434\u044f\u043c\u0438 \u0431\u044b\u043b\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u043c\u044b\u043c.<br \/>  \u0412 \u0441\u0438\u043b\u0443 \u044d\u0442\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438 \u0434\u043b\u044f \u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0441\u043d\u044b\u0445 \u0438\u0435\u0440\u0430\u0440\u0445\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0439 \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0443\u0440\u043e\u0432\u043d\u0435\u0439 \u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u0432 \u0446\u0435\u043b\u043e\u043c \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u0432\u0435\u0440\u043d\u0443\u0442\u044b\u043c \u0432 \u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u043e\u0439 \u043f\u043b\u043e\u0441\u043a\u043e\u0441\u0442\u0438 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0436\u0435\u043b\u0430\u0435\u043c\u043e\u0433\u043e. \u041c\u043e\u0436\u043d\u043e, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u043f\u0435\u0440\u0435\u0442\u0430\u0449\u0438\u0442\u044c \u043d\u043e\u0434\u044b \u043c\u044b\u0448\u044c\u044e, \u043d\u043e \u044d\u0442\u043e \u043d\u0435 \u043d\u0430\u0448 \u043f\u0443\u0442\u044c.<\/p>\n<p>  \u0412 NeXt UI \u0438\u043c\u0435\u044e\u0442\u0441\u044f \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0435 \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u043e \u0441\u043b\u043e\u044f\u043c\u0438.<br \/>  \u041d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 \u0441\u043b\u043e\u0435\u0432 \u0432\u0432\u0435\u0434\u0435\u043c \u0447\u0438\u0441\u043b\u043e\u0432\u043e\u0439 \u0430\u0442\u0440\u0438\u0431\u0443\u0442 \u043d\u043e\u0434 <strong>layerSortPreference<\/strong>.<br \/>  \u0412\u0441\u044e \u043b\u043e\u0433\u0438\u043a\u0443 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0438\u0435\u0440\u0430\u0440\u0445\u0438\u0438 \u0432 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u043d\u0435\u0441\u0442\u0438 \u0437\u0430 \u043f\u0440\u0435\u0434\u0435\u043b\u044b \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430 \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u0430 \u0435\u043c\u0443 \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0443 \u0441\u043b\u043e\u0435\u0432 \u0432 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u043c \u043f\u043e\u0440\u044f\u0434\u043a\u0435, \u0447\u0442\u043e \u0431\u043e\u043b\u0435\u0435 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u043e.  <\/p>\n<p>  <\/p>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043e\u0440\u0438\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u0443\u0440\u043e\u0432\u043d\u0435\u0439 \u0432 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">    var currentLayout = 'auto'     horizontal = function() {         if (currentLayout === 'horizontal') {             return;         };         currentLayout = 'horizontal';         var layout = topo.getLayout('hierarchicalLayout');         layout.direction('horizontal');         layout.levelBy(function(node, model) {             return model.get('layerSortPreference');         });         topo.activateLayout('hierarchicalLayout');     };     vertical = function() {         if (currentLayout === 'vertical') {             return;         };         currentLayout = 'vertical';         var layout = topo.getLayout('hierarchicalLayout');         layout.direction('vertical');         layout.levelBy(function(node, model) {           return model.get('layerSortPreference');         });         topo.activateLayout('hierarchicalLayout');     };<\/code><\/pre>\n<p>  <\/p>\n<p>\u0418\u0445 \u0432\u044b\u043d\u0435\u0441\u0435\u043c \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0438 \u0432 \u043d\u0430\u0448\u0438 \u0444\u043e\u0440\u043c\u044b main.html \u0438 diff_page.html:<\/p>\n<p>  <\/p>\n<pre><code class=\"html\">&lt;button onclick='horizontal()'&gt;\u041e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0443\u0440\u043e\u0432\u043d\u0438 \u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u043e&lt;\/button&gt; &lt;button onclick=&quot;vertical()&quot;&gt;\u041e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0443\u0440\u043e\u0432\u043d\u0438 \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u043e&lt;\/button&gt;<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412 \u0441\u043a\u0440\u0438\u043f\u0442\u0435 <strong>generate_topology.py<\/strong> \u0432\u0432\u0435\u0434\u0435\u043c \u0438\u0435\u0440\u0430\u0440\u0445\u0438\u044e \u0443\u0440\u043e\u0432\u043d\u0435\u0439 \u0441\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u043c\u0438 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f\u043c\u0438 \u0438 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043b\u043e\u0433\u0438\u043a\u0443 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043d\u043e\u043c\u0435\u0440\u0430 \u0443\u0440\u043e\u0432\u043d\u044f:<\/p>\n<p>  <\/p>\n<pre><code class=\"python\">NX_LAYER_SORT_ORDER = (     'undefined',     'outside',     'edge-switch',     'edge-router',     'core-router',     'core-switch',     'distribution-router',     'distribution-switch',     'leaf',     'spine',     'access-switch' )  def get_node_layer_sort_preference(device_role):     for i, role in enumerate(NX_LAYER_SORT_ORDER, start=1):         if device_role == role:             return i     return 1<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u0442\u044c \u0441 \u043f\u043e\u0440\u044f\u0434\u043a\u043e\u0432\u044b\u043c \u043d\u043e\u043c\u0435\u0440\u043e\u043c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0432 NX_LAYER_SORT_ORDER \u0441\u0432\u0435\u0440\u0445\u0443 \u0432\u043d\u0438\u0437.<br \/>  <strong>\u0412\u0430\u0436\u043d\u043e\u0435 \u0437\u0430\u043c\u0435\u0447\u0430\u043d\u0438\u0435<\/strong>: 0(\u043d\u043e\u043b\u044c) NeXt UI, \u043f\u043e\u0445\u043e\u0436\u0435, \u0432\u043e\u0441\u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043a\u0430\u043a undefined \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u044d\u0442\u043e \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u0432 \u043a\u043e\u043d\u0435\u0446, \u0430 \u043d\u0435 \u0432 \u043d\u0430\u0447\u0430\u043b\u043e. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u0441\u0442\u044c \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0441 \u0435\u0434\u0438\u043d\u0438\u0446\u044b.   <\/p>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0440\u043e\u043b\u0438(\u0443\u0440\u043e\u0432\u043d\u044f) \u043a\u043e\u043d\u043a\u0440\u0435\u043a\u0442\u043d\u043e\u0433\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0432\u0432\u0435\u0434\u0435\u043c \u0432 \u0444\u0430\u0439\u043b\u0435 \u0445\u043e\u0441\u0442\u043e\u0432 \u0438\u043d\u0432\u0435\u043d\u0442\u043e\u0440\u0438 Nornir \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0435 \u043f\u043e\u043b\u0435.<br \/>  \u041d\u0435\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u043f\u043e\u043b\u044f \u043c\u043e\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0432 <strong>data<\/strong> \u0445\u043e\u0441\u0442\u0430:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">dist-rtr01:     hostname: 10.10.20.175     platform: ios     groups:         - devnet-cml-lab     data:         role: distribution-router<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412\u0432\u0435\u0434\u0435\u043c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0430\u0442\u0440\u0438\u0431\u0443\u0442 nr_role, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u043c \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0432 \u0441\u043b\u043e\u0432\u0430\u0440\u044c global_facts \u0432 normalize_result:<\/p>\n<p>  <\/p>\n<pre><code class=\"python\"># \u043f\u043e\u043b\u043d\u044b\u0439 \u0432\u044b\u0432\u043e\u0434 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043e\u043f\u0443\u0441\u0442\u0438\u043c global_facts[device_fqdn]['nr_role'] = nr.inventory.hosts[device].get('role', 'undefined')<\/code><\/pre>\n<p>  <\/p>\n<p>\u0418 \u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c \u0432 generate_topology_json \u043f\u0440\u0438 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043d\u043e\u0434\u044b:<\/p>\n<p>  <\/p>\n<pre><code class=\"python\"># \u043f\u043e\u043b\u043d\u044b\u0439 \u0432\u044b\u0432\u043e\u0434 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043e\u043f\u0443\u0441\u0442\u0438\u043c device_role = facts[host].get('nr_role', 'undefined') topology_dict['nodes'].append({     'id': host_id,     'name': host,     'primaryIP': device_ip,     'model': device_model,     'serial_number': device_serial,     'layerSortPreference': get_node_layer_sort_preference(         device_role     ),     'icon': get_icon_type(         lldp_capabilities_dict.get(host, ''),         device_model     ) })<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u044b\u0440\u044b\u0432\u043d\u0438\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u043e \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0435 \u0432 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0435 \u0443\u0440\u043e\u0432\u043d\u0438 \u043f\u043e \u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u0438 \u0438\u043b\u0438 \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u0438. \u0412\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u044d\u0442\u043e \u043f\u0440\u0438 \u043d\u0430\u043b\u0438\u0447\u0438\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u0432 \u0432 \u043d\u043e\u0434\u0430\u0445 \u0442\u0430\u043a:<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/my\/k6\/0e\/myk60ehtgegonmev55v1qg5evd8.gif\"><\/p>\n<p>  <\/p>\n<h1 id=\"itogovaya-struktura-proekta\">\u0418\u0442\u043e\u0433\u043e\u0432\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h1>\n<p>  <\/p>\n<p>\u041f\u043e\u043b\u043d\u044b\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u0438 \u0444\u0430\u0439\u043b\u044b-\u043f\u0440\u0438\u043c\u0435\u0440\u044b \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0439 \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u043d\u0430 \u043c\u043e\u0435\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u043d\u0430 <a href=\"https:\/\/github.com\/iDebugAll\/devnet_marathon_endgame\" rel=\"nofollow\">GitHub<\/a>.<br \/>  \u0418\u0442\u043e\u0433\u043e\u0432\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">$ tree . -L 2 . \u251c\u2500\u2500 LICENSE \u251c\u2500\u2500 README.md \u251c\u2500\u2500 diff_page.html \u251c\u2500\u2500 diff_topology.js \u251c\u2500\u2500 generate_topology.py \u251c\u2500\u2500 img \u2502\u00a0\u00a0 \u2514\u2500\u2500 dead_node.png \u251c\u2500\u2500 inventory \u2502\u00a0\u00a0 \u251c\u2500\u2500 groups.yml \u2502\u00a0\u00a0 \u2514\u2500\u2500 hosts_devnet_sb_cml.yml \u251c\u2500\u2500 main.html \u251c\u2500\u2500 next_app.js \u251c\u2500\u2500 next_sources \u2502\u00a0\u00a0 \u251c\u2500\u2500 css \u2502\u00a0\u00a0 \u251c\u2500\u2500 doc \u2502\u00a0\u00a0 \u251c\u2500\u2500 fonts \u2502\u00a0\u00a0 \u2514\u2500\u2500 js \u251c\u2500\u2500 nornir_config.yml \u251c\u2500\u2500 requirements.txt \u251c\u2500\u2500 samples \u2502\u00a0\u00a0 \u251c\u2500\u2500 sample_diff.png \u2502\u00a0\u00a0 \u251c\u2500\u2500 sample_layout_horizontal.png \u2502\u00a0\u00a0 \u251c\u2500\u2500 sample_link_details.png \u2502\u00a0\u00a0 \u251c\u2500\u2500 sample_node_details.png \u2502\u00a0\u00a0 \u2514\u2500\u2500 sample_topology.png \u251c\u2500\u2500 styles_main_page.css \u2514\u2500\u2500 topology.js<\/code><\/pre>\n<p>  <\/p>\n<h1 id=\"vyvody\">\u0412\u044b\u0432\u043e\u0434\u044b<\/h1>\n<p>  <\/p>\n<p>\u0412 \u043f\u0435\u0440\u0432\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u0441\u043f\u0430\u0441\u0438\u0431\u043e \u0432\u0441\u0435\u043c, \u043a\u0442\u043e \u0434\u043e\u0447\u0438\u0442\u0430\u043b \u0434\u043e \u043a\u043e\u043d\u0446\u0430.  <\/p>\n<p>  <\/p>\n<p>\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u043f\u043e\u0441\u0442\u0430\u0440\u0430\u043b\u0441\u044f \u0438\u0437\u043b\u043e\u0436\u0438\u0442\u044c \u0438 \u043f\u0440\u043e\u043a\u043e\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u044d\u0442\u0430\u043f\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438\u0442\u043e\u0433\u043e\u0432\u043e\u0433\u043e \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043e\u0431\u0437\u043e\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0445 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432. \u0420\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0430 \u043c\u0430\u0440\u0430\u0444\u043e\u043d\u0435 \u0437\u0430\u043d\u044f\u043b\u043e \u043f\u0435\u0440\u0432\u043e\u0435 \u043c\u0435\u0441\u0442\u043e \u0438, \u0447\u0442\u043e \u0433\u043b\u0430\u0432\u043d\u043e\u0435, \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043a\u0440\u043e\u0441\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435\u043d\u043d\u044b\u043c \u0438 \u0438\u043c\u0435\u0435\u0442 \u043f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b \u043a \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c\u0443 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044e \u0438 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u043b\u0430\u0431\u043e\u0440\u0430\u0442\u043e\u0440\u043d\u044b\u0445 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445.<br \/>  \u041d\u0430\u0434\u0435\u044e\u0441\u044c, \u044d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043a\u043e\u043c\u0443-\u0442\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u043e.  <\/p>\n<p>  <\/p>\n<p>\u0411\u0443\u0434\u0443 \u0440\u0430\u0434 \u043e\u0431\u0440\u0430\u0442\u043d\u043e\u0439 \u0441\u0432\u044f\u0437\u0438 \u0438 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u0438\u0432\u043d\u043e\u0439 \u043a\u0440\u0438\u0442\u0438\u043a\u0435. \u0427\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0438\u043b\u0438 \u0443\u043b\u0443\u0447\u0448\u0438\u0442\u044c?<br \/>  \u041a\u0430\u043a \u0431\u044b \u0432\u044b \u043f\u043e\u0434\u043e\u0448\u043b\u0438 \u043a \u0440\u0435\u0448\u0435\u043d\u0438\u044e \u0437\u0430\u0434\u0430\u0447\u0438 \u0438\u043b\u0438 \u043a\u0430\u043a \u0435\u0435 \u0443\u0436\u0435 \u0440\u0435\u0448\u0430\u043b\u0438?<\/p>\n<\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/501164\/\"> https:\/\/habr.com\/ru\/post\/501164\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/501164\/\">\n<p>\u041f\u0440\u0438\u0432\u0435\u0442 \u0425\u0430\u0431\u0440! \u042d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0430 \u043f\u043e \u043c\u043e\u0442\u0438\u0432\u0430\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u043d\u0438\u044f \u043d\u0430 \u043d\u0435\u0434\u0430\u0432\u043d\u043e \u043f\u0440\u043e\u0448\u0435\u0434\u0448\u0435\u043c <a href=\"https:\/\/rrc.ru\/events\/onlajn-devnet-marafon-ot-cisco\" rel=\"nofollow\">\u043e\u043d\u043b\u0430\u0439\u043d-\u043c\u0430\u0440\u0430\u0444\u043e\u043d\u0435 DevNet<\/a> \u043e\u0442 Cisco. \u0423\u0447\u0430\u0441\u0442\u043d\u0438\u043a\u0430\u043c \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u043b\u043e\u0441\u044c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0430\u043d\u0430\u043b\u0438\u0437 \u0438 \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u043e\u0439 \u0441\u0435\u0442\u0435\u0432\u043e\u0439 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0438 \u0438, \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e, \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0438\u0445 \u0432 \u043d\u0435\u0439 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439. <br \/>  \u0417\u0430\u0434\u0430\u0447\u0430 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0435 \u0441\u0430\u043c\u043e\u0439 \u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u043e\u0439, \u0438 \u0432 \u0431\u043b\u043e\u0433\u043e\u0441\u0444\u0435\u0440\u0435 \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u0435\u0442\u0441\u044f \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043c\u0430\u043b\u043e \u0441\u0442\u0430\u0442\u0435\u0439 \u043d\u0430 \u044d\u0442\u0443 \u0442\u0435\u043c\u0443. \u041d\u0438\u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e \u0440\u0430\u0437\u0431\u043e\u0440 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0445 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0438 \u043f\u043e\u0434\u0445\u043e\u0434\u043e\u0432. <\/p>\n<p>  \u0412\u0441\u0435\u043c \u0437\u0430\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043e\u0432\u0430\u0432\u0448\u0438\u043c\u0441\u044f \u0434\u043e\u0431\u0440\u043e \u043f\u043e\u0436\u0430\u043b\u043e\u0432\u0430\u0442\u044c \u043f\u043e \u043a\u0430\u0442!<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/5h\/zi\/p1\/5hzip10y5vl8l71jpwwfmqp-xes.png\"><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-303383","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/303383","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=303383"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/303383\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=303383"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=303383"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=303383"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}