model_forms.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. from django import forms
  2. from django.utils.translation import gettext_lazy as _
  3. from dcim.models import Device, Interface
  4. from ipam.models import IPAddress
  5. from netbox.forms import NetBoxModelForm
  6. from tenancy.forms import TenancyForm
  7. from utilities.forms.fields import CommentField, DynamicModelChoiceField, DynamicModelMultipleChoiceField
  8. from utilities.forms.utils import add_blank_choice
  9. from utilities.forms.widgets import HTMXSelect
  10. from virtualization.models import VirtualMachine, VMInterface
  11. from vpn.choices import *
  12. from vpn.models import *
  13. __all__ = (
  14. 'IKEPolicyForm',
  15. 'IKEProposalForm',
  16. 'IPSecPolicyForm',
  17. 'IPSecProfileForm',
  18. 'IPSecProposalForm',
  19. 'TunnelCreateForm',
  20. 'TunnelForm',
  21. 'TunnelTerminationForm',
  22. )
  23. class TunnelForm(TenancyForm, NetBoxModelForm):
  24. ipsec_profile = DynamicModelChoiceField(
  25. queryset=IPSecProfile.objects.all(),
  26. label=_('IPSec Profile'),
  27. required=False
  28. )
  29. comments = CommentField()
  30. fieldsets = (
  31. (_('Tunnel'), ('name', 'status', 'encapsulation', 'description', 'tunnel_id', 'tags')),
  32. (_('Security'), ('ipsec_profile',)),
  33. (_('Tenancy'), ('tenant_group', 'tenant')),
  34. )
  35. class Meta:
  36. model = Tunnel
  37. fields = [
  38. 'name', 'status', 'encapsulation', 'description', 'tunnel_id', 'ipsec_profile', 'tenant_group', 'tenant',
  39. 'comments', 'tags',
  40. ]
  41. class TunnelCreateForm(TunnelForm):
  42. # First termination
  43. termination1_role = forms.ChoiceField(
  44. choices=add_blank_choice(TunnelTerminationRoleChoices),
  45. required=False,
  46. label=_('Role')
  47. )
  48. termination1_type = forms.ChoiceField(
  49. choices=TunnelTerminationTypeChoices,
  50. required=False,
  51. widget=HTMXSelect(),
  52. label=_('Type')
  53. )
  54. termination1_parent = DynamicModelChoiceField(
  55. queryset=Device.objects.all(),
  56. required=False,
  57. selector=True,
  58. label=_('Device')
  59. )
  60. termination1_termination = DynamicModelChoiceField(
  61. queryset=Interface.objects.all(),
  62. required=False,
  63. label=_('Interface'),
  64. query_params={
  65. 'device_id': '$termination1_parent',
  66. }
  67. )
  68. termination1_outside_ip = DynamicModelChoiceField(
  69. queryset=IPAddress.objects.all(),
  70. label=_('Outside IP'),
  71. required=False,
  72. query_params={
  73. 'device_id': '$termination1_parent',
  74. }
  75. )
  76. # Second termination
  77. termination2_role = forms.ChoiceField(
  78. choices=add_blank_choice(TunnelTerminationRoleChoices),
  79. required=False,
  80. label=_('Role')
  81. )
  82. termination2_type = forms.ChoiceField(
  83. choices=TunnelTerminationTypeChoices,
  84. required=False,
  85. widget=HTMXSelect(),
  86. label=_('Type')
  87. )
  88. termination2_parent = DynamicModelChoiceField(
  89. queryset=Device.objects.all(),
  90. required=False,
  91. selector=True,
  92. label=_('Device')
  93. )
  94. termination2_termination = DynamicModelChoiceField(
  95. queryset=Interface.objects.all(),
  96. required=False,
  97. label=_('Interface'),
  98. query_params={
  99. 'device_id': '$termination2_parent',
  100. }
  101. )
  102. termination2_outside_ip = DynamicModelChoiceField(
  103. queryset=IPAddress.objects.all(),
  104. required=False,
  105. label=_('Outside IP'),
  106. query_params={
  107. 'device_id': '$termination2_parent',
  108. }
  109. )
  110. fieldsets = (
  111. (_('Tunnel'), ('name', 'status', 'encapsulation', 'description', 'tunnel_id', 'tags')),
  112. (_('Security'), ('ipsec_profile',)),
  113. (_('Tenancy'), ('tenant_group', 'tenant')),
  114. (_('First Termination'), (
  115. 'termination1_role', 'termination1_type', 'termination1_parent', 'termination1_termination',
  116. 'termination1_outside_ip',
  117. )),
  118. (_('Second Termination'), (
  119. 'termination2_role', 'termination2_type', 'termination2_parent', 'termination2_termination',
  120. 'termination2_outside_ip',
  121. )),
  122. )
  123. def __init__(self, *args, initial=None, **kwargs):
  124. super().__init__(*args, initial=initial, **kwargs)
  125. if initial and initial.get('termination1_type') == TunnelTerminationTypeChoices.TYPE_VIRUTALMACHINE:
  126. self.fields['termination1_parent'].label = _('Virtual Machine')
  127. self.fields['termination1_parent'].queryset = VirtualMachine.objects.all()
  128. self.fields['termination1_termination'].queryset = VMInterface.objects.all()
  129. self.fields['termination1_termination'].widget.add_query_params({
  130. 'virtual_machine_id': '$termination1_parent',
  131. })
  132. self.fields['termination1_outside_ip'].widget.add_query_params({
  133. 'virtual_machine_id': '$termination1_parent',
  134. })
  135. if initial and initial.get('termination2_type') == TunnelTerminationTypeChoices.TYPE_VIRUTALMACHINE:
  136. self.fields['termination2_parent'].label = _('Virtual Machine')
  137. self.fields['termination2_parent'].queryset = VirtualMachine.objects.all()
  138. self.fields['termination2_termination'].queryset = VMInterface.objects.all()
  139. self.fields['termination2_termination'].widget.add_query_params({
  140. 'virtual_machine_id': '$termination2_parent',
  141. })
  142. self.fields['termination2_outside_ip'].widget.add_query_params({
  143. 'virtual_machine_id': '$termination2_parent',
  144. })
  145. def clean(self):
  146. super().clean()
  147. # Validate attributes for each termination (if any)
  148. for term in ('termination1', 'termination2'):
  149. required_parameters = (
  150. f'{term}_role', f'{term}_parent', f'{term}_termination',
  151. )
  152. parameters = (
  153. *required_parameters,
  154. f'{term}_outside_ip',
  155. )
  156. if any([self.cleaned_data[param] for param in parameters]):
  157. for param in required_parameters:
  158. if not self.cleaned_data[param]:
  159. raise forms.ValidationError({
  160. param: _("This parameter is required when defining a termination.")
  161. })
  162. def save(self, *args, **kwargs):
  163. instance = super().save(*args, **kwargs)
  164. # Create first termination
  165. if self.cleaned_data['termination1_termination']:
  166. TunnelTermination.objects.create(
  167. tunnel=instance,
  168. role=self.cleaned_data['termination1_role'],
  169. termination=self.cleaned_data['termination1_termination'],
  170. outside_ip=self.cleaned_data['termination1_outside_ip'],
  171. )
  172. # Create second termination, if defined
  173. if self.cleaned_data['termination2_termination']:
  174. TunnelTermination.objects.create(
  175. tunnel=instance,
  176. role=self.cleaned_data['termination2_role'],
  177. termination=self.cleaned_data['termination2_termination'],
  178. outside_ip=self.cleaned_data.get('termination1_outside_ip'),
  179. )
  180. return instance
  181. class TunnelTerminationForm(NetBoxModelForm):
  182. tunnel = DynamicModelChoiceField(
  183. queryset=Tunnel.objects.all()
  184. )
  185. type = forms.ChoiceField(
  186. choices=TunnelTerminationTypeChoices,
  187. widget=HTMXSelect(),
  188. label=_('Type')
  189. )
  190. parent = DynamicModelChoiceField(
  191. queryset=Device.objects.all(),
  192. selector=True,
  193. label=_('Device')
  194. )
  195. termination = DynamicModelChoiceField(
  196. queryset=Interface.objects.all(),
  197. label=_('Interface'),
  198. query_params={
  199. 'device_id': '$parent',
  200. }
  201. )
  202. outside_ip = DynamicModelChoiceField(
  203. queryset=IPAddress.objects.all(),
  204. label=_('Outside IP'),
  205. required=False,
  206. query_params={
  207. 'device_id': '$parent',
  208. }
  209. )
  210. fieldsets = (
  211. (None, ('tunnel', 'role', 'type', 'parent', 'termination', 'outside_ip', 'tags')),
  212. )
  213. class Meta:
  214. model = TunnelTermination
  215. fields = [
  216. 'tunnel', 'role', 'termination', 'outside_ip', 'tags',
  217. ]
  218. def __init__(self, *args, initial=None, **kwargs):
  219. super().__init__(*args, initial=initial, **kwargs)
  220. if initial and initial.get('type') == TunnelTerminationTypeChoices.TYPE_VIRUTALMACHINE:
  221. self.fields['parent'].label = _('Virtual Machine')
  222. self.fields['parent'].queryset = VirtualMachine.objects.all()
  223. self.fields['termination'].queryset = VMInterface.objects.all()
  224. self.fields['termination'].widget.add_query_params({
  225. 'virtual_machine_id': '$parent',
  226. })
  227. self.fields['outside_ip'].widget.add_query_params({
  228. 'virtual_machine_id': '$parent',
  229. })
  230. if self.instance.pk:
  231. self.fields['parent'].initial = self.instance.termination.parent_object
  232. self.fields['termination'].initial = self.instance.termination
  233. def clean(self):
  234. super().clean()
  235. # Set the terminated object
  236. self.instance.termination = self.cleaned_data.get('termination')
  237. class IKEProposalForm(NetBoxModelForm):
  238. fieldsets = (
  239. (_('Proposal'), ('name', 'description', 'tags')),
  240. (_('Parameters'), (
  241. 'authentication_method', 'encryption_algorithm', 'authentication_algorithm', 'group', 'sa_lifetime',
  242. )),
  243. )
  244. class Meta:
  245. model = IKEProposal
  246. fields = [
  247. 'name', 'description', 'authentication_method', 'encryption_algorithm', 'authentication_algorithm', 'group',
  248. 'sa_lifetime', 'tags',
  249. ]
  250. class IKEPolicyForm(NetBoxModelForm):
  251. proposals = DynamicModelMultipleChoiceField(
  252. queryset=IKEProposal.objects.all(),
  253. label=_('Proposals')
  254. )
  255. fieldsets = (
  256. (_('Policy'), ('name', 'description', 'tags')),
  257. (_('Parameters'), ('version', 'mode', 'proposals', 'preshared_key')),
  258. )
  259. class Meta:
  260. model = IKEPolicy
  261. fields = [
  262. 'name', 'description', 'version', 'mode', 'proposals', 'preshared_key', 'tags',
  263. ]
  264. class IPSecProposalForm(NetBoxModelForm):
  265. fieldsets = (
  266. (_('Proposal'), ('name', 'description', 'tags')),
  267. (_('Parameters'), (
  268. 'encryption_algorithm', 'authentication_algorithm', 'sa_lifetime_seconds', 'sa_lifetime_data',
  269. )),
  270. )
  271. class Meta:
  272. model = IPSecProposal
  273. fields = [
  274. 'name', 'description', 'encryption_algorithm', 'authentication_algorithm', 'sa_lifetime_seconds',
  275. 'sa_lifetime_data', 'tags',
  276. ]
  277. class IPSecPolicyForm(NetBoxModelForm):
  278. proposals = DynamicModelMultipleChoiceField(
  279. queryset=IPSecProposal.objects.all(),
  280. label=_('Proposals')
  281. )
  282. fieldsets = (
  283. (_('Policy'), ('name', 'description', 'tags')),
  284. (_('Parameters'), ('proposals', 'pfs_group')),
  285. )
  286. class Meta:
  287. model = IPSecPolicy
  288. fields = [
  289. 'name', 'description', 'proposals', 'pfs_group', 'tags',
  290. ]
  291. class IPSecProfileForm(NetBoxModelForm):
  292. ike_policy = DynamicModelChoiceField(
  293. queryset=IKEPolicy.objects.all(),
  294. label=_('IKE policy')
  295. )
  296. ipsec_policy = DynamicModelChoiceField(
  297. queryset=IPSecPolicy.objects.all(),
  298. label=_('IPSec policy')
  299. )
  300. comments = CommentField()
  301. fieldsets = (
  302. (_('Profile'), ('name', 'description', 'tags')),
  303. (_('Parameters'), ('mode', 'ike_policy', 'ipsec_policy')),
  304. )
  305. class Meta:
  306. model = IPSecProfile
  307. fields = [
  308. 'name', 'description', 'mode', 'ike_policy', 'ipsec_policy', 'description', 'comments', 'tags',
  309. ]