netbox-docker-plugin 5.0.1__tar.gz → 5.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {netbox_docker_plugin-5.0.1/netbox_docker_plugin.egg-info → netbox_docker_plugin-5.1.1}/PKG-INFO +5 -1
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/__init__.py +1 -1
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/api/serializers.py +8 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/forms/container.py +23 -0
- netbox_docker_plugin-5.1.1/netbox_docker_plugin/migrations/1043_container_cap_drop_container_extra_hosts_and_more.py +60 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/models/container.py +75 -3
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/models/image.py +1 -1
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/tables.py +4 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/templates/netbox_docker_plugin/container.html +16 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/tests/container/test_container_api.py +18 -0
- netbox_docker_plugin-5.1.1/netbox_docker_plugin/tests/container/test_container_delete.py +137 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/tests/container/test_container_views.py +5 -1
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/views/container.py +60 -1
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1/netbox_docker_plugin.egg-info}/PKG-INFO +5 -1
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin.egg-info/SOURCES.txt +3 -0
- netbox_docker_plugin-5.1.1/netbox_docker_plugin.egg-info/requires.txt +5 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/pyproject.toml +7 -1
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/LICENSE +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/MANIFEST.in +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/README.md +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/api/__init__.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/api/renderers.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/api/urls.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/api/views.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/filtersets.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/forms/__init__.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/forms/bind.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/forms/device.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/forms/env.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/forms/host.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/forms/image.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/forms/label.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/forms/log_driver_option.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/forms/mount.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/forms/network.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/forms/network_setting.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/forms/port.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/forms/registry.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/forms/sysctl.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/forms/volume.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0001_initial.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0002_image.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0003_image_size.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0004_volume.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0005_network.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0006_container_port_mount_label_env_and_more.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0007_remove_container_netbox_docker_plugin_container_unique_name_host__and_more.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0008_alter_network_unique_together_network_networkid_and_more.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0009_remove_container_network_networksettings_and_more.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0010_container_containerid_and_more.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0011_host_token.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0012_host_state.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0013_host_netbox_url.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0014_container_operation.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0015_remove_mount_netbox_docker_plugin_mount_unique_volume_and_more.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0016_alter_env_value.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0017_network_state.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0018_alter_mount_volume_alter_networksetting_network.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0019_host_agent_version_host_docker_api_version.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0020_container_hostname.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0021_registry_and_more.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0022_bind_bind_netbox_docker_plugin_bind_unique_bind.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0023_delete_hosts.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0024_registry_host_alter_registry_name_and_more.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0025_alter_image_version.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0026_image_digest.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0027_container_restart_policy.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0028_mount_and_bind_read_only.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0029_alter_container_state.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0030_alter_container_containerid_alter_container_hostname_and_more.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0031_container_cap_add.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0032_device_and_more.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0033_host_operation.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0034_volume_max_size.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0035_container_log_driver_logdriveroption.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0036_alter_container_log_driver.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0037_alter_env_value.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/0038_container_cmd.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/1039_alter_port_public_port.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/1040_alter_container_log_driver.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/1041_sysctl.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/1042_registry_username_max_length.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/migrations/__init__.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/models/__init__.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/models/host.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/models/network.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/models/registry.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/models/volume.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/navigation.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/signals.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/templates/netbox_docker_plugin/container-exec.html +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/templates/netbox_docker_plugin/container-layout.html +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/templates/netbox_docker_plugin/container-logs.html +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/templates/netbox_docker_plugin/host-graph.html +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/templates/netbox_docker_plugin/host.html +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/templates/netbox_docker_plugin/image.html +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/templates/netbox_docker_plugin/network.html +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/templates/netbox_docker_plugin/registry.html +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/templates/netbox_docker_plugin/volume.html +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/templatetags/__init__.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/templatetags/host.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/tests/__init__.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/tests/base.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/tests/container/__init__.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/tests/container/test_container_actions.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/tests/container/test_container_api_exec.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/tests/container/test_container_operation_view.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/tests/container/test_container_validation.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/tests/host/__init__.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/tests/host/test_host_api.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/tests/host/test_host_views.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/tests/host/test_replace_password.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/tests/image/__init__.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/tests/image/test_force_pull_image_with_special_cf.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/tests/image/test_image_api.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/tests/image/test_image_views.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/tests/network/__init__.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/tests/network/test_network_api.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/tests/network/test_network_views.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/tests/registry/__init__.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/tests/registry/test_registry_api.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/tests/registry/test_registry_views.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/tests/test_init.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/tests/volume/__init__.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/tests/volume/test_volume_api.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/tests/volume/test_volume_views.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/urls.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/utilities/__init__.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/views/__init__.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/views/bind.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/views/device.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/views/env.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/views/host.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/views/image.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/views/label.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/views/log_driver_option.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/views/mount.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/views/network.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/views/network_setting.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/views/port.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/views/registry.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/views/sysctl.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/views/volume.py +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin.egg-info/dependency_links.txt +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin.egg-info/top_level.txt +0 -0
- {netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/setup.cfg +0 -0
{netbox_docker_plugin-5.0.1/netbox_docker_plugin.egg-info → netbox_docker_plugin-5.1.1}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: netbox-docker-plugin
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.1.1
|
|
4
4
|
Summary: Manage Docker with Netbox & style.
|
|
5
5
|
Author-email: Vincent Simonin <vincent@saashup.com>, David Delassus <david.jose.delassus@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/SaaShup/netbox-docker-plugin
|
|
@@ -10,6 +10,10 @@ Classifier: Programming Language :: Python :: 3
|
|
|
10
10
|
Requires-Python: >=3.12
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
12
|
License-File: LICENSE
|
|
13
|
+
Provides-Extra: dev
|
|
14
|
+
Requires-Dist: requests-mock; extra == "dev"
|
|
15
|
+
Requires-Dist: coverage; extra == "dev"
|
|
16
|
+
Requires-Dist: pylint; extra == "dev"
|
|
13
17
|
Dynamic: license-file
|
|
14
18
|
|
|
15
19
|
# Netbox Docker Plugin
|
|
@@ -11,7 +11,7 @@ class NetBoxDockerConfig(PluginConfig):
|
|
|
11
11
|
name = "netbox_docker_plugin"
|
|
12
12
|
verbose_name = " NetBox Docker Plugin"
|
|
13
13
|
description = "Manage Docker"
|
|
14
|
-
version = "5.
|
|
14
|
+
version = "5.1.1"
|
|
15
15
|
base_url = "docker"
|
|
16
16
|
min_version = "4.5.0"
|
|
17
17
|
author = "Vincent Simonin <vincent@saashup.com>, David Delassus <david.jose.delassus@gmail.com>"
|
{netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/api/serializers.py
RENAMED
|
@@ -175,7 +175,11 @@ class NestedContainerSerializer(WritableNestedSerializer):
|
|
|
175
175
|
"operation",
|
|
176
176
|
"hostname",
|
|
177
177
|
"cap_add",
|
|
178
|
+
"cap_drop",
|
|
178
179
|
"log_driver",
|
|
180
|
+
"secOpt",
|
|
181
|
+
"pid_mode",
|
|
182
|
+
"extra_hosts",
|
|
179
183
|
"cmd",
|
|
180
184
|
)
|
|
181
185
|
|
|
@@ -481,6 +485,10 @@ class ContainerSerializer(NetBoxModelSerializer):
|
|
|
481
485
|
"hostname",
|
|
482
486
|
"restart_policy",
|
|
483
487
|
"cap_add",
|
|
488
|
+
"cap_drop",
|
|
489
|
+
"secOpt",
|
|
490
|
+
"pid_mode",
|
|
491
|
+
"extra_hosts",
|
|
484
492
|
"cmd",
|
|
485
493
|
"ports",
|
|
486
494
|
"env",
|
{netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/forms/container.py
RENAMED
|
@@ -19,6 +19,7 @@ from ..models.container import (
|
|
|
19
19
|
Container,
|
|
20
20
|
ContainerRestartPolicyChoices,
|
|
21
21
|
ContainerCapAddChoices,
|
|
22
|
+
ContainerCapDropChoices,
|
|
22
23
|
)
|
|
23
24
|
from ..models.image import Image
|
|
24
25
|
|
|
@@ -36,6 +37,9 @@ class ContainerForm(NetBoxModelForm):
|
|
|
36
37
|
query_params={"host_id": "$host"},
|
|
37
38
|
)
|
|
38
39
|
cap_add = forms.MultipleChoiceField(choices=ContainerCapAddChoices, required=False)
|
|
40
|
+
cap_drop = forms.MultipleChoiceField(
|
|
41
|
+
choices=ContainerCapDropChoices, required=False
|
|
42
|
+
)
|
|
39
43
|
|
|
40
44
|
class Meta:
|
|
41
45
|
"""Container form definition Meta class"""
|
|
@@ -48,6 +52,10 @@ class ContainerForm(NetBoxModelForm):
|
|
|
48
52
|
"hostname",
|
|
49
53
|
"restart_policy",
|
|
50
54
|
"cap_add",
|
|
55
|
+
"cap_drop",
|
|
56
|
+
"secOpt",
|
|
57
|
+
"pid_mode",
|
|
58
|
+
"extra_hosts",
|
|
51
59
|
"log_driver",
|
|
52
60
|
"cmd",
|
|
53
61
|
"tags",
|
|
@@ -59,6 +67,10 @@ class ContainerForm(NetBoxModelForm):
|
|
|
59
67
|
"hostname": "Hostname",
|
|
60
68
|
"restart_policy": "Restart Policy",
|
|
61
69
|
"cap_add": "Add Host capabilities",
|
|
70
|
+
"cap_drop": "Drop Host capabilities",
|
|
71
|
+
"secOpt": "Security options (separate by comma)",
|
|
72
|
+
"pid_mode": "PID mode",
|
|
73
|
+
"extra_hosts": "Extra hosts (separate by comma). Specified in the form hostname:IP",
|
|
62
74
|
"log_driver": "Logging driver",
|
|
63
75
|
"cmd": "Command",
|
|
64
76
|
}
|
|
@@ -73,6 +85,9 @@ class ContainerEditForm(NetBoxModelForm):
|
|
|
73
85
|
required=True,
|
|
74
86
|
)
|
|
75
87
|
cap_add = forms.MultipleChoiceField(choices=ContainerCapAddChoices, required=False)
|
|
88
|
+
cap_drop = forms.MultipleChoiceField(
|
|
89
|
+
choices=ContainerCapDropChoices, required=False
|
|
90
|
+
)
|
|
76
91
|
|
|
77
92
|
class Meta:
|
|
78
93
|
"""Container form definition Meta class"""
|
|
@@ -84,6 +99,10 @@ class ContainerEditForm(NetBoxModelForm):
|
|
|
84
99
|
"hostname",
|
|
85
100
|
"restart_policy",
|
|
86
101
|
"cap_add",
|
|
102
|
+
"cap_drop",
|
|
103
|
+
"secOpt",
|
|
104
|
+
"pid_mode",
|
|
105
|
+
"extra_hosts",
|
|
87
106
|
"log_driver",
|
|
88
107
|
"cmd",
|
|
89
108
|
"tags",
|
|
@@ -94,6 +113,10 @@ class ContainerEditForm(NetBoxModelForm):
|
|
|
94
113
|
"hostname": "Hostname",
|
|
95
114
|
"restart_policy": "Restart Policy",
|
|
96
115
|
"cap_add": "Add Host capabilities",
|
|
116
|
+
"cap_drop": "Drop Host capabilities",
|
|
117
|
+
"secOpt": "Security options (separate by comma)",
|
|
118
|
+
"pid_mode": "PID mode",
|
|
119
|
+
"extra_hosts": "Extra hosts (separate by comma). Specified in the form hostname:IP",
|
|
97
120
|
"log_driver": "Logging driver",
|
|
98
121
|
"cmd": "Command",
|
|
99
122
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# pylint: disable=C0103
|
|
2
|
+
"""Migration file"""
|
|
3
|
+
|
|
4
|
+
import django.contrib.postgres.fields
|
|
5
|
+
import django.core.validators
|
|
6
|
+
from django.db import migrations, models
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Migration(migrations.Migration):
|
|
10
|
+
"""Migration file"""
|
|
11
|
+
|
|
12
|
+
dependencies = [
|
|
13
|
+
("netbox_docker_plugin", "1042_registry_username_max_length"),
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
operations = [
|
|
17
|
+
migrations.AddField(
|
|
18
|
+
model_name="container",
|
|
19
|
+
name="cap_drop",
|
|
20
|
+
field=django.contrib.postgres.fields.ArrayField(
|
|
21
|
+
base_field=models.CharField(blank=True, max_length=32, null=True),
|
|
22
|
+
blank=True,
|
|
23
|
+
null=True,
|
|
24
|
+
),
|
|
25
|
+
),
|
|
26
|
+
migrations.AddField(
|
|
27
|
+
model_name="container",
|
|
28
|
+
name="extra_hosts",
|
|
29
|
+
field=django.contrib.postgres.fields.ArrayField(
|
|
30
|
+
base_field=models.CharField(blank=True, max_length=512, null=True),
|
|
31
|
+
blank=True,
|
|
32
|
+
null=True,
|
|
33
|
+
),
|
|
34
|
+
),
|
|
35
|
+
migrations.AddField(
|
|
36
|
+
model_name="container",
|
|
37
|
+
name="pid_mode",
|
|
38
|
+
field=models.CharField(blank=True, max_length=512, null=True),
|
|
39
|
+
),
|
|
40
|
+
migrations.AddField(
|
|
41
|
+
model_name="container",
|
|
42
|
+
name="secOpt",
|
|
43
|
+
field=django.contrib.postgres.fields.ArrayField(
|
|
44
|
+
base_field=models.CharField(blank=True, max_length=512, null=True),
|
|
45
|
+
blank=True,
|
|
46
|
+
null=True,
|
|
47
|
+
),
|
|
48
|
+
),
|
|
49
|
+
migrations.AlterField(
|
|
50
|
+
model_name="image",
|
|
51
|
+
name="size",
|
|
52
|
+
field=models.IntegerField(
|
|
53
|
+
default=0,
|
|
54
|
+
validators=[
|
|
55
|
+
django.core.validators.MinValueValidator(limit_value=0),
|
|
56
|
+
django.core.validators.MaxValueValidator(limit_value=8192),
|
|
57
|
+
],
|
|
58
|
+
),
|
|
59
|
+
),
|
|
60
|
+
]
|
{netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/models/container.py
RENAMED
|
@@ -2,17 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
# pylint: disable=E1101
|
|
4
4
|
|
|
5
|
+
from django.contrib.contenttypes.models import ContentType
|
|
5
6
|
from django.contrib.postgres.fields import ArrayField
|
|
6
7
|
from django.core.exceptions import ValidationError
|
|
7
|
-
from django.db import models
|
|
8
|
-
from django.db.models.functions import Lower
|
|
9
|
-
from django.urls import reverse
|
|
10
8
|
from django.core.validators import (
|
|
11
9
|
MinLengthValidator,
|
|
12
10
|
MaxLengthValidator,
|
|
13
11
|
MinValueValidator,
|
|
14
12
|
MaxValueValidator,
|
|
15
13
|
)
|
|
14
|
+
from django.db import models
|
|
15
|
+
from django.db.models.functions import Lower
|
|
16
|
+
from django.urls import reverse
|
|
17
|
+
from extras.models import JournalEntry
|
|
16
18
|
from utilities.choices import ChoiceSet
|
|
17
19
|
from utilities.querysets import RestrictedQuerySet
|
|
18
20
|
from netbox.models import NetBoxModel
|
|
@@ -110,6 +112,41 @@ class ContainerCapAddChoices(ChoiceSet):
|
|
|
110
112
|
("SYS_PTRACE", "SYS_PTRACE"),
|
|
111
113
|
("SYS_RESOURCE", "SYS_RESOURCE"),
|
|
112
114
|
("SYS_NICE", "SYS_NICE"),
|
|
115
|
+
("ALL", "ALL"),
|
|
116
|
+
]
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class ContainerCapDropChoices(ChoiceSet):
|
|
120
|
+
"""cap-drop choices definition class"""
|
|
121
|
+
|
|
122
|
+
key = "Container.cap_drop"
|
|
123
|
+
|
|
124
|
+
CHOICES = [
|
|
125
|
+
("AUDIT_WRITE", "AUDIT_WRITE"),
|
|
126
|
+
("CHOWN", "CHOWN"),
|
|
127
|
+
("DAC_OVERRIDE", "DAC_OVERRIDE"),
|
|
128
|
+
("FOWNER", "FOWNER"),
|
|
129
|
+
("FSETID", "FSETID"),
|
|
130
|
+
("KILL", "KILL"),
|
|
131
|
+
("MKNOD", "MKNOD"),
|
|
132
|
+
("NET_BIND_SERVICE", "NET_BIND_SERVICE"),
|
|
133
|
+
("NET_RAW", "NET_RAW"),
|
|
134
|
+
("SETFCAP", "SETFCAP"),
|
|
135
|
+
("SETGID", "SETGID"),
|
|
136
|
+
("SETPCAP", "SETPCAP"),
|
|
137
|
+
("SETUID", "SETUID"),
|
|
138
|
+
("SYS_CHROOT", "SYS_CHROOT"),
|
|
139
|
+
("ALL", "ALL"),
|
|
140
|
+
]
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class PidModeChoices(ChoiceSet):
|
|
144
|
+
"""Pid mode choices definition class"""
|
|
145
|
+
|
|
146
|
+
key = "Container.pid_mode"
|
|
147
|
+
|
|
148
|
+
CHOICES = [
|
|
149
|
+
("host", "host"),
|
|
113
150
|
]
|
|
114
151
|
|
|
115
152
|
|
|
@@ -170,11 +207,34 @@ class Container(NetBoxModel):
|
|
|
170
207
|
null=True,
|
|
171
208
|
blank=True,
|
|
172
209
|
)
|
|
210
|
+
cap_drop = ArrayField(
|
|
211
|
+
models.CharField(
|
|
212
|
+
max_length=32, blank=True, null=True, choices=ContainerCapDropChoices
|
|
213
|
+
),
|
|
214
|
+
null=True,
|
|
215
|
+
blank=True,
|
|
216
|
+
)
|
|
173
217
|
log_driver = models.CharField(
|
|
174
218
|
max_length=32,
|
|
175
219
|
null=True,
|
|
176
220
|
blank=True,
|
|
177
221
|
)
|
|
222
|
+
secOpt = ArrayField(
|
|
223
|
+
models.CharField(max_length=512, blank=True, null=True),
|
|
224
|
+
null=True,
|
|
225
|
+
blank=True,
|
|
226
|
+
)
|
|
227
|
+
pid_mode = models.CharField(
|
|
228
|
+
max_length=512,
|
|
229
|
+
choices=PidModeChoices,
|
|
230
|
+
null=True,
|
|
231
|
+
blank=True,
|
|
232
|
+
)
|
|
233
|
+
extra_hosts = ArrayField(
|
|
234
|
+
models.CharField(max_length=512, blank=True, null=True),
|
|
235
|
+
null=True,
|
|
236
|
+
blank=True,
|
|
237
|
+
)
|
|
178
238
|
cmd = ArrayField(
|
|
179
239
|
models.CharField(max_length=1024, blank=True, null=True),
|
|
180
240
|
null=True,
|
|
@@ -248,6 +308,18 @@ class Container(NetBoxModel):
|
|
|
248
308
|
),
|
|
249
309
|
)
|
|
250
310
|
|
|
311
|
+
def delete(self, using=None, keep_parents=False):
|
|
312
|
+
ct = ContentType.objects.get_for_model(self)
|
|
313
|
+
qs = JournalEntry.objects.filter(
|
|
314
|
+
assigned_object_type=ct,
|
|
315
|
+
assigned_object_id=self.pk,
|
|
316
|
+
)
|
|
317
|
+
# _raw_delete issues a single SQL DELETE bypassing Django's Collector,
|
|
318
|
+
# avoiding per-row post_delete signals (ObjectChange writes) that make
|
|
319
|
+
# bulk journal cleanup O(n) slow.
|
|
320
|
+
qs._raw_delete(qs.db) # pylint: disable=protected-access
|
|
321
|
+
return super().delete(using, keep_parents)
|
|
322
|
+
|
|
251
323
|
def __str__(self):
|
|
252
324
|
return f"{self.name}"
|
|
253
325
|
|
|
@@ -40,6 +40,22 @@
|
|
|
40
40
|
<th scope="row">Host Capacities added</th>
|
|
41
41
|
<td>{{ object.cap_add }}</td>
|
|
42
42
|
</tr>
|
|
43
|
+
<tr>
|
|
44
|
+
<th scope="row">Host Capacities dropped</th>
|
|
45
|
+
<td>{{ object.cap_drop }}</td>
|
|
46
|
+
</tr>
|
|
47
|
+
<tr>
|
|
48
|
+
<th scope="row">Security options</th>
|
|
49
|
+
<td>{{ object.secOpt }}</td>
|
|
50
|
+
</tr>
|
|
51
|
+
<tr>
|
|
52
|
+
<th scope="row">PID mode</th>
|
|
53
|
+
<td>{{ object.pid_mode|placeholder }}</td>
|
|
54
|
+
</tr>
|
|
55
|
+
<tr>
|
|
56
|
+
<th scope="row">Extra hosts added</th>
|
|
57
|
+
<td>{{ object.extra_hosts }}</td>
|
|
58
|
+
</tr>
|
|
43
59
|
<tr>
|
|
44
60
|
<th scope="row">Status</th>
|
|
45
61
|
<td>{{ object.status|placeholder }}</td>
|
|
@@ -30,14 +30,18 @@ class ContainerApiTestCase(
|
|
|
30
30
|
brief_fields = [
|
|
31
31
|
"ContainerID",
|
|
32
32
|
"cap_add",
|
|
33
|
+
"cap_drop",
|
|
33
34
|
"cmd",
|
|
34
35
|
"display",
|
|
36
|
+
"extra_hosts",
|
|
35
37
|
"hostname",
|
|
36
38
|
"id",
|
|
37
39
|
"log_driver",
|
|
38
40
|
"name",
|
|
39
41
|
"operation",
|
|
42
|
+
"pid_mode",
|
|
40
43
|
"restart_policy",
|
|
44
|
+
"secOpt",
|
|
41
45
|
"state",
|
|
42
46
|
"status",
|
|
43
47
|
"url",
|
|
@@ -195,6 +199,20 @@ class ContainerApiTestCase(
|
|
|
195
199
|
"cap_add": ["NET_ADMIN"],
|
|
196
200
|
"cmd": ["cat", "/etc/hosts"],
|
|
197
201
|
},
|
|
202
|
+
{
|
|
203
|
+
"host": host2.pk,
|
|
204
|
+
"image": image2.pk,
|
|
205
|
+
"name": "container11",
|
|
206
|
+
"ports": [],
|
|
207
|
+
"env": [],
|
|
208
|
+
"labels": [],
|
|
209
|
+
"sysctls": [],
|
|
210
|
+
"cap_add": [],
|
|
211
|
+
"cap_drop": ["FSETID", "MKNOD"],
|
|
212
|
+
"pid_mode": "host",
|
|
213
|
+
"extra_hosts": ["test1:192.168.1.2", "test2:192.168.1.3"],
|
|
214
|
+
"secOpt": ["apparmor:unconfined"],
|
|
215
|
+
},
|
|
198
216
|
]
|
|
199
217
|
|
|
200
218
|
def test_that_patch_overwrites_data_only_when_explicitly_set(self):
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"""Container deletion tests — journal entry cleanup"""
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
|
|
5
|
+
from django.contrib.contenttypes.models import ContentType
|
|
6
|
+
from django.test import TestCase
|
|
7
|
+
|
|
8
|
+
from extras.models import JournalEntry
|
|
9
|
+
from netbox_docker_plugin.models.container import Container
|
|
10
|
+
from netbox_docker_plugin.models.host import Host
|
|
11
|
+
from netbox_docker_plugin.models.image import Image
|
|
12
|
+
from netbox_docker_plugin.models.registry import Registry
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _make_journal_entries(container, count):
|
|
16
|
+
ct = ContentType.objects.get_for_model(Container)
|
|
17
|
+
batch_size = 10000
|
|
18
|
+
for start in range(0, count, batch_size):
|
|
19
|
+
JournalEntry.objects.bulk_create(
|
|
20
|
+
[
|
|
21
|
+
JournalEntry(
|
|
22
|
+
assigned_object_type=ct,
|
|
23
|
+
assigned_object_id=container.pk,
|
|
24
|
+
created_by=None,
|
|
25
|
+
kind="info",
|
|
26
|
+
comments=f"entry {start + i}",
|
|
27
|
+
)
|
|
28
|
+
for i in range(min(batch_size, count - start))
|
|
29
|
+
]
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class ContainerDeleteJournalTestCase(TestCase):
|
|
34
|
+
"""Verify that container deletion cleans up journal entries in batches."""
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def setUpTestData(cls):
|
|
38
|
+
cls.host = Host.objects.create(endpoint="http://localhost:8080", name="host1")
|
|
39
|
+
cls.registry = Registry.objects.create(
|
|
40
|
+
host=cls.host,
|
|
41
|
+
name="registry1",
|
|
42
|
+
serveraddress="http://localhost:8080",
|
|
43
|
+
)
|
|
44
|
+
cls.image = Image.objects.create(
|
|
45
|
+
host=cls.host, name="image1", registry=cls.registry
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
def _make_container(self, name="container1", state="exited"):
|
|
49
|
+
"""Create and return a Container in the given state."""
|
|
50
|
+
return Container.objects.create(
|
|
51
|
+
host=self.host,
|
|
52
|
+
image=self.image,
|
|
53
|
+
name=name,
|
|
54
|
+
operation="none",
|
|
55
|
+
state=state,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
def test_delete_container_with_no_journal_entries(self):
|
|
59
|
+
"""Container with no journal entries can be deleted without errors."""
|
|
60
|
+
container = self._make_container()
|
|
61
|
+
pk = container.pk
|
|
62
|
+
t0 = time.monotonic()
|
|
63
|
+
container.delete()
|
|
64
|
+
print(
|
|
65
|
+
f"Deleted container (0 journal entries) in {(time.monotonic() - t0) * 1000:.1f}ms"
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
self.assertFalse(Container.objects.filter(pk=pk).exists())
|
|
69
|
+
|
|
70
|
+
def test_delete_container_removes_journal_entries(self):
|
|
71
|
+
"""Journal entries linked to the deleted container are removed."""
|
|
72
|
+
container = self._make_container(name="container2")
|
|
73
|
+
_make_journal_entries(container, 5)
|
|
74
|
+
ct = ContentType.objects.get_for_model(Container)
|
|
75
|
+
|
|
76
|
+
self.assertEqual(
|
|
77
|
+
JournalEntry.objects.filter(
|
|
78
|
+
assigned_object_type=ct, assigned_object_id=container.pk
|
|
79
|
+
).count(),
|
|
80
|
+
5,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
pk = container.pk
|
|
84
|
+
t0 = time.monotonic()
|
|
85
|
+
container.delete()
|
|
86
|
+
print(
|
|
87
|
+
f"Deleted container (5 journal entries) in {(time.monotonic() - t0) * 1000:.1f}ms"
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
self.assertFalse(Container.objects.filter(pk=pk).exists())
|
|
91
|
+
self.assertEqual(
|
|
92
|
+
JournalEntry.objects.filter(
|
|
93
|
+
assigned_object_type=ct, assigned_object_id=pk
|
|
94
|
+
).count(),
|
|
95
|
+
0,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
def test_delete_container_removes_many_journal_entries(self):
|
|
99
|
+
"""Deletion removes all journal entries regardless of count."""
|
|
100
|
+
container = self._make_container(name="container3")
|
|
101
|
+
_make_journal_entries(container, 500000)
|
|
102
|
+
ct = ContentType.objects.get_for_model(Container)
|
|
103
|
+
|
|
104
|
+
pk = container.pk
|
|
105
|
+
t0 = time.monotonic()
|
|
106
|
+
container.delete()
|
|
107
|
+
elapsed = (time.monotonic() - t0) * 1000
|
|
108
|
+
print(f"Deleted container (500000 journal entries) in {elapsed:.1f}ms")
|
|
109
|
+
|
|
110
|
+
self.assertFalse(Container.objects.filter(pk=pk).exists())
|
|
111
|
+
self.assertEqual(
|
|
112
|
+
JournalEntry.objects.filter(
|
|
113
|
+
assigned_object_type=ct, assigned_object_id=pk
|
|
114
|
+
).count(),
|
|
115
|
+
0,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
def test_delete_does_not_remove_journal_entries_of_other_containers(self):
|
|
119
|
+
"""Deleting one container must not remove journal entries of another."""
|
|
120
|
+
container_a = self._make_container(name="container4a")
|
|
121
|
+
container_b = self._make_container(name="container4b")
|
|
122
|
+
_make_journal_entries(container_a, 3)
|
|
123
|
+
_make_journal_entries(container_b, 3)
|
|
124
|
+
ct = ContentType.objects.get_for_model(Container)
|
|
125
|
+
|
|
126
|
+
t0 = time.monotonic()
|
|
127
|
+
container_a.delete()
|
|
128
|
+
print(
|
|
129
|
+
f"Deleted container (3 journal entries) in {(time.monotonic() - t0) * 1000:.1f}ms"
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
self.assertEqual(
|
|
133
|
+
JournalEntry.objects.filter(
|
|
134
|
+
assigned_object_type=ct, assigned_object_id=container_b.pk
|
|
135
|
+
).count(),
|
|
136
|
+
3,
|
|
137
|
+
)
|
|
@@ -67,8 +67,12 @@ class ContainerViewsTestCase(
|
|
|
67
67
|
"image": image1.pk,
|
|
68
68
|
"restart_policy": "unless-stopped",
|
|
69
69
|
"cap_add": ["NET_ADMIN"],
|
|
70
|
+
"cap_drop": ["FSETID", "MKNOD"],
|
|
71
|
+
"pid_mode": "host",
|
|
72
|
+
"extra_hosts": "test1:192.168.1.2,test2:192.168.1.3",
|
|
73
|
+
"secOpt": "apparmor:unconfined",
|
|
70
74
|
"log_driver": "syslog",
|
|
71
|
-
"cmd": "ls,-al"
|
|
75
|
+
"cmd": "ls,-al",
|
|
72
76
|
}
|
|
73
77
|
|
|
74
78
|
cls.csv_data = (
|
{netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin/views/container.py
RENAMED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
"""Container views definitions"""
|
|
2
2
|
|
|
3
|
+
from collections import defaultdict
|
|
4
|
+
from django.db import router
|
|
5
|
+
from django.db.models.deletion import Collector
|
|
6
|
+
from extras.models import JournalEntry
|
|
3
7
|
from utilities.query import count_related
|
|
4
8
|
from utilities.views import ViewTab, register_model_view
|
|
5
9
|
from netbox.views import generic
|
|
@@ -125,11 +129,66 @@ class ContainerBulkDeleteView(generic.BulkDeleteView):
|
|
|
125
129
|
table = tables.ContainerTable
|
|
126
130
|
|
|
127
131
|
|
|
132
|
+
class _JournalEntryCount:
|
|
133
|
+
"""Proxy passed to the deletion template in place of a full JournalEntry list.
|
|
134
|
+
|
|
135
|
+
The template calls len() for the accordion header count, then iterates to
|
|
136
|
+
render individual rows. This object answers len() with a single COUNT query
|
|
137
|
+
and yields nothing on iteration, avoiding fetching hundreds of thousands of
|
|
138
|
+
rows just to display a number."""
|
|
139
|
+
|
|
140
|
+
def __init__(self, queryset):
|
|
141
|
+
self._queryset = queryset
|
|
142
|
+
self._count = None
|
|
143
|
+
|
|
144
|
+
def __len__(self):
|
|
145
|
+
if self._count is None:
|
|
146
|
+
self._count = self._queryset.count()
|
|
147
|
+
return self._count
|
|
148
|
+
|
|
149
|
+
def __iter__(self):
|
|
150
|
+
return iter([])
|
|
151
|
+
|
|
152
|
+
def __bool__(self):
|
|
153
|
+
return len(self) > 0
|
|
154
|
+
|
|
155
|
+
|
|
128
156
|
class ContainerDeleteView(generic.ObjectDeleteView):
|
|
129
157
|
"""Container delete view definition"""
|
|
130
158
|
|
|
131
159
|
default_return_url = "plugins:netbox_docker_plugin:container_list"
|
|
132
|
-
queryset = Container.objects.
|
|
160
|
+
queryset = Container.objects.select_related("host", "image")
|
|
161
|
+
|
|
162
|
+
def _get_dependent_objects(self, obj):
|
|
163
|
+
class SkipJournalCollector(Collector):
|
|
164
|
+
"""Collector that skips JournalEntry to avoid a slow full scan."""
|
|
165
|
+
|
|
166
|
+
def collect(self, objs, **kwargs): # pylint: disable=arguments-differ
|
|
167
|
+
if getattr(objs, "model", None) is JournalEntry:
|
|
168
|
+
return
|
|
169
|
+
super().collect(objs, **kwargs)
|
|
170
|
+
|
|
171
|
+
using = router.db_for_write(obj._meta.model)
|
|
172
|
+
collector = SkipJournalCollector(using=using)
|
|
173
|
+
collector.collect([obj])
|
|
174
|
+
|
|
175
|
+
dependent_objects = defaultdict(list)
|
|
176
|
+
for model, instances in collector.instances_with_model():
|
|
177
|
+
if model._meta.auto_created:
|
|
178
|
+
continue
|
|
179
|
+
if instances == obj:
|
|
180
|
+
continue
|
|
181
|
+
dependent_objects[model].append(instances)
|
|
182
|
+
|
|
183
|
+
journal_qs = JournalEntry.objects.filter(
|
|
184
|
+
assigned_object_type__app_label="netbox_docker_plugin",
|
|
185
|
+
assigned_object_type__model="container",
|
|
186
|
+
assigned_object_id=obj.pk,
|
|
187
|
+
)
|
|
188
|
+
if journal_qs.exists():
|
|
189
|
+
dependent_objects[JournalEntry] = _JournalEntryCount(journal_qs)
|
|
190
|
+
|
|
191
|
+
return dict(dependent_objects)
|
|
133
192
|
|
|
134
193
|
|
|
135
194
|
class ContainerOperationView(generic.ObjectEditView):
|
{netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1/netbox_docker_plugin.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: netbox-docker-plugin
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.1.1
|
|
4
4
|
Summary: Manage Docker with Netbox & style.
|
|
5
5
|
Author-email: Vincent Simonin <vincent@saashup.com>, David Delassus <david.jose.delassus@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/SaaShup/netbox-docker-plugin
|
|
@@ -10,6 +10,10 @@ Classifier: Programming Language :: Python :: 3
|
|
|
10
10
|
Requires-Python: >=3.12
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
12
|
License-File: LICENSE
|
|
13
|
+
Provides-Extra: dev
|
|
14
|
+
Requires-Dist: requests-mock; extra == "dev"
|
|
15
|
+
Requires-Dist: coverage; extra == "dev"
|
|
16
|
+
Requires-Dist: pylint; extra == "dev"
|
|
13
17
|
Dynamic: license-file
|
|
14
18
|
|
|
15
19
|
# Netbox Docker Plugin
|
{netbox_docker_plugin-5.0.1 → netbox_docker_plugin-5.1.1}/netbox_docker_plugin.egg-info/SOURCES.txt
RENAMED
|
@@ -11,6 +11,7 @@ netbox_docker_plugin/urls.py
|
|
|
11
11
|
netbox_docker_plugin.egg-info/PKG-INFO
|
|
12
12
|
netbox_docker_plugin.egg-info/SOURCES.txt
|
|
13
13
|
netbox_docker_plugin.egg-info/dependency_links.txt
|
|
14
|
+
netbox_docker_plugin.egg-info/requires.txt
|
|
14
15
|
netbox_docker_plugin.egg-info/top_level.txt
|
|
15
16
|
netbox_docker_plugin/api/__init__.py
|
|
16
17
|
netbox_docker_plugin/api/renderers.py
|
|
@@ -75,6 +76,7 @@ netbox_docker_plugin/migrations/1039_alter_port_public_port.py
|
|
|
75
76
|
netbox_docker_plugin/migrations/1040_alter_container_log_driver.py
|
|
76
77
|
netbox_docker_plugin/migrations/1041_sysctl.py
|
|
77
78
|
netbox_docker_plugin/migrations/1042_registry_username_max_length.py
|
|
79
|
+
netbox_docker_plugin/migrations/1043_container_cap_drop_container_extra_hosts_and_more.py
|
|
78
80
|
netbox_docker_plugin/migrations/__init__.py
|
|
79
81
|
netbox_docker_plugin/models/__init__.py
|
|
80
82
|
netbox_docker_plugin/models/container.py
|
|
@@ -102,6 +104,7 @@ netbox_docker_plugin/tests/container/__init__.py
|
|
|
102
104
|
netbox_docker_plugin/tests/container/test_container_actions.py
|
|
103
105
|
netbox_docker_plugin/tests/container/test_container_api.py
|
|
104
106
|
netbox_docker_plugin/tests/container/test_container_api_exec.py
|
|
107
|
+
netbox_docker_plugin/tests/container/test_container_delete.py
|
|
105
108
|
netbox_docker_plugin/tests/container/test_container_operation_view.py
|
|
106
109
|
netbox_docker_plugin/tests/container/test_container_validation.py
|
|
107
110
|
netbox_docker_plugin/tests/container/test_container_views.py
|