From 8ac53fd5411b637473753e91108405b1ea36db76 Mon Sep 17 00:00:00 2001 From: Benjamin Bertrand <benjamin.bertrand@esss.se> Date: Wed, 4 Dec 2019 13:52:58 +0100 Subject: [PATCH] Allow users to edit host with no interface JIRA INFRA-1604 #action In Progress --- app/models.py | 4 +-- app/network/views.py | 2 +- tests/functional/test_api.py | 32 ++++++++++++++++++++++++ tests/functional/test_models.py | 2 +- tests/functional/test_web.py | 43 +++++++++++++++++++++++++++++++++ 5 files changed, 79 insertions(+), 4 deletions(-) diff --git a/app/models.py b/app/models.py index 87be9fc..dd0413e 100644 --- a/app/models.py +++ b/app/models.py @@ -264,9 +264,9 @@ class User(db.Model, UserMixin): - LOGIN_DISABLED can be set to True to turn off authentication check when testing. In this case, this function always returns True. """ - if current_app.config.get("LOGIN_DISABLED") or self.is_admin: + if current_app.config.get("LOGIN_DISABLED") or self.is_admin or network is None: return True - if network is None or network.admin_only: + if network.admin_only: # True is already returned for admin users return False return str(network.scope) in self.csentry_network_scopes diff --git a/app/network/views.py b/app/network/views.py index e759400..a849720 100644 --- a/app/network/views.py +++ b/app/network/views.py @@ -285,7 +285,7 @@ def create_interface(hostname): form = InterfaceForm( request.form, host_id=host.id, interface_name=host.name, random_mac=random_mac ) - if not current_user.is_admin: + if not current_user.is_admin and host.main_network is not None: # Restrict the networks to the same network scope as the main interface form.network_id.choices = [ (str(network.id), network.vlan_name) diff --git a/tests/functional/test_api.py b/tests/functional/test_api.py index c5988c9..316c1dc 100644 --- a/tests/functional/test_api.py +++ b/tests/functional/test_api.py @@ -135,6 +135,11 @@ def user_token(client): return get_token(client, "user_rw", "userrw") +@pytest.fixture() +def user_prod_token(client): + return get_token(client, "user_prod", "userprod") + + @pytest.fixture() def consultant_token(client): return get_token(client, "consultant", "consultantpwd") @@ -1207,6 +1212,33 @@ def test_create_interface_ip_not_in_range_as_admin( assert response.status_code == 201 +def test_normal_user_can_create_interface_on_empty_host( + client, host, network_scope_factory, network_factory, user_prod_token +): + scope = network_scope_factory(name="ProdNetworks") + network = network_factory( + address="192.168.1.0/24", + first_ip="192.168.1.10", + last_ip="192.168.1.250", + scope=scope, + ) + data = { + "network": network.vlan_name, + "ip": "192.168.1.20", + "name": host.name, + "host": host.name, + } + response = post( + client, f"{API_URL}/network/interfaces", data=data, token=user_prod_token + ) + assert response.status_code == 201 + assert response.get_json()["network"] == network.vlan_name + assert response.get_json()["ip"] == "192.168.1.20" + assert response.get_json()["name"] == host.name + # This is the main interface + assert response.get_json()["is_main"] + + def test_delete_interface_invalid_credentials(client, interface_factory, user_token): interface1 = interface_factory() response = delete( diff --git a/tests/functional/test_models.py b/tests/functional/test_models.py index 377a1dc..0d7e45e 100644 --- a/tests/functional/test_models.py +++ b/tests/functional/test_models.py @@ -63,7 +63,7 @@ def test_user_has_access_to_network( assert user.has_access_to_network(network_prod) assert user.has_access_to_network(network_lab) assert not user.has_access_to_network(network_lab_admin) - assert not user.has_access_to_network(None) + assert user.has_access_to_network(None) user = user_factory(groups=["foo", "CSEntry Lab"]) assert not user.has_access_to_network(network_prod) assert user.has_access_to_network(network_lab) diff --git a/tests/functional/test_web.py b/tests/functional/test_web.py index c4bdda2..8827f2d 100644 --- a/tests/functional/test_web.py +++ b/tests/functional/test_web.py @@ -438,6 +438,49 @@ def test_create_interface( assert interface.host == host +def test_add_interface_to_empty_host( + client, host_factory, network_scope_factory, network_factory, +): + host = host_factory(name="myhost") + scope = network_scope_factory(name="ProdNetworks") + network = network_factory( + address="192.168.2.0/24", + first_ip="192.168.2.10", + last_ip="192.168.2.250", + scope=scope, + ) + name = host.name + ip = "192.168.2.11" + mac = "02:42:42:46:3c:75" + form = { + "host_id": host.id, + "interface_name": name, + "network_id": network.id, + "random_mac": False, + "ip": ip, + "mac": mac, + "cnames_string": "", + } + # user_lab doesn't have permissions for the network domain: prod.example.org + # form validation will fail because the network_id won't be in the choices + login(client, "user_lab", "userlab") + response = client.post(f"/network/interfaces/create/{host.name}", data=form) + assert response.status_code == 200 + # The host wasn't created + assert models.Interface.query.filter_by(name=name).first() is None + logout(client) + # Success with user_prod user + login(client, "user_prod", "userprod") + response = client.post(f"/network/interfaces/create/{host.name}", data=form) + assert response.status_code == 302 + # The interface was created + interface = models.Interface.query.filter_by(name=name).first() + assert interface.ip == ip + assert interface.mac == mac + assert interface.name == name + assert interface.host == host + + def check_vm_creation_response(response, success=True): assert response.status_code == 200 assert (b"View task" in response.data) is success -- GitLab