Skip to content

Commit 0fdf996

Browse files
committed
User-AS: support bind IP for user attachment point
Add collapsible form field for bind_ip in the user AS attachment point form. The model field backing this has already been there (host.bind_ip). Also, consider this optional bind_ip in the creation of the OpenVPN server config.
1 parent d4a5144 commit 0fdf996

File tree

4 files changed

+34
-10
lines changed

4 files changed

+34
-10
lines changed

scionlab/forms/user_as_form.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# limitations under the License.
1414
from crispy_forms.bootstrap import AppendedText
1515
from crispy_forms.helper import FormHelper
16-
from crispy_forms.layout import Layout, Field, Column, Row, Div
16+
from crispy_forms.layout import Layout, Field, HTML, Column, Row, Div
1717
from django import forms
1818
from django.forms import modelformset_factory
1919
from django.core.exceptions import ValidationError
@@ -46,8 +46,21 @@ def _crispy_helper(instance):
4646
),
4747
Div(
4848
Row(
49-
Column('public_ip', css_class='col-md-5'),
50-
Column('provide_vpn', css_class='col-md-5'),
49+
Column('public_ip', css_class='col-md-6'),
50+
Column('provide_vpn', css_class='col-md-4'),
51+
),
52+
Row(
53+
HTML("""<button type="button" class="btn btn-link bind-row-collapser collapsed"
54+
aria-expanded="false" aria-controls="bind-row">
55+
Show binding options for NAT
56+
<i class="fa fa-plus-circle"></i>
57+
<i class="fa fa-minus-circle"></i>
58+
</button>""")
59+
),
60+
Row(
61+
Column(AppendedText('bind_ip', '<span class="fa fa-external-link-square"/>'),
62+
css_class='col-md-6'),
63+
css_class="bind-row"
5164
),
5265
css_class="card-body", css_id="user-ap-card-body",
5366
),
@@ -104,6 +117,12 @@ class UserASForm(forms.Form):
104117
label="Public IP",
105118
help_text="Public IP Address to be used for connections to child ASes"
106119
)
120+
bind_ip = forms.GenericIPAddressField(
121+
required=False,
122+
label="Bind IP address",
123+
help_text="(Optional) Specify the local IP "
124+
"if your border router is behind a NAT/firewall etc.",
125+
)
107126
provide_vpn = forms.BooleanField(
108127
required=False,
109128
label="Provide VPN",
@@ -144,6 +163,7 @@ def __init__(self, data=None, *args, **kwargs):
144163
'label': self.instance.label,
145164
'installation_type': self.instance.installation_type,
146165
'public_ip': host.public_ip,
166+
'bind_ip': host.bind_ip,
147167
'become_user_ap': is_ap,
148168
'provide_vpn': has_vpn
149169
})
@@ -193,6 +213,7 @@ def save(self, commit=True):
193213
installation_type=self.cleaned_data['installation_type'],
194214
label=self.cleaned_data['label'],
195215
public_ip=self.cleaned_data['public_ip'],
216+
bind_ip=self.cleaned_data['bind_ip'],
196217
wants_user_ap=self.cleaned_data['become_user_ap'],
197218
wants_vpn=self.cleaned_data['provide_vpn'],
198219
)
@@ -203,6 +224,7 @@ def save(self, commit=True):
203224
installation_type=self.cleaned_data['installation_type'],
204225
label=self.cleaned_data['label'],
205226
public_ip=self.cleaned_data['public_ip'],
227+
bind_ip=self.cleaned_data['bind_ip'],
206228
wants_user_ap=self.cleaned_data['become_user_ap'],
207229
wants_vpn=self.cleaned_data['provide_vpn'],
208230
)

scionlab/models/user_as.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ def create(self,
5151
owner: User,
5252
installation_type: str,
5353
isd: int,
54-
public_ip: str = "",
54+
public_ip: str = None,
55+
bind_ip: str = None,
5556
wants_user_ap: bool = False,
5657
wants_vpn: bool = False,
5758
as_id: str = None,
@@ -62,6 +63,7 @@ def create(self,
6263
:param str installation_type:
6364
:param int isd:
6465
:param str public_ip: optional public IP address for the host of the AS
66+
:param str bind_ip: optional bind IP address for the host of the AS
6567
:param bool wants_user_ap: optional boolean if the User AS should be AP
6668
:param str wants_vpn: optional boolean if the User AP should provide a VPN
6769
:param str as_id: optional as_id, if None is given, the next free ID is chosen
@@ -90,7 +92,7 @@ def create(self,
9092

9193
user_as.generate_keys()
9294
user_as.generate_certs()
93-
user_as.init_default_services(public_ip=public_ip)
95+
user_as.init_default_services(public_ip=public_ip, bind_ip=bind_ip)
9496

9597
if wants_user_ap:
9698
host = user_as.hosts.first()
@@ -148,7 +150,7 @@ class Meta:
148150
def get_absolute_url(self):
149151
return urls.reverse('user_as_detail', kwargs={'pk': self.pk})
150152

151-
def update(self, label: str, installation_type: str, public_ip: str = "",
153+
def update(self, label: str, installation_type: str, public_ip: str = None, bind_ip: str = None,
152154
wants_user_ap: bool = False, wants_vpn: bool = False):
153155
"""
154156
Updates the `UserAS` fields and immediately saves
@@ -161,7 +163,7 @@ def update(self, label: str, installation_type: str, public_ip: str = "",
161163
self._unset_bind_ips_for_vagrant()
162164
self.installation_type = installation_type
163165
host = self.host
164-
host.update(public_ip=public_ip)
166+
host.update(public_ip=public_ip, bind_ip=bind_ip)
165167
if self.is_attachment_point():
166168
# the case has_vpn and not wants_vpn will be ignored here because it's not allowed
167169
ap = self.attachment_point_info

scionlab/openvpn_config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ def generate_vpn_server_config(vpn):
213213
server_vpn_subnet = vpn.vpn_subnet()
214214

215215
server_config = string.Template(server_config_tmpl).substitute(
216-
ServerPublicIP=vpn.server.public_ip,
216+
ServerPublicIP=vpn.server.bind_ip or vpn.server.public_ip,
217217
ServerPort=vpn.server_port,
218218
ServerVPNIP=vpn.server_vpn_ip,
219219
Netmask=server_vpn_subnet.netmask,

scionlab/templates/scionlab/partials/user_as_form_script.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
}
6666
$('.bind-row-collapser').each(function() {
6767
// Init collapser and bind-row
68-
let bind_row = $(this).closest('.attachment').find('.bind-row')
68+
let bind_row = $(this).closest('.card-body').find('.bind-row')
6969
bind_row.addClass('collapse')
7070
if (!should_collapse_bind_row(bind_row)) {
7171
bind_row.addClass('show')
@@ -74,7 +74,7 @@
7474
});
7575
$('.bind-row-collapser').click(function() {
7676
// Toggle collapse state for collapser and bind-row
77-
let bind_row = $(this).closest('.attachment').find('.bind-row')
77+
let bind_row = $(this).closest('.card-body').find('.bind-row')
7878
$(this).toggleClass('collapsed')
7979
bind_row.collapse('toggle')
8080
});

0 commit comments

Comments
 (0)