Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
d24c912
Added ip2location.io for IP geolocation lookup.
ip2location Nov 17, 2025
fb351b1
Removed tab in last line.
ip2location Nov 17, 2025
d69c3e8
Added "ip2location" as maintainer.
ip2location Nov 17, 2025
54bcad8
Update plugins/modules/ip2locationio_facts.py
ip2location Nov 23, 2025
d34c8eb
Update plugins/modules/ip2locationio_facts.py
ip2location Nov 23, 2025
561606e
Update plugins/modules/ip2locationio_facts.py
ip2location Nov 23, 2025
81c39a3
Update plugins/modules/ip2locationio_facts.py
ip2location Nov 23, 2025
f3a7b6c
Update plugins/modules/ip2locationio_facts.py
ip2location Nov 23, 2025
a6be241
Update plugins/modules/ip2locationio_facts.py
ip2location Nov 23, 2025
b7d3650
Update plugins/modules/ip2locationio_facts.py
ip2location Nov 23, 2025
2ae9ad3
Added "typing" library.
ip2location Nov 24, 2025
59647f5
Updated import position.
ip2location Nov 24, 2025
1df0bc5
Merge branch 'ansible-collections:main' into main
ip2location Nov 24, 2025
74f1f6c
Reformatted.
ip2location Nov 24, 2025
6a4948b
Added unit test.
ip2location Nov 30, 2025
838493e
Updated documentation to add "ip" parameter.
ip2location Nov 30, 2025
c8a4862
Renamed module from "ip2location_facts" to "ip2location_info".
ip2location Dec 1, 2025
a5c1e90
Updated version number.
ip2location Dec 1, 2025
dca2adc
Update plugins/modules/ip2location_info.py
ip2location Dec 1, 2025
6f4ced8
Update plugins/modules/ip2location_info.py
ip2location Dec 1, 2025
0e69e07
Updated return definition.
ip2location Dec 1, 2025
d9a2954
Update BOTMETA.yml to latest module name.
ip2location Dec 2, 2025
c9dc43c
Update plugins/modules/ip2location_info.py
ip2location Dec 2, 2025
16949aa
Update plugins/modules/ip2location_info.py
ip2location Dec 2, 2025
16a8ccf
Removed extra parameter from "fetch_url".
ip2location Dec 3, 2025
41b02ff
Fixed "test_ip2location_info.py" with formatter.
ip2location Dec 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/BOTMETA.yml
Original file line number Diff line number Diff line change
Expand Up @@ -745,6 +745,8 @@ files:
maintainers: obourdon hryamzik
$modules/ip_netns.py:
maintainers: bregman-arie
$modules/ip2location_info.py:
maintainers: ip2location
$modules/ipa_:
maintainers: $team_ipa
ignore: fxfitz
Expand Down
164 changes: 164 additions & 0 deletions plugins/modules/ip2location_info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
#!/usr/bin/python

# Copyright (c) 2025, IP2Location <support@ip2location.com>
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later

from __future__ import annotations

DOCUMENTATION = r"""
module: ip2location_info
short_description: Retrieve IP geolocation information of a host's IP address
version_added: 12.2.0
description:
- Gather IP geolocation information of a host's IP address using the keyless U(api.ip2location.io) API.
author: "IP2Location (@ip2location)"
extends_documentation_fragment:
- community.general.attributes
- community.general.attributes.info_module
options:
ip:
description:
- IP address to retrieve geolocation information.
type: str
timeout:
description:
- HTTP connection timeout in seconds.
default: 10
type: int
http_agent:
description:
- Set HTTP user agent.
default: "ansible-ip2location-info-module/0.0.1"
type: str
notes:
- This module uses the keyless endpoint which has usage limits.
Check U(https://www.ip2location.io/ip2location-documentation) for more information.
"""

EXAMPLES = r"""
# Retrieve geolocation data of a host's IP address
- name: Get IP geolocation data
community.general.ip2location_info:
register: result

- name: Show some information
ansible.builtin.debug:
msg: "{{ result.ip }} is located in {{ result.country_code }} ({{ result.country_name }})"
"""

RETURN = r"""
record:
description: Dictionary of IP geolocation information for the IP address.
returned: changed
type: complex
contains:
ip:
description: "Public IP address of a host."
type: str
sample: "8.8.8.8"
country_code:
description: ISO 3166-1 alpha-2 country code.
type: str
sample: "US"
country_name:
description: Country name based on ISO 3166.
type: str
sample: "United States of America"
region_name:
description: State or province name.
type: str
sample: "California"
city_name:
description: City name.
type: str
sample: "Mountain View"
latitude:
description: Latitude of the city.
type: float
sample: 37.3860
longitude:
description: Longitude of the city.
type: float
sample: -122.0838
zip_code:
description: ZIP/Postal code.
type: str
sample: "94035"
time_zone:
description: UTC time zone (with DST supported).
type: str
sample: "-08:00"
asn:
description: Autonomous system number (ASN).
type: str
sample: "15169"
as:
description: Autonomous system (AS) name.
type: str
sample: "Google LLC"
is_proxy:
description: Whether is a proxy or not.
type: bool
sample: false
"""

import typing as t

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.urls import fetch_url

USER_AGENT = "ansible-ip2location-info-module/0.0.1"


class Ip2LocationInfo:
def __init__(self, module: AnsibleModule) -> None:
self.url = "https://api.ip2location.io/"
self.timeout = module.params.get("timeout")
self.ip = module.params.get("ip")
self.module = module

def get_geo_data(self) -> dict[str, t.Any]:
url = self.url
if self.ip:
url += f"?ip={self.ip}"

response, info = fetch_url(
self.module,
url,
timeout=self.timeout,
)
if info["status"] != 200:
self.module.fail_json(
msg=f"Could not get {url} page, check for connectivity! HTTP Status: {info['status']}"
)

try:
content = response.read()
result = self.module.from_json(content)
except Exception as exc:
self.module.fail_json(
msg=f"Failed to parse the ip2location.io response from {url}: {exc}", read_content=content
)
else:
return result


def main():
module = AnsibleModule(
argument_spec=dict(
http_agent=dict(default=USER_AGENT),
timeout=dict(type="int", default=10),
ip=dict(type="str"),
),
supports_check_mode=True,
)

ip2location_info = Ip2LocationInfo(module)
ip2location_info_result = {"changed": False}
ip2location_info_result.update(ip2location_info.get_geo_data())
module.exit_json(**ip2location_info_result)


if __name__ == "__main__":
main()
47 changes: 47 additions & 0 deletions tests/unit/plugins/modules/test_ip2location_info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Copyright (c) 2025, IP2Location <support@ip2location.com>
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later

from __future__ import annotations

import json
import unittest
from unittest.mock import Mock, patch

from ansible_collections.community.general.plugins.modules.ip2location_info import Ip2LocationInfo


IP2LOCATION_DATA = {
"ip": "8.8.8.8",
"country_code": "US",
"country_name": "United States of America",
"region_name": "California",
"city_name": "Mountain View",
"latitude": 37.386051,
"longitude": -122.083855,
"zip_code": "94035",
"time_zone": "-07:00",
"asn": "15169",
"as": "Google LLC",
"is_proxy": False,
}


class TestIp2LocationInfo(unittest.TestCase):
def test_get_geo_data_with_ip(self):
module = Mock()
module.params = {"timeout": 10, "ip": "8.8.8.8"}
module.from_json.side_effect = json.loads

with patch(
"ansible_collections.community.general.plugins.modules.ip2location_info.fetch_url"
) as mock_fetch_url:
mock_response = Mock()
mock_response.read.return_value = json.dumps(IP2LOCATION_DATA)
mock_fetch_url.return_value = (mock_response, {"status": 200})

ip2location_info = Ip2LocationInfo(module)
result = ip2location_info.get_geo_data()

self.assertEqual(result["country_code"], "US")
mock_fetch_url.assert_called_once_with(module, "https://api.ip2location.io/?ip=8.8.8.8", timeout=10)