diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..d4a2c44 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,21 @@ +# http://editorconfig.org + +root = true + +[*] +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true +insert_final_newline = true +charset = utf-8 +end_of_line = lf + +[*.bat] +indent_style = tab +end_of_line = crlf + +[LICENSE] +insert_final_newline = false + +[Makefile] +indent_style = tab diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..668b9aa --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,30 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug +assignees: '' + +--- + +**NetBox version** +What version of NetBox are you currently running? + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..11fc491 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/workflows/mkdocs.yml b/.github/workflows/mkdocs.yml new file mode 100644 index 0000000..eedcdb1 --- /dev/null +++ b/.github/workflows/mkdocs.yml @@ -0,0 +1,18 @@ +name: ci +on: + push: + branches: + - master + - main +permissions: + contents: write +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: 3.x + - run: pip install mkdocs-material mkdocs-autorefs mkdocs-material-extensions mkdocstrings mkdocstrings-python-legacy mkdocs-include-markdown-plugin + - run: mkdocs gh-deploy --force diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c915d1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,106 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# dotenv +.env + +# virtualenv +.venv +venv/ +ENV/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + +# IDE settings +.vscode/ +.idea/ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..fc63d4f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +# Changelog + +## 0.1.0 (2023-01-27) + +* First release on PyPI. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..7d39f20 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,114 @@ +# Contributing + +Contributions are welcome, and they are greatly appreciated! Every little bit +helps, and credit will always be given. + +You can contribute in many ways: + +## Types of Contributions + +### Report Bugs + +Report bugs at https://github.com/arthanson/netbox_napalm_plugin/issues. + +If you are reporting a bug, please include: + +* Your operating system name and version. +* Any details about your local setup that might be helpful in troubleshooting. +* Detailed steps to reproduce the bug. + +### Fix Bugs + +Look through the GitHub issues for bugs. Anything tagged with "bug" and "help +wanted" is open to whoever wants to implement it. + +### Implement Features + +Look through the GitHub issues for features. Anything tagged with "enhancement" +and "help wanted" is open to whoever wants to implement it. + +### Write Documentation + +NetBox Napalm Plugin could always use more documentation, whether as part of the +official NetBox Napalm Plugin docs, in docstrings, or even on the web in blog posts, +articles, and such. + +### Submit Feedback + +The best way to send feedback is to file an issue at https://github.com/arthanson/netbox_napalm_plugin/issues. + +If you are proposing a feature: + +* Explain in detail how it would work. +* Keep the scope as narrow as possible, to make it easier to implement. +* Remember that this is a volunteer-driven project, and that contributions + are welcome :) + +## Get Started! + +Ready to contribute? Here's how to set up `netbox_napalm_plugin` for local development. + +1. Fork the `netbox_napalm_plugin` repo on GitHub. +2. Clone your fork locally + + ``` + $ git clone git@github.com:your_name_here/netbox_napalm_plugin.git + ``` + +3. Install dependencies and start your virtualenv: + + ``` + $ poetry install -E test -E doc -E dev + ``` + +4. Create a branch for local development: + + ``` + $ git checkout -b name-of-your-bugfix-or-feature + ``` + + Now you can make your changes locally. + +5. When you're done making changes, check that your changes pass the + tests, including testing other Python versions, with tox: + + ``` + $ poetry run tox + ``` + +6. Commit your changes and push your branch to GitHub: + + ``` + $ git add . + $ git commit -m "Your detailed description of your changes." + $ git push origin name-of-your-bugfix-or-feature + ``` + +7. Submit a pull request through the GitHub website. + +## Pull Request Guidelines + +Before you submit a pull request, check that it meets these guidelines: + +1. The pull request should include tests. +2. If the pull request adds functionality, the docs should be updated. Put + your new functionality into a function with a docstring, and add the + feature to the list in README.md. +3. The pull request should work for Python 3.6, 3.7, 3.8 and 3.9. Check + https://github.com/arthanson/netbox_napalm_plugin/actions + and make sure that the tests pass for all supported Python versions. + + +## Deploying + +A reminder for the maintainers on how to deploy. +Make sure all your changes are committed (including an entry in CHANGELOG.md). +Then run: + +``` +$ poetry run bump2version patch # possible: major / minor / patch +$ git push +$ git push --tags +``` + +GitHub Actions will then deploy to PyPI if tests pass. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/LICENSE @@ -0,0 +1 @@ + diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..ca948a2 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,9 @@ +include CONTRIBUTING.md +include LICENSE +include README.md + +recursive-include tests * +recursive-exclude * __pycache__ +recursive-exclude * *.py[co] + +recursive-include docs *.rst conf.py Makefile make.bat *.jpg *.png *.gif diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b8b1d41 --- /dev/null +++ b/Makefile @@ -0,0 +1,18 @@ +sources = NetBox Napalm Plugin + +.PHONY: test format lint unittest pre-commit clean +test: format lint unittest + +format: + isort $(sources) tests + black $(sources) tests + +lint: + flake8 $(sources) tests + +pre-commit: + pre-commit run --all-files + +clean: + rm -rf *.egg-info + rm -rf .tox dist site diff --git a/README.md b/README.md new file mode 100644 index 0000000..a0b5582 --- /dev/null +++ b/README.md @@ -0,0 +1,59 @@ +==================== +# NetBox Napalm Plugin +==================== + +NetBox plugin for Napalm. + + +* Free software: Apache-2.0 +* Documentation: https://netbox-napalm-plugin.readthedocs.io. + + +## Features + +The features the plugin provides should be listed here. + +## Compatibility + +| NetBox Version | Plugin Version | +|----------------|----------------| +| 3.4 | 0.1.0 | + +## Installing + +For adding to a NetBox Docker setup see +[the general instructions for using netbox-docker with plugins](https://github.com/netbox-community/netbox-docker/wiki/Using-Netbox-Plugins). + +While this is still in development and not yet on pypi you can install with pip: + +```bash +pip install git+https://github.com/arthanson/netbox_napalm_plugin +``` + +or by adding to your `local_requirements.txt` or `plugin_requirements.txt` (netbox-docker): + +```bash +git+https://github.com/arthanson/netbox_napalm_plugin +``` + +Enable the plugin in `/opt/netbox/netbox/netbox/configuration.py`, + or if you use netbox-docker, your `/configuration/plugins.py` file : + +```python +PLUGINS = [ + 'Napalm' +] + +PLUGINS_CONFIG = { + "Napalm": {}, +} +``` + +## Credits + +Based on the NetBox plugin tutorial: + +- [demo repository](https://github.com/netbox-community/netbox-plugin-demo) +- [tutorial](https://github.com/netbox-community/netbox-plugin-tutorial) + +This package was created with [Cookiecutter](https://github.com/audreyr/cookiecutter) and the [`netbox-community/cookiecutter-netbox-plugin`](https://github.com/netbox-community/cookiecutter-netbox-plugin) project template. diff --git a/docs/changelog.md b/docs/changelog.md new file mode 100644 index 0000000..67259da --- /dev/null +++ b/docs/changelog.md @@ -0,0 +1,3 @@ +{% + include-markdown "../CHANGELOG.md" +%} diff --git a/docs/contributing.md b/docs/contributing.md new file mode 100644 index 0000000..f9a79cb --- /dev/null +++ b/docs/contributing.md @@ -0,0 +1,3 @@ +{% + include-markdown "../CONTRIBUTING.md" +%} diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..925533a --- /dev/null +++ b/docs/index.md @@ -0,0 +1,3 @@ +{% + include-markdown "../README.md" +%} diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..929cd00 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,72 @@ +site_name: NetBox Napalm Plugin +site_url: https://arthanson.github.io/netbox_napalm_plugin +repo_url: https://github.com/arthanson/netbox_napalm_plugin +repo_name: arthanson/netbox_napalm_plugin +#strict: true +nav: + - Home: index.md + - Contributing: contributing.md + - Changelog: changelog.md +theme: + name: material + language: en + #logo: assets/logo.png + palette: + scheme: preference + primary: indigo + accent: indigo + features: + - navigation.indexes + - navigation.instant + - navigation.tabs.sticky +markdown_extensions: + - pymdownx.emoji: + emoji_index: !!python/name:materialx.emoji.twemoji + emoji_generator: !!python/name:materialx.emoji.to_svg + - pymdownx.critic + - pymdownx.caret + - pymdownx.mark + - pymdownx.tilde + - pymdownx.tabbed + - attr_list + - pymdownx.arithmatex: + generic: true + - pymdownx.highlight: + linenums: false + - pymdownx.superfences + - pymdownx.inlinehilite + - pymdownx.details + - admonition + - toc: + baselevel: 2 + permalink: true + slugify: !!python/name:pymdownx.slugs.uslugify + - meta +plugins: + - include-markdown + - search: + lang: en + - mkdocstrings: + watch: + - netbox_napalm_plugin +extra: + social: + - icon: fontawesome/brands/twitter + # replace with your own tweet link below + link: https://github.com/netbox-community/cookiecutter-netbox-plugin + name: Tweet + - icon: fontawesome/brands/facebook + # replace with your own facebook link below + link: https://github.com/netbox-community/cookiecutter-netbox-plugin + name: Facebook + - icon: fontawesome/brands/github + link: https://github.com/arthanson/netbox_napalm_plugin + name: Github + - icon: material/email + link: "mailto:ahanson@netboxlabs.com" + # to enable disqus, uncomment the following and put your disqus id below + # disqus: disqus_id +# uncomment the following and put your google tracking id below to enable GA +#google_analytics: + #- UA-xxx + #- auto diff --git a/netbox_napalm_plugin/__init__.py b/netbox_napalm_plugin/__init__.py new file mode 100644 index 0000000..571dcd3 --- /dev/null +++ b/netbox_napalm_plugin/__init__.py @@ -0,0 +1,19 @@ +"""Top-level package for NetBox Napalm Plugin.""" + +__author__ = """Arthur Hanson""" +__email__ = 'ahanson@netboxlabs.com' +__version__ = '0.1.0' + + +from extras.plugins import PluginConfig + + +class NapalmConfig(PluginConfig): + name = 'netbox_napalm_plugin' + verbose_name = 'NetBox Napalm Plugin' + description = 'NetBox plugin for Napalm.' + version = 'version' + base_url = 'netbox_napalm_plugin' + + +config = NapalmConfig diff --git a/netbox_napalm_plugin/filtersets.py b/netbox_napalm_plugin/filtersets.py new file mode 100644 index 0000000..d8cff16 --- /dev/null +++ b/netbox_napalm_plugin/filtersets.py @@ -0,0 +1,12 @@ +from netbox.filtersets import NetBoxModelFilterSet +from .models import Napalm + + +# class NapalmFilterSet(NetBoxModelFilterSet): +# +# class Meta: +# model = Napalm +# fields = ['name', ] +# +# def search(self, queryset, name, value): +# return queryset.filter(description__icontains=value) diff --git a/netbox_napalm_plugin/forms.py b/netbox_napalm_plugin/forms.py new file mode 100644 index 0000000..9beecb3 --- /dev/null +++ b/netbox_napalm_plugin/forms.py @@ -0,0 +1,13 @@ +from django import forms + +from ipam.models import Prefix +from netbox.forms import NetBoxModelForm, NetBoxModelFilterSetForm +from utilities.forms.fields import CommentField, DynamicModelChoiceField +from .models import Napalm + + +class NapalmForm(NetBoxModelForm): + + class Meta: + model = Napalm + fields = ('name', 'tags') diff --git a/netbox_napalm_plugin/models.py b/netbox_napalm_plugin/models.py new file mode 100644 index 0000000..658850b --- /dev/null +++ b/netbox_napalm_plugin/models.py @@ -0,0 +1,19 @@ +from django.db import models +from django.urls import reverse + +from netbox.models import NetBoxModel + + +class Napalm(NetBoxModel): + name = models.CharField( + max_length=100 + ) + + class Meta: + ordering = ('name',) + + def __str__(self): + return self.name + + def get_absolute_url(self): + return reverse('plugins:netbox_napalm_plugin:napalm', args=[self.pk]) diff --git a/netbox_napalm_plugin/navigation.py b/netbox_napalm_plugin/navigation.py new file mode 100644 index 0000000..964c916 --- /dev/null +++ b/netbox_napalm_plugin/navigation.py @@ -0,0 +1,20 @@ +from extras.plugins import PluginMenuButton, PluginMenuItem +from utilities.choices import ButtonColorChoices + + +plugin_buttons = [ + PluginMenuButton( + link='plugins:netbox_napalm_plugin:napalm_add', + title='Add', + icon_class='mdi mdi-plus-thick', + color=ButtonColorChoices.GREEN + ) +] + +menu_items = ( + PluginMenuItem( + link='plugins:netbox_napalm_plugin:napalm_list', + link_text='Napalm', + buttons=plugin_buttons + ), +) diff --git a/netbox_napalm_plugin/tables.py b/netbox_napalm_plugin/tables.py new file mode 100644 index 0000000..a57d9ee --- /dev/null +++ b/netbox_napalm_plugin/tables.py @@ -0,0 +1,15 @@ +import django_tables2 as tables + +from netbox.tables import NetBoxTable, ChoiceFieldColumn +from .models import Napalm + + +class NapalmTable(NetBoxTable): + name = tables.Column( + linkify=True + ) + + class Meta(NetBoxTable.Meta): + model = Napalm + fields = ('pk', 'id', 'name', 'actions') + default_columns = ('name', ) diff --git a/netbox_napalm_plugin/templates/netbox_napalm_plugin/napalm.html b/netbox_napalm_plugin/templates/netbox_napalm_plugin/napalm.html new file mode 100644 index 0000000..eb61606 --- /dev/null +++ b/netbox_napalm_plugin/templates/netbox_napalm_plugin/napalm.html @@ -0,0 +1,29 @@ + +{% extends 'generic/object.html' %} +{% load render_table from django_tables2 %} + +{% block content %} +
+
+
+ +
NetBox Napalm Plugin
+ +
+ + + + + +
Name{{ object.name }}
+
+
+ {% include 'inc/panels/custom_fields.html' %} +
+
+ {% include 'inc/panels/tags.html' %} + {% include 'inc/panels/comments.html' %} +
+
+{% endblock content %} + diff --git a/netbox_napalm_plugin/urls.py b/netbox_napalm_plugin/urls.py new file mode 100644 index 0000000..ee48447 --- /dev/null +++ b/netbox_napalm_plugin/urls.py @@ -0,0 +1,18 @@ +from django.urls import path + +from netbox.views.generic import ObjectChangeLogView +from . import models, views + + +urlpatterns = ( + + path('napalms/', views.NapalmListView.as_view(), name='napalm_list'), + path('napalms/add/', views.NapalmEditView.as_view(), name='napalm_add'), + path('napalms//', views.NapalmView.as_view(), name='napalm'), + path('napalms//edit/', views.NapalmEditView.as_view(), name='napalm_edit'), + path('napalms//delete/', views.NapalmDeleteView.as_view(), name='napalm_delete'), + path('napalms//changelog/', ObjectChangeLogView.as_view(), name='napalm_changelog', kwargs={ + 'model': models.Napalm + }), + +) diff --git a/netbox_napalm_plugin/views.py b/netbox_napalm_plugin/views.py new file mode 100644 index 0000000..c23acac --- /dev/null +++ b/netbox_napalm_plugin/views.py @@ -0,0 +1,24 @@ +from django.db.models import Count + +from netbox.views import generic +from . import filtersets, forms, models, tables + + +class NapalmView(generic.ObjectView): + queryset = models.Napalm.objects.all() + + +class NapalmListView(generic.ObjectListView): + queryset = models.Napalm.objects.all() + table = tables.NapalmTable + + +class NapalmEditView(generic.ObjectEditView): + queryset = models.Napalm.objects.all() + form = forms.NapalmForm + + +class NapalmDeleteView(generic.ObjectDeleteView): + queryset = models.Napalm.objects.all() + + diff --git a/requirements_dev.txt b/requirements_dev.txt new file mode 100644 index 0000000..741ce49 --- /dev/null +++ b/requirements_dev.txt @@ -0,0 +1,9 @@ +pip==22.3.1 +bump2version==0.5.11 +wheel==0.33.6 +watchdog==0.9.0 +flake8==6.0.0 +Sphinx==1.8.5 +twine==4.0.2 +black==22.12.0 +isort=5.11.4 diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..8b7217d --- /dev/null +++ b/setup.cfg @@ -0,0 +1,46 @@ +[flake8] +max-line-length = 120 +max-complexity = 18 +ignore = E203, E266, W503 +per-file-ignores = __init__.py:F401 +exclude = .git, + __pycache__, + setup.py, + build, + dist, + docs, + releases, + .venv, + .tox, + .mypy_cache, + .pytest_cache, + .vscode, + .github, + # By default test codes will be linted. + # tests + +[tox:tox] +isolated_build = true +envlist = py38, py39, py310, format, lint, build + +[gh-actions] +python = + 3.10: py310 + 3.9: py39 + 3.8: py38, format, lint, build + +[bumpversion] +current_version = 0.1.0 +commit = True +tag = True + +[bumpversion:file:setup.py] +search = version='{current_version}' +replace = version='{new_version}' + +[bumpversion:file:netbox_napalm_plugin/__init__.py] +search = __version__ = '{current_version}' +replace = __version__ = '{new_version}' + +[bdist_wheel] +universal = 1 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..24d2307 --- /dev/null +++ b/setup.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python + +"""The setup script.""" + +from setuptools import setup, find_packages + +with open('README.md') as readme_file: + readme = readme_file.read() + +requirements = [] + +setup( + author="Arthur Hanson", + author_email='ahanson@netboxlabs.com', + python_requires='>=3.8', + classifiers=[ + 'Development Status :: 2 - Pre-Alpha', + 'Intended Audience :: Developers', + 'Natural Language :: English', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + ], + description="NetBox plugin for Napalm.", + install_requires=requirements, + long_description=readme, + include_package_data=True, + keywords='netbox_napalm_plugin', + name='netbox_napalm_plugin', + packages=find_packages(include=['netbox_napalm_plugin', 'netbox_napalm_plugin.*']), + test_suite='tests', + url='https://github.com/arthanson/netbox_napalm_plugin', + version='0.1.0', + zip_safe=False, +) diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..a11067d --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1 @@ +"""Unit test package for netbox_napalm_plugin.""" diff --git a/tests/test_netbox_napalm_plugin.py b/tests/test_netbox_napalm_plugin.py new file mode 100644 index 0000000..c883a71 --- /dev/null +++ b/tests/test_netbox_napalm_plugin.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python + +"""Tests for `netbox_napalm_plugin` package.""" + +from netbox_napalm_plugin import netbox_napalm_plugin +