netbox-docker-plugin 2.6.0__tar.gz → 2.8.0__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.
Files changed (128) hide show
  1. {netbox_docker_plugin-2.6.0/netbox_docker_plugin.egg-info → netbox_docker_plugin-2.8.0}/PKG-INFO +1 -1
  2. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/__init__.py +1 -1
  3. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/api/serializers.py +34 -0
  4. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/api/views.py +1 -0
  5. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/filtersets.py +17 -0
  6. netbox_docker_plugin-2.8.0/netbox_docker_plugin/forms/device.py +45 -0
  7. netbox_docker_plugin-2.8.0/netbox_docker_plugin/migrations/0032_device_and_more.py +66 -0
  8. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/models/container.py +44 -0
  9. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/signals.py +1 -0
  10. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/tables.py +30 -0
  11. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/templates/netbox_docker_plugin/container-layout.html +14 -0
  12. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/templates/netbox_docker_plugin/container.html +20 -0
  13. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/tests/container/test_container_actions.py +34 -10
  14. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/tests/container/test_container_api.py +4 -0
  15. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/urls.py +22 -0
  16. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/views/container.py +3 -0
  17. netbox_docker_plugin-2.8.0/netbox_docker_plugin/views/device.py +28 -0
  18. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0/netbox_docker_plugin.egg-info}/PKG-INFO +1 -1
  19. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin.egg-info/SOURCES.txt +3 -0
  20. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/pyproject.toml +1 -1
  21. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/LICENSE +0 -0
  22. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/MANIFEST.in +0 -0
  23. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/README.md +0 -0
  24. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/api/__init__.py +0 -0
  25. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/api/renderers.py +0 -0
  26. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/api/urls.py +0 -0
  27. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/forms/__init__.py +0 -0
  28. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/forms/bind.py +0 -0
  29. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/forms/container.py +0 -0
  30. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/forms/env.py +0 -0
  31. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/forms/host.py +0 -0
  32. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/forms/image.py +0 -0
  33. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/forms/label.py +0 -0
  34. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/forms/mount.py +0 -0
  35. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/forms/network.py +0 -0
  36. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/forms/network_setting.py +0 -0
  37. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/forms/port.py +0 -0
  38. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/forms/registry.py +0 -0
  39. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/forms/volume.py +0 -0
  40. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0001_initial.py +0 -0
  41. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0002_image.py +0 -0
  42. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0003_image_size.py +0 -0
  43. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0004_volume.py +0 -0
  44. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0005_network.py +0 -0
  45. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0006_container_port_mount_label_env_and_more.py +0 -0
  46. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0007_remove_container_netbox_docker_plugin_container_unique_name_host__and_more.py +0 -0
  47. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0008_alter_network_unique_together_network_networkid_and_more.py +0 -0
  48. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0009_remove_container_network_networksettings_and_more.py +0 -0
  49. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0010_container_containerid_and_more.py +0 -0
  50. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0011_host_token.py +0 -0
  51. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0012_host_state.py +0 -0
  52. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0013_host_netbox_url.py +0 -0
  53. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0014_container_operation.py +0 -0
  54. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0015_remove_mount_netbox_docker_plugin_mount_unique_volume_and_more.py +0 -0
  55. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0016_alter_env_value.py +0 -0
  56. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0017_network_state.py +0 -0
  57. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0018_alter_mount_volume_alter_networksetting_network.py +0 -0
  58. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0019_host_agent_version_host_docker_api_version.py +0 -0
  59. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0020_container_hostname.py +0 -0
  60. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0021_registry_and_more.py +0 -0
  61. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0022_bind_bind_netbox_docker_plugin_bind_unique_bind.py +0 -0
  62. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0023_delete_hosts.py +0 -0
  63. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0024_registry_host_alter_registry_name_and_more.py +0 -0
  64. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0025_alter_image_version.py +0 -0
  65. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0026_image_digest.py +0 -0
  66. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0027_container_restart_policy.py +0 -0
  67. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0028_mount_and_bind_read_only.py +0 -0
  68. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0029_alter_container_state.py +0 -0
  69. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0030_alter_container_containerid_alter_container_hostname_and_more.py +0 -0
  70. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/0031_container_cap_add.py +0 -0
  71. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/migrations/__init__.py +0 -0
  72. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/models/__init__.py +0 -0
  73. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/models/host.py +0 -0
  74. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/models/image.py +0 -0
  75. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/models/network.py +0 -0
  76. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/models/registry.py +0 -0
  77. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/models/volume.py +0 -0
  78. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/navigation.py +0 -0
  79. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/templates/netbox_docker_plugin/container-exec.html +0 -0
  80. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/templates/netbox_docker_plugin/container-logs.html +0 -0
  81. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/templates/netbox_docker_plugin/host-graph.html +0 -0
  82. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/templates/netbox_docker_plugin/host.html +0 -0
  83. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/templates/netbox_docker_plugin/image.html +0 -0
  84. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/templates/netbox_docker_plugin/network.html +0 -0
  85. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/templates/netbox_docker_plugin/registry.html +0 -0
  86. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/templates/netbox_docker_plugin/volume.html +0 -0
  87. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/templatetags/__init__.py +0 -0
  88. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/templatetags/host.py +0 -0
  89. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/tests/__init__.py +0 -0
  90. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/tests/base.py +0 -0
  91. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/tests/container/__init__.py +0 -0
  92. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/tests/container/test_container_api_exec.py +0 -0
  93. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/tests/container/test_container_operation_view.py +0 -0
  94. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/tests/container/test_container_validation.py +0 -0
  95. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/tests/container/test_container_views.py +0 -0
  96. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/tests/host/__init__.py +0 -0
  97. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/tests/host/test_host_api.py +0 -0
  98. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/tests/host/test_host_views.py +0 -0
  99. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/tests/host/test_replace_password.py +0 -0
  100. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/tests/image/__init__.py +0 -0
  101. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/tests/image/test_image_api.py +0 -0
  102. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/tests/image/test_image_views.py +0 -0
  103. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/tests/network/__init__.py +0 -0
  104. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/tests/network/test_network_api.py +0 -0
  105. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/tests/network/test_network_views.py +0 -0
  106. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/tests/registry/__init__.py +0 -0
  107. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/tests/registry/test_registry_api.py +0 -0
  108. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/tests/registry/test_registry_views.py +0 -0
  109. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/tests/test_init.py +0 -0
  110. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/tests/volume/__init__.py +0 -0
  111. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/tests/volume/test_volume_api.py +0 -0
  112. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/tests/volume/test_volume_views.py +0 -0
  113. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/utilities/__init__.py +0 -0
  114. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/views/__init__.py +0 -0
  115. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/views/bind.py +0 -0
  116. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/views/env.py +0 -0
  117. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/views/host.py +0 -0
  118. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/views/image.py +0 -0
  119. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/views/label.py +0 -0
  120. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/views/mount.py +0 -0
  121. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/views/network.py +0 -0
  122. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/views/network_setting.py +0 -0
  123. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/views/port.py +0 -0
  124. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/views/registry.py +0 -0
  125. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin/views/volume.py +0 -0
  126. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin.egg-info/dependency_links.txt +0 -0
  127. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/netbox_docker_plugin.egg-info/top_level.txt +0 -0
  128. {netbox_docker_plugin-2.6.0 → netbox_docker_plugin-2.8.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: netbox-docker-plugin
3
- Version: 2.6.0
3
+ Version: 2.8.0
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,7 +10,7 @@ class NetBoxDockerConfig(PluginConfig):
10
10
  name = "netbox_docker_plugin"
11
11
  verbose_name = " NetBox Docker Plugin"
12
12
  description = "Manage Docker"
13
- version = "2.6.0"
13
+ version = "2.8.0"
14
14
  base_url = "docker"
15
15
  min_version = "4.0.0"
16
16
  author= "Vincent Simonin <vincent@saashup.com>, David Delassus <david.jose.delassus@gmail.com>"
@@ -18,6 +18,7 @@ from ..models.container import (
18
18
  Mount,
19
19
  Bind,
20
20
  NetworkSetting,
21
+ Device,
21
22
  )
22
23
  from ..models.registry import Registry
23
24
 
@@ -375,6 +376,19 @@ class NetworkSettingSerializer(serializers.ModelSerializer):
375
376
  fields = ("network",)
376
377
 
377
378
 
379
+ class DeviceSerializer(serializers.ModelSerializer):
380
+ """Container Device Serializer class"""
381
+
382
+ class Meta:
383
+ """Container Device Serializer Meta class"""
384
+
385
+ model = Device
386
+ fields = (
387
+ "host_path",
388
+ "container_path",
389
+ )
390
+
391
+
378
392
  class ContainerSerializer(NetBoxModelSerializer):
379
393
  """Container Serializer class"""
380
394
 
@@ -389,6 +403,7 @@ class ContainerSerializer(NetBoxModelSerializer):
389
403
  mounts = MountSerializer(many=True, required=False)
390
404
  binds = BindSerializer(many=True, required=False)
391
405
  network_settings = NetworkSettingSerializer(many=True, required=False)
406
+ devices = DeviceSerializer(many=True, required=False)
392
407
 
393
408
  class Meta:
394
409
  """Container Serializer Meta class"""
@@ -414,6 +429,7 @@ class ContainerSerializer(NetBoxModelSerializer):
414
429
  "mounts",
415
430
  "binds",
416
431
  "network_settings",
432
+ "devices",
417
433
  "custom_fields",
418
434
  "created",
419
435
  "last_updated",
@@ -429,11 +445,13 @@ class ContainerSerializer(NetBoxModelSerializer):
429
445
  attrs.pop("mounts", None)
430
446
  attrs.pop("binds", None)
431
447
  attrs.pop("network_settings", None)
448
+ attrs.pop("devices", None)
432
449
 
433
450
  super().validate(attrs)
434
451
 
435
452
  return data
436
453
 
454
+ # pylint: disable=R0912
437
455
  def create(self, validated_data):
438
456
  ports_data = validated_data.pop("ports", None)
439
457
  env_data = validated_data.pop("env", None)
@@ -441,6 +459,7 @@ class ContainerSerializer(NetBoxModelSerializer):
441
459
  mounts_data = validated_data.pop("mounts", None)
442
460
  binds_data = validated_data.pop("binds", None)
443
461
  network_settings_data = validated_data.pop("network_settings", None)
462
+ devices_data = validated_data.pop("devices", None)
444
463
 
445
464
  container = super().create(validated_data)
446
465
 
@@ -474,8 +493,15 @@ class ContainerSerializer(NetBoxModelSerializer):
474
493
  obj.full_clean()
475
494
  obj.save()
476
495
 
496
+ if devices_data is not None:
497
+ for device in devices_data:
498
+ obj = Device(container=container, **device)
499
+ obj.full_clean()
500
+ obj.save()
501
+
477
502
  return container
478
503
 
504
+ # pylint: disable=R0912
479
505
  def update(self, instance, validated_data):
480
506
  ports_data = validated_data.pop("ports", None)
481
507
  env_data = validated_data.pop("env", None)
@@ -483,6 +509,7 @@ class ContainerSerializer(NetBoxModelSerializer):
483
509
  mounts_data = validated_data.pop("mounts", None)
484
510
  binds_data = validated_data.pop("binds", None)
485
511
  network_settings_data = validated_data.pop("network_settings", None)
512
+ devices_data = validated_data.pop("devices", None)
486
513
 
487
514
  container = super().update(instance, validated_data)
488
515
 
@@ -522,6 +549,13 @@ class ContainerSerializer(NetBoxModelSerializer):
522
549
  obj.full_clean()
523
550
  obj.save()
524
551
 
552
+ if devices_data is not None:
553
+ Device.objects.filter(container=container).delete()
554
+ for device in devices_data:
555
+ obj = Device(container=container, **device)
556
+ obj.full_clean()
557
+ obj.save()
558
+
525
559
  return container
526
560
 
527
561
 
@@ -136,6 +136,7 @@ class ContainerViewSet(NetBoxModelViewSet):
136
136
  """Container view set class"""
137
137
 
138
138
  queryset = Container.objects.prefetch_related(
139
+ "devices",
139
140
  "network_settings",
140
141
  "mounts",
141
142
  "binds",
@@ -15,6 +15,7 @@ from .models.container import (
15
15
  Mount,
16
16
  Bind,
17
17
  NetworkSetting,
18
+ Device,
18
19
  )
19
20
  from .models.registry import Registry
20
21
 
@@ -288,3 +289,19 @@ class NetworkSettingFilterSet(BaseFilterSet):
288
289
 
289
290
  model = NetworkSetting
290
291
  fields = ("id",)
292
+
293
+
294
+ class DeviceFilterSet(BaseFilterSet):
295
+ """Device filterset definition class"""
296
+
297
+ container_id = ModelMultipleChoiceFilter(
298
+ field_name="container_id",
299
+ queryset=Container.objects.all(),
300
+ label="Container (ID)",
301
+ )
302
+
303
+ class Meta:
304
+ """Device filterset definition meta class"""
305
+
306
+ model = Device
307
+ fields = ("id",)
@@ -0,0 +1,45 @@
1
+ """Device Form definition"""
2
+
3
+ from django import forms
4
+ from utilities.forms.fields import (
5
+ DynamicModelMultipleChoiceField,
6
+ DynamicModelChoiceField,
7
+ )
8
+ from netbox.forms import (
9
+ NetBoxModelFilterSetForm,
10
+ )
11
+ from ..models.container import Device, Container
12
+
13
+
14
+ class DeviceForm(forms.ModelForm):
15
+ """Device form definition class"""
16
+
17
+ container = DynamicModelChoiceField(
18
+ label="Container", queryset=Container.objects.all(), required=True
19
+ )
20
+
21
+ class Meta:
22
+ """Device form definition Meta class"""
23
+
24
+ model = Device
25
+ fields = (
26
+ "container",
27
+ "host_path",
28
+ "container_path",
29
+ )
30
+ labels = {
31
+ "container": "Container",
32
+ "host_path": "Path to the device on host",
33
+ "container_path": "Path to the device in container",
34
+ }
35
+
36
+
37
+ class DeviceFilterForm(NetBoxModelFilterSetForm):
38
+ """Device filter form definition class"""
39
+
40
+ model = Device
41
+ container_id = DynamicModelMultipleChoiceField(
42
+ queryset=Container.objects.all(),
43
+ required=False,
44
+ label="Container",
45
+ )
@@ -0,0 +1,66 @@
1
+ # pylint: disable=C0103
2
+ """Migration file"""
3
+
4
+ import django.core.validators
5
+ import django.db.models.deletion
6
+ from django.db import migrations, models
7
+
8
+
9
+ class Migration(migrations.Migration):
10
+ """Migration file"""
11
+
12
+ dependencies = [
13
+ ("netbox_docker_plugin", "0031_container_cap_add"),
14
+ ]
15
+
16
+ operations = [
17
+ migrations.CreateModel(
18
+ name="Device",
19
+ fields=[
20
+ (
21
+ "id",
22
+ models.BigAutoField(
23
+ auto_created=True, primary_key=True, serialize=False
24
+ ),
25
+ ),
26
+ (
27
+ "host_path",
28
+ models.CharField(
29
+ max_length=1024,
30
+ validators=[
31
+ django.core.validators.MinLengthValidator(limit_value=1),
32
+ django.core.validators.MaxLengthValidator(limit_value=1024),
33
+ ],
34
+ ),
35
+ ),
36
+ (
37
+ "container_path",
38
+ models.CharField(
39
+ max_length=1024,
40
+ validators=[
41
+ django.core.validators.MinLengthValidator(limit_value=1),
42
+ django.core.validators.MaxLengthValidator(limit_value=1024),
43
+ ],
44
+ ),
45
+ ),
46
+ (
47
+ "container",
48
+ models.ForeignKey(
49
+ on_delete=django.db.models.deletion.CASCADE,
50
+ related_name="devices",
51
+ to="netbox_docker_plugin.container",
52
+ ),
53
+ ),
54
+ ],
55
+ options={
56
+ "ordering": ("container", "container_path", "host_path"),
57
+ },
58
+ ),
59
+ migrations.AddConstraint(
60
+ model_name="device",
61
+ constraint=models.UniqueConstraint(
62
+ fields=("container", "container_path", "host_path"),
63
+ name="netbox_docker_plugin_device_unique_device",
64
+ ),
65
+ ),
66
+ ]
@@ -53,6 +53,7 @@ class ContainerOperationChoices(ChoiceSet):
53
53
  ("restart", "Restart", "blue"),
54
54
  ("stop", "Stop", "blue"),
55
55
  ("recreate", "Recreate", "blue"),
56
+ ("kill", "Kill", "red"),
56
57
  ("none", "None", "white"),
57
58
  ]
58
59
 
@@ -188,6 +189,11 @@ class Container(NetBoxModel):
188
189
  "dead",
189
190
  ]
190
191
 
192
+ @property
193
+ def can_kill(self) -> bool:
194
+ """Check if the container can be killed"""
195
+ return self.state in ["created", "restarting", "running", "exited", "dead"]
196
+
191
197
  class Meta:
192
198
  """Image Model Meta Class"""
193
199
 
@@ -461,3 +467,41 @@ class NetworkSetting(models.Model):
461
467
  + f"{self.container.host}."
462
468
  }
463
469
  )
470
+
471
+
472
+ class Device(models.Model):
473
+ """Device definition class"""
474
+
475
+ objects = RestrictedQuerySet.as_manager()
476
+
477
+ container = models.ForeignKey(
478
+ Container, on_delete=models.CASCADE, related_name="devices"
479
+ )
480
+ host_path = models.CharField(
481
+ max_length=1024,
482
+ validators=[
483
+ MinLengthValidator(limit_value=1),
484
+ MaxLengthValidator(limit_value=1024),
485
+ ],
486
+ )
487
+ container_path = models.CharField(
488
+ max_length=1024,
489
+ validators=[
490
+ MinLengthValidator(limit_value=1),
491
+ MaxLengthValidator(limit_value=1024),
492
+ ],
493
+ )
494
+
495
+ class Meta:
496
+ """Device Model Meta Class"""
497
+
498
+ ordering = ("container", "container_path", "host_path")
499
+ constraints = (
500
+ models.UniqueConstraint(
501
+ fields=["container", "container_path", "host_path"],
502
+ name="%(app_label)s_%(class)s_unique_device",
503
+ ),
504
+ )
505
+
506
+ def __str__(self):
507
+ return f"{self.host_path}:{self.container_path}"
@@ -42,6 +42,7 @@ def restrict_container_actions(instance, **_kwargs):
42
42
  instance.operation == "restart" and not instance.can_restart,
43
43
  instance.operation == "stop" and not instance.can_stop,
44
44
  instance.operation == "recreate" and not instance.can_recreate,
45
+ instance.operation == "kill" and not instance.can_kill,
45
46
  ]
46
47
  ):
47
48
  raise AbortRequest(
@@ -14,6 +14,7 @@ from .models.container import (
14
14
  Mount,
15
15
  Bind,
16
16
  NetworkSetting,
17
+ Device,
17
18
  )
18
19
  from .models.registry import Registry
19
20
  from .templatetags.host import remove_password
@@ -239,6 +240,11 @@ class ContainerTable(NetBoxTable):
239
240
  url_params={"container_id": "pk"},
240
241
  verbose_name="Labels count",
241
242
  )
243
+ device_count = columns.LinkedCountColumn(
244
+ viewname="plugins:netbox_docker_plugin:device_list",
245
+ url_params={"container_id": "pk"},
246
+ verbose_name="Devices count",
247
+ )
242
248
  tags = columns.TagColumn()
243
249
 
244
250
  class Meta(NetBoxTable.Meta):
@@ -263,6 +269,7 @@ class ContainerTable(NetBoxTable):
263
269
  "networksetting_count",
264
270
  "env_count",
265
271
  "label_count",
272
+ "device_count",
266
273
  "tags",
267
274
  )
268
275
  default_columns = (
@@ -395,3 +402,26 @@ class NetworkSettingTable(NetBoxTable):
395
402
  "container",
396
403
  "network",
397
404
  )
405
+
406
+
407
+ class DeviceTable(NetBoxTable):
408
+ """Device Table definition class"""
409
+
410
+ container = tables.Column(linkify=True)
411
+
412
+ actions = columns.ActionsColumn(actions=("edit", "delete"))
413
+
414
+ class Meta(NetBoxTable.Meta):
415
+ """Device Table definition Meta class"""
416
+
417
+ model = Device
418
+ fields = (
419
+ "container",
420
+ "host_path",
421
+ "container_path",
422
+ )
423
+ default_columns = (
424
+ "container",
425
+ "host_path",
426
+ "container_path",
427
+ )
@@ -45,6 +45,20 @@
45
45
  </button>
46
46
  </form>
47
47
 
48
+ <form action="{% url 'plugins:netbox_docker_plugin:container_operation' pk=object.id operation='kill' %}" method="post">
49
+ {% csrf_token %}
50
+ <input type="hidden" name="operation" value="kill">
51
+ <button
52
+ type="submit"
53
+ class="btn btn-dark"
54
+ {% if not object.can_kill %}
55
+ disabled
56
+ {% endif %}
57
+ >
58
+ <i class="mdi mdi-skull"></i> Kill
59
+ </button>
60
+ </form>
61
+
48
62
  <form action="{% url 'plugins:netbox_docker_plugin:container_operation' pk=object.id operation='recreate' %}" method="post">
49
63
  {% csrf_token %}
50
64
  <input type="hidden" name="operation" value="recreate">
@@ -165,4 +165,24 @@
165
165
  </div>
166
166
  </div>
167
167
  </div>
168
+
169
+ <h2>Host capabilities</h2>
170
+ <div class="row mb-3">
171
+ <div class="col col-md-6">
172
+ <div class="card">
173
+ <h5 class="card-header">DEVICES</h5>
174
+ <div class="card-body htmx-container table-responsive"
175
+ hx-get="{% url 'plugins:netbox_docker_plugin:device_list' %}?container_id={{ object.pk }}"
176
+ hx-trigger="load"
177
+ ></div>
178
+ {% if perms.netbox_docker_plugin.add_device %}
179
+ <div class="card-footer text-end noprint">
180
+ <a href="{% url 'plugins:netbox_docker_plugin:device_add' %}?container={{ object.pk }}&return_url={{ object.get_absolute_url }}" class="btn btn-primary">
181
+ <i class="mdi mdi-plus-thick" aria-hidden="true"></i> New Device
182
+ </a>
183
+ </div>
184
+ {% endif %}
185
+ </div>
186
+ </div>
187
+ </div>
168
188
  {% endblock content %}
@@ -10,12 +10,12 @@ from netbox_docker_plugin.models.registry import Registry
10
10
 
11
11
 
12
12
  class ContainerActionTestCase(TestCase):
13
- """ Test the various scenarii of container actions """
13
+ """Test the various scenarii of container actions"""
14
14
 
15
15
  objects = {}
16
16
 
17
17
  def test_allowed_operations(self):
18
- """ Test that only specific operations are allowed according to a state """
18
+ """Test that only specific operations are allowed according to a state"""
19
19
 
20
20
  cases = [
21
21
  ("create", ["none"]),
@@ -23,7 +23,19 @@ class ContainerActionTestCase(TestCase):
23
23
  ("stop", ["running"]),
24
24
  ("restart", ["running"]),
25
25
  ("recreate", ["created", "exited", "dead", "running"]),
26
- ("noop", ["created", "restarting", "running", "paused", "exited", "dead", "none"]),
26
+ ("kill", ["created", "restarting", "running", "exited", "dead"]),
27
+ (
28
+ "noop",
29
+ [
30
+ "created",
31
+ "restarting",
32
+ "running",
33
+ "paused",
34
+ "exited",
35
+ "dead",
36
+ "none",
37
+ ],
38
+ ),
27
39
  ]
28
40
 
29
41
  for operation, states in cases:
@@ -48,14 +60,18 @@ class ContainerActionTestCase(TestCase):
48
60
  )
49
61
 
50
62
  def test_forbidden_operations(self):
51
- """ Test that forbidden operations raise an AbortRequest """
63
+ """Test that forbidden operations raise an AbortRequest"""
52
64
 
53
65
  cases = [
54
- ("create", ["created", "restarting", "running", "paused", "exited", "dead"]),
66
+ (
67
+ "create",
68
+ ["created", "restarting", "running", "paused", "exited", "dead"],
69
+ ),
55
70
  ("start", ["running", "restarting", "paused", "none"]),
56
71
  ("stop", ["created", "restarting", "paused", "exited", "dead", "none"]),
57
72
  ("restart", ["created", "restarting", "paused", "exited", "dead", "none"]),
58
73
  ("recreate", ["restarting", "paused", "none"]),
74
+ ("kill", ["paused", "none"]),
59
75
  ]
60
76
 
61
77
  for operation, states in cases:
@@ -79,7 +95,7 @@ class ContainerActionTestCase(TestCase):
79
95
  obj.save()
80
96
 
81
97
  def test_delete_non_running_container(self):
82
- """ Test that a non running container can be deleted """
98
+ """Test that a non running container can be deleted"""
83
99
 
84
100
  for state in ["created", "paused", "exited", "dead"]:
85
101
  with self.subTest(operation="delete", state=state):
@@ -98,7 +114,7 @@ class ContainerActionTestCase(TestCase):
98
114
  self.assertFalse(Container.objects.filter(name=name).exists())
99
115
 
100
116
  def test_delete_running_container(self):
101
- """ Test that a running container cannot be deleted """
117
+ """Test that a running container cannot be deleted"""
102
118
 
103
119
  for state in ["running", "restarting", "none"]:
104
120
  with self.subTest(operation="delete", state=state):
@@ -119,9 +135,17 @@ class ContainerActionTestCase(TestCase):
119
135
  obj.delete()
120
136
 
121
137
  def test_delete_container_on_deleted_host(self):
122
- """ Test that a container on a deleted host can be deleted """
123
-
124
- for state in ["created", "running", "restarted", "paused", "exited", "dead", "none"]:
138
+ """Test that a container on a deleted host can be deleted"""
139
+
140
+ for state in [
141
+ "created",
142
+ "running",
143
+ "restarted",
144
+ "paused",
145
+ "exited",
146
+ "dead",
147
+ "none",
148
+ ]:
125
149
  with self.subTest(operation="delete", state=state):
126
150
  with transaction.atomic():
127
151
  name = f"container-delete-{state}"
@@ -47,6 +47,7 @@ class ContainerApiTestCase(
47
47
  "mounts",
48
48
  "binds",
49
49
  "network_settings",
50
+ "devices",
50
51
  ]
51
52
 
52
53
  @classmethod
@@ -121,6 +122,9 @@ class ContainerApiTestCase(
121
122
  "network_settings": [
122
123
  {"network": network1.pk},
123
124
  ],
125
+ "devices": [
126
+ {"host_path": "/dev/sda", "container_path": "/dev/xvdc"},
127
+ ]
124
128
  },
125
129
  {
126
130
  "host": host2.pk,
@@ -21,6 +21,7 @@ from .views import (
21
21
  bind as bind_views,
22
22
  network_setting as network_setting_views,
23
23
  registry as registry_views,
24
+ device as device_views,
24
25
  )
25
26
 
26
27
  urlpatterns = (
@@ -405,4 +406,25 @@ urlpatterns = (
405
406
  name="registry_journal",
406
407
  kwargs={"model": Registry},
407
408
  ),
409
+ # Device
410
+ path(
411
+ "devices/",
412
+ device_views.DeviceListView.as_view(),
413
+ name="device_list",
414
+ ),
415
+ path(
416
+ "devices/add/",
417
+ device_views.DeviceEditView.as_view(),
418
+ name="device_add",
419
+ ),
420
+ path(
421
+ "devices/<int:pk>/edit/",
422
+ device_views.DeviceEditView.as_view(),
423
+ name="device_edit",
424
+ ),
425
+ path(
426
+ "devices/<int:pk>/delete/",
427
+ device_views.DeviceDeleteView.as_view(),
428
+ name="device_delete",
429
+ ),
408
430
  )
@@ -13,6 +13,7 @@ from ..models.container import (
13
13
  NetworkSetting,
14
14
  Env,
15
15
  Label,
16
+ Device,
16
17
  )
17
18
 
18
19
 
@@ -29,6 +30,7 @@ class ContainerView(generic.ObjectView):
29
30
  "binds",
30
31
  "ports",
31
32
  "network_settings",
33
+ "devices",
32
34
  )
33
35
 
34
36
 
@@ -74,6 +76,7 @@ class ContainerListView(generic.ObjectListView):
74
76
  networksetting_count=count_related(NetworkSetting, "container"),
75
77
  env_count=count_related(Env, "container"),
76
78
  label_count=count_related(Label, "container"),
79
+ device_count=count_related(Device, "container"),
77
80
  )
78
81
 
79
82
  table = tables.ContainerTable
@@ -0,0 +1,28 @@
1
+ """Container views definitions"""
2
+
3
+ from netbox.views import generic
4
+ from .. import tables, filtersets
5
+ from ..forms.device import DeviceForm, DeviceFilterForm
6
+ from ..models.container import Device
7
+
8
+
9
+ class DeviceListView(generic.ObjectListView):
10
+ """Device list view definition"""
11
+
12
+ queryset = Device.objects.prefetch_related("container")
13
+ table = tables.DeviceTable
14
+ filterset = filtersets.DeviceFilterSet
15
+ filterset_form = DeviceFilterForm
16
+
17
+
18
+ class DeviceEditView(generic.ObjectEditView):
19
+ """Device edition view definition"""
20
+
21
+ queryset = Device.objects.all()
22
+ form = DeviceForm
23
+
24
+
25
+ class DeviceDeleteView(generic.ObjectDeleteView):
26
+ """Device delete view definition"""
27
+
28
+ queryset = Device.objects.all()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: netbox-docker-plugin
3
- Version: 2.6.0
3
+ Version: 2.8.0
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
@@ -20,6 +20,7 @@ netbox_docker_plugin/api/views.py
20
20
  netbox_docker_plugin/forms/__init__.py
21
21
  netbox_docker_plugin/forms/bind.py
22
22
  netbox_docker_plugin/forms/container.py
23
+ netbox_docker_plugin/forms/device.py
23
24
  netbox_docker_plugin/forms/env.py
24
25
  netbox_docker_plugin/forms/host.py
25
26
  netbox_docker_plugin/forms/image.py
@@ -61,6 +62,7 @@ netbox_docker_plugin/migrations/0028_mount_and_bind_read_only.py
61
62
  netbox_docker_plugin/migrations/0029_alter_container_state.py
62
63
  netbox_docker_plugin/migrations/0030_alter_container_containerid_alter_container_hostname_and_more.py
63
64
  netbox_docker_plugin/migrations/0031_container_cap_add.py
65
+ netbox_docker_plugin/migrations/0032_device_and_more.py
64
66
  netbox_docker_plugin/migrations/__init__.py
65
67
  netbox_docker_plugin/models/__init__.py
66
68
  netbox_docker_plugin/models/container.py
@@ -111,6 +113,7 @@ netbox_docker_plugin/utilities/__init__.py
111
113
  netbox_docker_plugin/views/__init__.py
112
114
  netbox_docker_plugin/views/bind.py
113
115
  netbox_docker_plugin/views/container.py
116
+ netbox_docker_plugin/views/device.py
114
117
  netbox_docker_plugin/views/env.py
115
118
  netbox_docker_plugin/views/host.py
116
119
  netbox_docker_plugin/views/image.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "netbox-docker-plugin"
7
- version = "2.6.0"
7
+ version = "2.8.0"
8
8
  authors = [
9
9
  { name="Vincent Simonin", email="vincent@saashup.com" },
10
10
  { name="David Delassus", email="david.jose.delassus@gmail.com" }