diff --git a/netbox/core/plugins.py b/netbox/core/plugins.py index e31e7d67a..e633001f5 100644 --- a/netbox/core/plugins.py +++ b/netbox/core/plugins.py @@ -32,6 +32,8 @@ class Plugin: tag_line: str = '' description_short: str = '' author: str = '' + homepage_url: str = '' + license_type: str = '' created: datetime.datetime = None updated: datetime.datetime = None is_local: bool = False @@ -41,7 +43,8 @@ class Plugin: versions: list[PluginVersion] = field(default_factory=list) -def get_local_plugins(plugins): +def get_local_plugins(): + plugins = {} for plugin_name in settings.PLUGINS: plugin = importlib.import_module(plugin_name) plugin_config: PluginConfig = plugin.config @@ -62,20 +65,20 @@ def get_local_plugins(plugins): return plugins -def get_catalog_plugins(plugins): - url = 'https://api.netbox.oss.netboxlabs.com/v1/plugins' +def get_catalog_plugins(): session = requests.Session() + plugins = {} def get_pages(): # TODO: pagintation is curently broken in API payload = {'page': '1', 'per_page': '50'} - first_page = session.get(url, params=payload).json() + first_page = session.get(settings.PLUGIN_CATALOG_URL, params=payload).json() yield first_page num_pages = first_page['metadata']['pagination']['last_page'] for page in range(2, num_pages + 1): payload['page'] = page - next_page = session.get(url, params=payload).json() + next_page = session.get(settings.PLUGIN_CATALOG_URL, params=payload).json() yield next_page for page in get_pages(): @@ -96,39 +99,43 @@ def get_catalog_plugins(plugins): is_netboxlabs_supported=version['is_netboxlabs_supported'], ) ) + versions = sorted(versions, key=lambda x: x.date, reverse=True) - if data['slug'] in plugins: - plugins[data['slug']].is_local = False - plugins[data['slug']].is_certified = data['release_latest']['is_certified'] - plugins[data['slug']].description_short = data['description_short'] - else: - plugins[data['slug']] = Plugin( - slug=data['slug'], - config_name=data['config_name'], - name=data['title_short'], - title_long=data['title_long'], - tag_line=data['tag_line'], - description_short=data['description_short'], - author=data['author']['name'] or _('Unknown Author'), - created=datetime_from_timestamp(data['created_at']), - updated=datetime_from_timestamp(data['updated_at']), - is_local=False, - is_installed=False, - is_certified=data['release_latest']['is_certified'], - is_community=not data['release_latest']['is_certified'], - versions=versions, - ) + plugins[data['slug']] = Plugin( + slug=data['slug'], + config_name=data['config_name'], + name=data['title_short'], + title_long=data['title_long'], + tag_line=data['tag_line'], + description_short=data['description_short'], + author=data['author']['name'] or _('Unknown Author'), + homepage_url=data['homepage_url'], + license_type=data['license_type'], + created=datetime_from_timestamp(data['created_at']), + updated=datetime_from_timestamp(data['updated_at']), + is_local=False, + is_installed=False, + is_certified=data['release_latest']['is_certified'], + is_community=not data['release_latest']['is_certified'], + versions=versions, + ) return plugins def get_plugins(): - if plugins := cache.get('plugins-catalog-feed'): - return plugins + local_plugins = get_local_plugins() + catalog_plugins = cache.get('plugins-catalog-feed') + if not catalog_plugins: + catalog_plugins = get_catalog_plugins() + cache.set('plugins-catalog-feed', catalog_plugins, 3600) - plugins = {} - plugins = get_local_plugins(plugins) - plugins = get_catalog_plugins(plugins) + plugins = catalog_plugins + for k, v in local_plugins.items(): + if k in plugins: + plugins[k].is_local = True + plugins[k].is_installed = True + else: + plugins[k] = v - cache.set('plugins-catalog-feed', plugins, 3600) return plugins diff --git a/netbox/core/views.py b/netbox/core/views.py index 692e10801..fa8c18a1b 100644 --- a/netbox/core/views.py +++ b/netbox/core/views.py @@ -617,12 +617,6 @@ class SystemView(UserPassesTestMixin, View): 'rq_worker_count': Worker.count(get_connection('default')), } - # Plugins - plugins = [ - # Look up app config by package name - apps.get_app_config(plugin.rsplit('.', 1)[-1]) for plugin in settings.PLUGINS - ] - # Configuration try: config = ConfigRevision.objects.get(pk=cache.get('config_version')) @@ -634,9 +628,6 @@ class SystemView(UserPassesTestMixin, View): if 'export' in request.GET: data = { **stats, - 'plugins': { - plugin.name: plugin.version for plugin in plugins - }, 'config': { k: config.data[k] for k in sorted(config.data) }, @@ -664,10 +655,18 @@ class PluginListView(UserPassesTestMixin, View): q = request.GET.get('q', None) plugins = get_plugins() + plugins = plugins.values() if q: - plugins = [v for k, v in plugins.items() if q.casefold() in v['name'].casefold()] - else: - plugins = plugins.values() + plugins = [obj for obj in plugins if q.casefold() in obj.name.casefold()] + + # Sort order should be: + # Installed plugins + # Certified catalog plugins + # Remaining catalog plugins + # With alphabetical sort within each traunch. + plugins = sorted(plugins, key=lambda x: x.name, reverse=False) + plugins = sorted(plugins, key=lambda x: x.is_certified, reverse=True) + plugins = sorted(plugins, key=lambda x: x.is_installed, reverse=True) table = CatalogPluginTable(plugins, user=request.user) table.configure(request) diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 64fb24f09..b2ce3eacd 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -769,6 +769,8 @@ STRAWBERRY_DJANGO = { # Plugins # +PLUGIN_CATALOG_URL = 'https://api.netbox.oss.netboxlabs.com/v1/plugins' + # Register any configured plugins for plugin_name in PLUGINS: try: diff --git a/netbox/templates/core/plugin.html b/netbox/templates/core/plugin.html index de7060394..020326b7d 100644 --- a/netbox/templates/core/plugin.html +++ b/netbox/templates/core/plugin.html @@ -15,6 +15,8 @@ {% block subtitle %}
You can install this plugin from the command line with PyPi.
-The following commands may be helpful; always refer to the plugin's own documentation and the Installing a Plugin unit of the NetBox documentation.
-1. Enter the NetBox virtual environment and install the plugin package:
+ {% if plugin.is_community %} +You can install this plugin from the command line with PyPi.
+The following commands may be helpful; always refer to the plugin's own documentation and the Installing a Plugin unit of the NetBox documentation.
+1. Enter the NetBox virtual environment and install the plugin package:
-
+
source /opt/netbox/venv/bin/activate
pip install {{ plugin.slug }}
@@ -76,16 +81,17 @@ pip install {{ plugin.slug }}
PLUGINS=[
"{{ plugin.config_name }}",
]
-
- 3. Still from the NetBox virtual environment, run database migrations and collect static files:
-
-python3 /opt/netbox/netbox/netbox/manage.py migrate
-python3 /opt/netbox/netbox/netbox/manage.py collectstatic
-
- 4. Restart the NetBox services to complete the plugin installation:
-
-sudo systemctl restart netbox netbox-rq
-
- 3. Still from the NetBox virtual environment, run database migrations and collect static files:
+
+ python3 /opt/netbox/netbox/netbox/manage.py migrate
+ python3 /opt/netbox/netbox/netbox/manage.py collectstatic
+
+ 4. Restart the NetBox services to complete the plugin installation:
+
+ sudo systemctl restart netbox netbox-rq
+
+