Skip to content

Commit

Permalink
User-AS: support bind IP for user attachment point
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
matzf committed Jul 10, 2023
1 parent d4a5144 commit 0fdf996
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 10 deletions.
28 changes: 25 additions & 3 deletions scionlab/forms/user_as_form.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# limitations under the License.
from crispy_forms.bootstrap import AppendedText
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Field, Column, Row, Div
from crispy_forms.layout import Layout, Field, HTML, Column, Row, Div
from django import forms
from django.forms import modelformset_factory
from django.core.exceptions import ValidationError
Expand Down Expand Up @@ -46,8 +46,21 @@ def _crispy_helper(instance):
),
Div(
Row(
Column('public_ip', css_class='col-md-5'),
Column('provide_vpn', css_class='col-md-5'),
Column('public_ip', css_class='col-md-6'),
Column('provide_vpn', css_class='col-md-4'),
),
Row(
HTML("""<button type="button" class="btn btn-link bind-row-collapser collapsed"
aria-expanded="false" aria-controls="bind-row">
Show binding options for NAT
<i class="fa fa-plus-circle"></i>
<i class="fa fa-minus-circle"></i>
</button>""")
),
Row(
Column(AppendedText('bind_ip', '<span class="fa fa-external-link-square"/>'),
css_class='col-md-6'),
css_class="bind-row"
),
css_class="card-body", css_id="user-ap-card-body",
),
Expand Down Expand Up @@ -104,6 +117,12 @@ class UserASForm(forms.Form):
label="Public IP",
help_text="Public IP Address to be used for connections to child ASes"
)
bind_ip = forms.GenericIPAddressField(
required=False,
label="Bind IP address",
help_text="(Optional) Specify the local IP "
"if your border router is behind a NAT/firewall etc.",
)
provide_vpn = forms.BooleanField(
required=False,
label="Provide VPN",
Expand Down Expand Up @@ -144,6 +163,7 @@ def __init__(self, data=None, *args, **kwargs):
'label': self.instance.label,
'installation_type': self.instance.installation_type,
'public_ip': host.public_ip,
'bind_ip': host.bind_ip,
'become_user_ap': is_ap,
'provide_vpn': has_vpn
})
Expand Down Expand Up @@ -193,6 +213,7 @@ def save(self, commit=True):
installation_type=self.cleaned_data['installation_type'],
label=self.cleaned_data['label'],
public_ip=self.cleaned_data['public_ip'],
bind_ip=self.cleaned_data['bind_ip'],
wants_user_ap=self.cleaned_data['become_user_ap'],
wants_vpn=self.cleaned_data['provide_vpn'],
)
Expand All @@ -203,6 +224,7 @@ def save(self, commit=True):
installation_type=self.cleaned_data['installation_type'],
label=self.cleaned_data['label'],
public_ip=self.cleaned_data['public_ip'],
bind_ip=self.cleaned_data['bind_ip'],
wants_user_ap=self.cleaned_data['become_user_ap'],
wants_vpn=self.cleaned_data['provide_vpn'],
)
Expand Down
10 changes: 6 additions & 4 deletions scionlab/models/user_as.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ def create(self,
owner: User,
installation_type: str,
isd: int,
public_ip: str = "",
public_ip: str = None,
bind_ip: str = None,
wants_user_ap: bool = False,
wants_vpn: bool = False,
as_id: str = None,
Expand All @@ -62,6 +63,7 @@ def create(self,
:param str installation_type:
:param int isd:
:param str public_ip: optional public IP address for the host of the AS
:param str bind_ip: optional bind IP address for the host of the AS
:param bool wants_user_ap: optional boolean if the User AS should be AP
:param str wants_vpn: optional boolean if the User AP should provide a VPN
:param str as_id: optional as_id, if None is given, the next free ID is chosen
Expand Down Expand Up @@ -90,7 +92,7 @@ def create(self,

user_as.generate_keys()
user_as.generate_certs()
user_as.init_default_services(public_ip=public_ip)
user_as.init_default_services(public_ip=public_ip, bind_ip=bind_ip)

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

def update(self, label: str, installation_type: str, public_ip: str = "",
def update(self, label: str, installation_type: str, public_ip: str = None, bind_ip: str = None,
wants_user_ap: bool = False, wants_vpn: bool = False):
"""
Updates the `UserAS` fields and immediately saves
Expand All @@ -161,7 +163,7 @@ def update(self, label: str, installation_type: str, public_ip: str = "",
self._unset_bind_ips_for_vagrant()
self.installation_type = installation_type
host = self.host
host.update(public_ip=public_ip)
host.update(public_ip=public_ip, bind_ip=bind_ip)
if self.is_attachment_point():
# the case has_vpn and not wants_vpn will be ignored here because it's not allowed
ap = self.attachment_point_info
Expand Down
2 changes: 1 addition & 1 deletion scionlab/openvpn_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ def generate_vpn_server_config(vpn):
server_vpn_subnet = vpn.vpn_subnet()

server_config = string.Template(server_config_tmpl).substitute(
ServerPublicIP=vpn.server.public_ip,
ServerPublicIP=vpn.server.bind_ip or vpn.server.public_ip,
ServerPort=vpn.server_port,
ServerVPNIP=vpn.server_vpn_ip,
Netmask=server_vpn_subnet.netmask,
Expand Down
4 changes: 2 additions & 2 deletions scionlab/templates/scionlab/partials/user_as_form_script.html
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
}
$('.bind-row-collapser').each(function() {
// Init collapser and bind-row
let bind_row = $(this).closest('.attachment').find('.bind-row')
let bind_row = $(this).closest('.card-body').find('.bind-row')
bind_row.addClass('collapse')
if (!should_collapse_bind_row(bind_row)) {
bind_row.addClass('show')
Expand All @@ -74,7 +74,7 @@
});
$('.bind-row-collapser').click(function() {
// Toggle collapse state for collapser and bind-row
let bind_row = $(this).closest('.attachment').find('.bind-row')
let bind_row = $(this).closest('.card-body').find('.bind-row')
$(this).toggleClass('collapsed')
bind_row.collapse('toggle')
});
Expand Down

0 comments on commit 0fdf996

Please sign in to comment.