diff --git a/app/api/network.py b/app/api/network.py index b48e05dba65f551130d85510ec4d7a73c2e2e1ef..0a0b7bf43bc36e2b595e095141686c99ffdc39c1 100644 --- a/app/api/network.py +++ b/app/api/network.py @@ -65,6 +65,21 @@ def create_interface(): return create_generic_model(models.Interface, mandatory_fields=('network', 'ip', 'name')) +@bp.route('/hosts') +@jwt_required +def get_hosts(): + return get_generic_model(models.Host, + order_by=models.Host.name) + + +@bp.route('/hosts', methods=['POST']) +@jwt_required +@jwt_groups_accepted('admin', 'create') +def create_host(): + """Create a new host""" + return create_generic_model(models.Host, mandatory_fields=('name',)) + + @bp.route('/macs') @jwt_required def get_macs(): diff --git a/tests/functional/test_api.py b/tests/functional/test_api.py index 8ef3c98541179ef0859d986602a3627d393722e3..708fc7bacb896f9d1cb50492e4540a710e029f8f 100644 --- a/tests/functional/test_api.py +++ b/tests/functional/test_api.py @@ -25,12 +25,13 @@ ENDPOINT_MODEL = { 'inventory/items': models.Item, 'network/networks': models.Network, 'network/interfaces': models.Interface, + 'network/hosts': models.Host, 'network/macs': models.Mac, } GENERIC_GET_ENDPOINTS = [key for key in ENDPOINT_MODEL.keys() - if key not in ('inventory/items', 'network/macs', 'network/networks', 'network/interfaces')] + if key.startswith('inventory') and key != 'inventory/items'] GENERIC_CREATE_ENDPOINTS = [key for key in ENDPOINT_MODEL.keys() - if key not in ('inventory/items', 'inventory/actions', 'network/macs', 'network/networks', 'network/interfaces')] + if key.startswith('inventory') and key not in ('inventory/items', 'inventory/actions')] CREATE_AUTH_ENDPOINTS = [key for key in ENDPOINT_MODEL.keys() if key != 'inventory/actions'] @@ -695,3 +696,41 @@ def test_create_mac_invalid_address(address, client, user_token): data = {'address': address} response = post(client, f'{API_URL}/network/macs', data=data, token=user_token) check_response_message(response, f"'{address}' does not appear to be a MAC address", 422) + + +def test_get_hosts(client, host_factory, readonly_token): + # Create some hosts + host1 = host_factory() + host2 = host_factory() + response = get(client, f'{API_URL}/network/hosts', token=readonly_token) + assert response.status_code == 200 + assert len(response.json) == 2 + check_input_is_subset_of_response(response, (host1.to_dict(), host2.to_dict())) + + +def test_create_host(client, item_factory, user_token): + item = item_factory() + # check that name is mandatory + response = post(client, f'{API_URL}/network/hosts', data={}, token=user_token) + check_response_message(response, "Missing mandatory field 'name'", 422) + + data = {'name': 'my-hostname'} + response = post(client, f'{API_URL}/network/hosts', data=data, token=user_token) + assert response.status_code == 201 + assert {'id', 'name', 'type', 'description', + 'item', 'interfaces', 'created_at', + 'updated_at', 'user'} == set(response.json.keys()) + assert response.json['name'] == data['name'] + + # Check that name shall be unique + response = post(client, f'{API_URL}/network/hosts', data=data, token=user_token) + check_response_message(response, '(psycopg2.IntegrityError) duplicate key value violates unique constraint', 422) + + # Check that we can pass an item_id + data2 = {'name': 'another-hostname', + 'item_id': item.id} + response = post(client, f'{API_URL}/network/hosts', data=data2, token=user_token) + assert response.status_code == 201 + + # check that all items were created + assert models.Host.query.count() == 2