[{"data":1,"prerenderedAt":541},["ShallowReactive",2],{"project-mikro-manager":3},{"id":4,"title":5,"body":6,"description":520,"duration":521,"extension":522,"featured":523,"github":524,"image":525,"live":526,"meta":527,"navigation":336,"order":373,"path":528,"role":526,"seo":529,"status":530,"stem":531,"team_size":526,"tech":532,"type":538,"year":539,"__hash__":540},"projects\u002Fproject\u002Fmikro-manager.md","Mikrotik Manager",{"type":7,"value":8,"toc":512},"minimark",[9,14,18,22,30,67,71,76,85,100,108,124,128,133,136,274,278,281,508],[10,11,13],"h2",{"id":12},"the-problem","The Problem",[15,16,17],"p",{},"Network administrators often spend hours manually configuring MikroTik routers via WinBox GUI for repetitive tasks like setting up IP addresses, configuring DHCP servers, or managing backups. This manual process is prone to clicks-errors and lacks the speed required for deploying multiple devices efficiently.",[10,19,21],{"id":20},"my-solution","My Solution",[15,23,24,25,29],{},"I built ",[26,27,28],"strong",{},"Mikro Manager",", a modular Command Line Interface (CLI) tool that interacts directly with the RouterOS API to automate network provisioning.",[31,32,33,45,51,61],"ul",{},[34,35,36,39,40,44],"li",{},[26,37,38],{},"Interactive CLI:"," Leveraged the ",[41,42,43],"code",{},"rich"," library to create a beautiful, menu-driven terminal interface that is easy to navigate.",[34,46,47,50],{},[26,48,49],{},"Task Automation:"," implemented specific modules for critical tasks such as Backup Management, DHCP Setup, NAT Configuration, and IP Address management.",[34,52,53,56,57,60],{},[26,54,55],{},"Secure Connection:"," Uses environment variables (",[41,58,59],{},".env",") to handle router credentials securely, separating configuration from code.",[34,62,63,66],{},[26,64,65],{},"Modular Design:"," Architected with a clear separation of concerns (Views pattern), making it easy to add new configuration modules without breaking the core application.",[10,68,70],{"id":69},"technical-deep-dive","Technical Deep Dive",[72,73,75],"h3",{"id":74},"architecture-decisions","Architecture Decisions",[15,77,78],{},[26,79,80,81,84],{},"Why ",[41,82,83],{},"routeros_api"," wrapper?",[31,86,87],{},[34,88,89,92,93,95,96,99],{},[26,90,91],{},"Abstraction:"," Instead of writing raw socket commands, I used the ",[41,94,83],{}," library to interact with MikroTik's resources in a Pythonic way (e.g., ",[41,97,98],{},"api.get_resource('\u002Fip\u002Faddress')","). This ensures better error handling and cleaner code.",[15,101,102],{},[26,103,80,104,107],{},[41,105,106],{},"Rich"," for the UI?",[31,109,110],{},[34,111,112,115,116,119,120,123],{},[26,113,114],{},"User Experience:"," CLI tools don't have to be ugly. I used ",[41,117,118],{},"rich.console"," and ",[41,121,122],{},"rich.panel"," to display formatted tables, success\u002Ferror alerts, and banners. This makes the tool approachable for technicians who might not be developers.",[72,125,127],{"id":126},"key-features-i-built","Key Features I Built",[129,130,132],"h4",{"id":131},"_1-modular-resource-interaction","1. Modular Resource Interaction",[15,134,135],{},"Each network function is encapsulated in its own view. For example, adding an IP address isn't just a script; it's a function that validates input and interacts with the specific RouterOS endpoint.",[137,138,143],"pre",{"className":139,"code":140,"language":141,"meta":142,"style":142},"language-bash shiki shiki-themes github-light github-dark","# python\n# views\u002Fip_address.py\ndef add_ip(api):\n    # ... input prompts ...\n    try:\n        list_ip = api.get_resource('\u002Fip\u002Faddress')\n        list_ip.add(address=addr, interface=interface)\n        console.print(Panel(f\"Success: IP {addr} added to {interface}\", style=\"green\"))\n    except Exception as e:\n        console.print(f\"[red]Error adding IP: {e}[\u002Fred]\")\n","bash","",[41,144,145,154,160,184,190,196,216,230,248,263],{"__ignoreMap":142},[146,147,150],"span",{"class":148,"line":149},"line",1,[146,151,153],{"class":152},"sJ8bj","# python\n",[146,155,157],{"class":148,"line":156},2,[146,158,159],{"class":152},"# views\u002Fip_address.py\n",[146,161,163,167,171,175,178,181],{"class":148,"line":162},3,[146,164,166],{"class":165},"sScJk","def",[146,168,170],{"class":169},"sZZnC"," add_ip",[146,172,174],{"class":173},"sVt8B","(",[146,176,177],{"class":165},"api",[146,179,180],{"class":173},")",[146,182,183],{"class":169},":\n",[146,185,187],{"class":148,"line":186},4,[146,188,189],{"class":152},"    # ... input prompts ...\n",[146,191,193],{"class":148,"line":192},5,[146,194,195],{"class":165},"    try:\n",[146,197,199,202,205,208,210,213],{"class":148,"line":198},6,[146,200,201],{"class":165},"        list_ip",[146,203,204],{"class":169}," =",[146,206,207],{"class":169}," api.get_resource",[146,209,174],{"class":173},[146,211,212],{"class":165},"'\u002Fip\u002Faddress'",[146,214,215],{"class":173},")\n",[146,217,219,222,225,228],{"class":148,"line":218},7,[146,220,221],{"class":165},"        list_ip.add(address",[146,223,224],{"class":169},"=addr,",[146,226,227],{"class":169}," interface=interface",[146,229,215],{"class":173},[146,231,233,236,239,242,245],{"class":148,"line":232},8,[146,234,235],{"class":165},"        console.print(Panel(f",[146,237,238],{"class":165},"\"Success: IP {addr} added to {interface}\"",[146,240,241],{"class":165},",",[146,243,244],{"class":169}," style=\"green\"",[146,246,247],{"class":173},"))\n",[146,249,251,254,257,260],{"class":148,"line":250},9,[146,252,253],{"class":165},"    except",[146,255,256],{"class":169}," Exception",[146,258,259],{"class":169}," as",[146,261,262],{"class":169}," e:\n",[146,264,266,269,272],{"class":148,"line":265},10,[146,267,268],{"class":165},"        console.print(f",[146,270,271],{"class":165},"\"[red]Error adding IP: {e}[\u002Fred]\"",[146,273,215],{"class":173},[129,275,277],{"id":276},"_2-centralized-authentication-menu-loop","2. Centralized Authentication & Menu Loop",[15,279,280],{},"The main.py acts as the controller, managing the connection state and routing the user to the correct module based on their input.",[137,282,284],{"className":139,"code":283,"language":141,"meta":142,"style":142},"# python\n# main.py\ndef main():\n    connection = Connect()\n    api = connection.connect()\n\n    while True:\n        # Display menu with Rich\n        console.print(Panel.fit(\"1. Add IP Address\\n2. DHCP Setup\\n...\", title=\"Menu\"))\n\n        match choice:\n            case \"1\":\n                ip_address.add_ip(api)\n            case \"2\":\n                dhcp.setup_dhcp(api2. Centralized Authentication & Menu Loop\n\n                The main.py acts as the controller, managing the connection state and routing the user to the correct module based on their input.)\n            # ... handles other modules\n",[41,285,286,290,295,307,320,332,338,347,352,367,371,380,391,399,409,430,435,502],{"__ignoreMap":142},[146,287,288],{"class":148,"line":149},[146,289,153],{"class":152},[146,291,292],{"class":148,"line":156},[146,293,294],{"class":152},"# main.py\n",[146,296,297,299,302,305],{"class":148,"line":162},[146,298,166],{"class":165},[146,300,301],{"class":169}," main",[146,303,304],{"class":173},"()",[146,306,183],{"class":169},[146,308,309,312,314,317],{"class":148,"line":186},[146,310,311],{"class":165},"    connection",[146,313,204],{"class":169},[146,315,316],{"class":169}," Connect",[146,318,319],{"class":173},"()\n",[146,321,322,325,327,330],{"class":148,"line":192},[146,323,324],{"class":165},"    api",[146,326,204],{"class":169},[146,328,329],{"class":169}," connection.connect",[146,331,319],{"class":173},[146,333,334],{"class":148,"line":198},[146,335,337],{"emptyLinePlaceholder":336},true,"\n",[146,339,340,344],{"class":148,"line":218},[146,341,343],{"class":342},"szBVR","    while",[146,345,346],{"class":165}," True:\n",[146,348,349],{"class":148,"line":232},[146,350,351],{"class":152},"        # Display menu with Rich\n",[146,353,354,357,360,362,365],{"class":148,"line":250},[146,355,356],{"class":165},"        console.print(Panel.fit(",[146,358,359],{"class":165},"\"1. Add IP Address\\n2. DHCP Setup\\n...\"",[146,361,241],{"class":165},[146,363,364],{"class":169}," title=\"Menu\"",[146,366,247],{"class":173},[146,368,369],{"class":148,"line":265},[146,370,337],{"emptyLinePlaceholder":336},[146,372,374,377],{"class":148,"line":373},11,[146,375,376],{"class":165},"        match",[146,378,379],{"class":169}," choice:\n",[146,381,383,386,389],{"class":148,"line":382},12,[146,384,385],{"class":173},"            case ",[146,387,388],{"class":169},"\"1\"",[146,390,183],{"class":173},[146,392,394,397],{"class":148,"line":393},13,[146,395,396],{"class":165},"                ip_address.add_ip(api",[146,398,215],{"class":173},[146,400,402,404,407],{"class":148,"line":401},14,[146,403,385],{"class":173},[146,405,406],{"class":169},"\"2\"",[146,408,183],{"class":173},[146,410,412,415,418,421,424,427],{"class":148,"line":411},15,[146,413,414],{"class":165},"                dhcp.setup_dhcp(api2.",[146,416,417],{"class":169}," Centralized",[146,419,420],{"class":169}," Authentication",[146,422,423],{"class":173}," & ",[146,425,426],{"class":165},"Menu",[146,428,429],{"class":169}," Loop\n",[146,431,433],{"class":148,"line":432},16,[146,434,337],{"emptyLinePlaceholder":336},[146,436,438,441,444,447,449,452,455,458,460,463,466,469,472,474,477,480,482,485,488,491,494,497,500],{"class":148,"line":437},17,[146,439,440],{"class":165},"                The",[146,442,443],{"class":169}," main.py",[146,445,446],{"class":169}," acts",[146,448,259],{"class":169},[146,450,451],{"class":169}," the",[146,453,454],{"class":169}," controller,",[146,456,457],{"class":169}," managing",[146,459,451],{"class":169},[146,461,462],{"class":169}," connection",[146,464,465],{"class":169}," state",[146,467,468],{"class":169}," and",[146,470,471],{"class":169}," routing",[146,473,451],{"class":169},[146,475,476],{"class":169}," user",[146,478,479],{"class":169}," to",[146,481,451],{"class":169},[146,483,484],{"class":169}," correct",[146,486,487],{"class":169}," module",[146,489,490],{"class":169}," based",[146,492,493],{"class":169}," on",[146,495,496],{"class":169}," their",[146,498,499],{"class":169}," input.",[146,501,215],{"class":173},[146,503,505],{"class":148,"line":504},18,[146,506,507],{"class":152},"            # ... handles other modules\n",[509,510,511],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}",{"title":142,"searchDepth":156,"depth":156,"links":513},[514,515,516],{"id":12,"depth":156,"text":13},{"id":20,"depth":156,"text":21},{"id":69,"depth":156,"text":70,"children":517},[518,519],{"id":74,"depth":162,"text":75},{"id":126,"depth":162,"text":127},"A Python-based CLI utility designed to automate common MikroTik RouterOS configuration tasks, featuring a modular architecture and a rich terminal interface.","3 weeks","md",false,"https:\u002F\u002Fgithub.com\u002Fszuryuu\u002Fmikro-manager","\u002Fimages\u002Fprojects\u002Fmikrotik.png",null,{},"\u002Fproject\u002Fmikro-manager",{"title":5,"description":520},"Completed","project\u002Fmikro-manager",[533,534,535,536,537],"Python","MikroTik","Paramiko","Streamlit","SSH","Team Project","2024","XP7ksGjcqHdxs6dJTAE6ut7dWIm_CLeJxyPykXjoiQI",1776582962962]