mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-08-01 07:26:34 +02:00
switches states and updates, deletes and creates hosts
This commit is contained in:
parent
06dd9a4f19
commit
026860c88a
3 changed files with 144 additions and 27 deletions
|
@ -292,6 +292,15 @@ class Domain(TimeStampedModel, DomainHelper):
|
|||
newDict[tup[0]] = tup[1]
|
||||
return newDict
|
||||
|
||||
def isDotGov(self, nameserver):
|
||||
return nameserver.find(".gov")!=-1
|
||||
|
||||
def checkHostIPCombo(self, nameserver:str, ip:list):
|
||||
if ( self.isDotGov(nameserver) and (ip is None or
|
||||
ip==[]) ):
|
||||
raise ValueError("Nameserver %s needs to have an ip address", nameserver)
|
||||
return None
|
||||
|
||||
def getNameserverChanges(self, hosts:list[tuple[str]]):
|
||||
"""
|
||||
calls self.nameserver, it should pull from cache but may result
|
||||
|
@ -316,16 +325,25 @@ class Domain(TimeStampedModel, DomainHelper):
|
|||
# but are not in the list of new host values
|
||||
if prevHost not in newHostDict:
|
||||
deleted_values.append((prevHost,addrs))
|
||||
#if the host exists in both, check if the addresses changed
|
||||
# if the host exists in both, check if the addresses changed
|
||||
else:
|
||||
#TODO - host is being updated when previous was None and new is an empty list
|
||||
#add check here
|
||||
if newHostDict[prevHost] != addrs:
|
||||
# add check here
|
||||
if (newHostDict[prevHost] != addrs
|
||||
and newHostDict[prevHost] is not None):
|
||||
# could raise error here if new value is empty and is a dotgov
|
||||
self.checkHostIPCombo(nameserver=prevHost, ip=newHostDict[prevHost])
|
||||
updated_values.append((prevHost,newHostDict[prevHost]))
|
||||
|
||||
new_values=set(newHostDict)-set(previousHostDict) #returns actually a set
|
||||
|
||||
final_new_values = dict.fromkeys(new_values, None)
|
||||
# loop in final new values to check for .gov and missing addresses
|
||||
for nameserver, ip in final_new_values.items():
|
||||
# check the new values for missing IPs
|
||||
# raise error if missing
|
||||
self.checkHostIPCombo(nameserver=nameserver,ip=ip)
|
||||
|
||||
return (deleted_values,updated_values,final_new_values, previousHostDict)
|
||||
|
||||
@nameservers.setter # type: ignore
|
||||
|
@ -333,7 +351,7 @@ class Domain(TimeStampedModel, DomainHelper):
|
|||
"""host should be a tuple of type str, str,... where the elements are
|
||||
Fully qualified host name, addresses associated with the host
|
||||
example: [(ns1.okay.gov, 127.0.0.1, others ips)]"""
|
||||
# TODO-848: Finish this implementation of delete + update nameserver
|
||||
|
||||
# TODO-848: ip version checking may need to be added in a different ticket
|
||||
|
||||
# We currently don't have IP address functionality
|
||||
|
@ -906,16 +924,29 @@ class Domain(TimeStampedModel, DomainHelper):
|
|||
self._delete_domain()
|
||||
# TODO - delete ticket any additional error handling here
|
||||
|
||||
def is_dns_needed(self):
|
||||
self._invalidate_cache()
|
||||
nameserverList = self.nameservers
|
||||
return len(nameserverList) < 2
|
||||
# def is_dns_needed(self):
|
||||
# """Commented out and kept in the codebase
|
||||
# as this call should be made, but adds
|
||||
# a lot of processing time
|
||||
# when EPP calling is made more efficient
|
||||
# this should be added back in
|
||||
|
||||
# The goal is to double check that
|
||||
# the nameservers we set are in fact
|
||||
# on the registry
|
||||
# """
|
||||
# self._invalidate_cache()
|
||||
# nameserverList = self.nameservers
|
||||
# return len(nameserverList) < 2
|
||||
|
||||
# def dns_not_needed(self):
|
||||
# return not self.is_dns_needed()
|
||||
|
||||
@transition(
|
||||
field="state",
|
||||
source=[State.DNS_NEEDED],
|
||||
target=State.READY,
|
||||
conditions=[lambda x : not is_dns_needed]
|
||||
# conditions=[dns_not_needed]
|
||||
)
|
||||
def ready(self):
|
||||
"""Transition to the ready state
|
||||
|
@ -929,7 +960,7 @@ class Domain(TimeStampedModel, DomainHelper):
|
|||
field="state",
|
||||
source=[State.READY],
|
||||
target=State.DNS_NEEDED,
|
||||
conditions=[is_dns_needed]
|
||||
# conditions=[is_dns_needed]
|
||||
)
|
||||
def dns_needed(self):
|
||||
"""Transition to the DNS_NEEDED state
|
||||
|
@ -1054,17 +1085,21 @@ class Domain(TimeStampedModel, DomainHelper):
|
|||
|
||||
def _convert_ips(self, ip_list: list[str]):
|
||||
edited_ip_list = []
|
||||
if ip_list is None:
|
||||
return []
|
||||
|
||||
for ip_addr in ip_list:
|
||||
if self.is_ipv6():
|
||||
edited_ip_list.append(epp.Ip(addr=ip_addr, ip="v6"))
|
||||
else: # default ip addr is v4
|
||||
edited_ip_list.append(epp.Ip(addr=ip_addr))
|
||||
|
||||
return edited_ip_list
|
||||
|
||||
def _update_host(self, nameserver: str, ip_list: list[str], old_ip_list: list[str]):
|
||||
try:
|
||||
|
||||
if len(ip_list) == 0:
|
||||
if ip_list is None or len(ip_list) == 0 and isinstance(old_ip_list,list) and len(old_ip_list)!=0 :
|
||||
return ErrorCode.COMMAND_COMPLETED_SUCCESSFULLY
|
||||
|
||||
request = commands.UpdateHost(name=nameserver, add=self._convert_ips(ip_list), rem=self._convert_ips(old_ip_list))
|
||||
|
|
|
@ -581,15 +581,36 @@ class MockEppLib(TestCase):
|
|||
contacts=[],
|
||||
hosts=["fake.host.com"],
|
||||
)
|
||||
infoDomainThreeHosts =fakedEppObject(
|
||||
"my-nameserver.gov",
|
||||
cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
|
||||
contacts=[],
|
||||
hosts=["ns1.my-nameserver-1.com","ns1.my-nameserver-2.com","ns1.cats-are-superior3.com"],
|
||||
)
|
||||
infoDomainNoHost =fakedEppObject(
|
||||
"my-nameserver.gov",
|
||||
cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
|
||||
contacts=[],
|
||||
hosts=[],
|
||||
)
|
||||
infoDomainTwoHosts =fakedEppObject(
|
||||
"my-nameserver.gov",
|
||||
cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
|
||||
contacts=[],
|
||||
hosts=["ns1.my-nameserver-1.com","ns1.my-nameserver-2.com"],
|
||||
)
|
||||
mockDataInfoContact = fakedEppObject(
|
||||
"anotherPw", cr_date=datetime.datetime(2023, 7, 25, 19, 45, 35)
|
||||
)
|
||||
mockDataInfoHosts = fakedEppObject(
|
||||
"lastPw", cr_date=datetime.datetime(2023, 8, 25, 19, 45, 35), addrs=["1.2.3", "2.3.4"]
|
||||
)
|
||||
|
||||
mockDataHostChange =fakedEppObject(
|
||||
"lastPw", cr_date=datetime.datetime(2023, 8, 25, 19, 45, 35)
|
||||
)
|
||||
|
||||
extendedValues=False
|
||||
|
||||
def mockSend(self, _request, cleaned):
|
||||
"""Mocks the registry.send function used inside of domain.py
|
||||
|
@ -599,6 +620,13 @@ class MockEppLib(TestCase):
|
|||
if isinstance(_request, commands.InfoDomain):
|
||||
if getattr(_request, "name", None) == "security.gov":
|
||||
return MagicMock(res_data=[self.infoDomainNoContact])
|
||||
elif getattr(_request, "name", None) == "my-nameserver.gov":
|
||||
if self.extendedValues:
|
||||
return MagicMock(res_data=[self.infoDomainThreeHosts])
|
||||
elif self.mockedSendFunction.call_count==5: ## remove this breaks anything?
|
||||
return MagicMock(res_data=[self.infoDomainTwoHosts])
|
||||
else:
|
||||
return MagicMock(res_data=[self.infoDomainNoHost])
|
||||
return MagicMock(res_data=[self.mockDataInfoDomain])
|
||||
elif isinstance(_request, commands.InfoContact):
|
||||
return MagicMock(res_data=[self.mockDataInfoContact])
|
||||
|
|
|
@ -599,7 +599,7 @@ class TestRegistrantNameservers(MockEppLib):
|
|||
"""
|
||||
|
||||
# set 2 nameservers
|
||||
|
||||
print("DOCKER DIDNT SUCK THIS TIME")
|
||||
self.domain.nameservers = [(self.nameserver1,), (self.nameserver2,)]
|
||||
|
||||
# when you create a host, you also have to update at same time
|
||||
|
@ -609,8 +609,10 @@ class TestRegistrantNameservers(MockEppLib):
|
|||
created_host2 = commands.CreateHost(self.nameserver2)
|
||||
update_domain_with_created2 = commands.UpdateDomain(name=self.domain.name, add=[common.HostObjSet([created_host2.name])])
|
||||
|
||||
infoDomain = commands.InfoDomain(name='my-nameserver.gov', auth_info=None)
|
||||
# checking if commands were sent (commands have to be sent in order)
|
||||
expectedCalls = [
|
||||
call(infoDomain, cleaned=True),
|
||||
call(created_host1, cleaned=True),
|
||||
call(update_domain_with_created1, cleaned=True),
|
||||
call(created_host2, cleaned=True),
|
||||
|
@ -620,8 +622,8 @@ class TestRegistrantNameservers(MockEppLib):
|
|||
print("self.mockedSendFunction.call_args_list is ")
|
||||
print(self.mockedSendFunction.call_args_list)
|
||||
|
||||
self.mockedSendFunction.assert_has_calls(expectedCalls)
|
||||
|
||||
self.mockedSendFunction.assert_has_calls(expectedCalls, any_order=True)
|
||||
self.assertEqual(5, self.mockedSendFunction.call_count)
|
||||
# check that status is READY
|
||||
self.assertTrue(self.domain.is_active())
|
||||
|
||||
|
@ -657,7 +659,6 @@ class TestRegistrantNameservers(MockEppLib):
|
|||
self.assertRaises(ValueError, _get_14_nameservers)
|
||||
self.assertEqual(self.mockedSendFunction.call_count, 0)
|
||||
|
||||
@skip("not implemented yet")
|
||||
def test_user_removes_some_nameservers(self):
|
||||
"""
|
||||
Scenario: Registrant removes some nameservers, while keeping at least 2
|
||||
|
@ -667,29 +668,59 @@ class TestRegistrantNameservers(MockEppLib):
|
|||
to the registry
|
||||
And `domain.is_active` returns True
|
||||
"""
|
||||
#Given the domain has 3 nameservers
|
||||
self.domain.nameservers = [(self.nameserver1,), (self.nameserver2,),(self.nameserver3,)]
|
||||
|
||||
#now remove one
|
||||
# Mock is set to return 3 nameservers on infodomain
|
||||
self.extendedValues=True
|
||||
self.domain.nameservers = [(self.nameserver1,), (self.nameserver2,)]
|
||||
expectedCalls=[
|
||||
# calls info domain, and info on all hosts
|
||||
# to get past values
|
||||
# then removes the single host and updates domain
|
||||
call(commands.InfoDomain(name='my-nameserver.gov', auth_info=None), cleaned=True),
|
||||
call(commands.InfoHost(name='ns1.my-nameserver-1.com'), cleaned=True),
|
||||
call(commands.InfoHost(name='ns1.my-nameserver-2.com'), cleaned=True),
|
||||
call(commands.InfoHost(name='ns1.cats-are-superior3.com'), cleaned=True),
|
||||
call(commands.UpdateDomain(name='my-nameserver.gov', add=[], rem=[common.HostObjSet(hosts=['ns1.cats-are-superior3.com'])], nsset=None, keyset=None, registrant=None, auth_info=None), cleaned=True),
|
||||
call(commands.DeleteHost(name='ns1.cats-are-superior3.com'), cleaned=True)]
|
||||
|
||||
#assert updatedomain called
|
||||
#assert call deletehost?
|
||||
raise
|
||||
print("self.mockedSendFunction.call_args_list is ")
|
||||
print(self.mockedSendFunction.call_args_list)
|
||||
self.mockedSendFunction.assert_has_calls(expectedCalls, any_order=True)
|
||||
self.assertTrue(self.domain.is_active())
|
||||
|
||||
@skip("not implemented yet")
|
||||
|
||||
def test_user_removes_too_many_nameservers(self):
|
||||
"""
|
||||
Scenario: Registrant removes some nameservers, bringing the total to less than 2
|
||||
Given the domain has 3 nameservers
|
||||
Given the domain has 2 nameservers
|
||||
When `domain.nameservers` is set to an array containing nameserver #1
|
||||
Then `commands.UpdateDomain` and `commands.DeleteHost` is sent
|
||||
to the registry
|
||||
And `domain.is_active` returns False
|
||||
|
||||
"""
|
||||
raise
|
||||
self.extendedValues=True
|
||||
print("domain state")
|
||||
print(self.domain.state)
|
||||
self.domain.ready()
|
||||
print("Domain state is now")
|
||||
print(self.domain.state)
|
||||
self.domain.nameservers = [(self.nameserver1,)]
|
||||
print("self.mockedSendFunction.call_args_list is ")
|
||||
print(self.mockedSendFunction.call_args_list)
|
||||
expectedCalls=[call(commands.InfoDomain(name='my-nameserver.gov', auth_info=None), cleaned=True),
|
||||
call(commands.InfoHost(name='ns1.my-nameserver-1.com'), cleaned=True),
|
||||
call(commands.InfoHost(name='ns1.my-nameserver-2.com'), cleaned=True),
|
||||
call(commands.InfoHost(name='ns1.cats-are-superior3.com'), cleaned=True),
|
||||
call(commands.UpdateDomain(name='my-nameserver.gov', add=[], rem=[common.HostObjSet(hosts=['ns1.my-nameserver-2.com'])], nsset=None, keyset=None, registrant=None, auth_info=None), cleaned=True),
|
||||
call(commands.DeleteHost(name='ns1.my-nameserver-2.com'), cleaned=True),
|
||||
call(commands.UpdateDomain(name='my-nameserver.gov', add=[], rem=[common.HostObjSet(hosts=['ns1.cats-are-superior3.com'])], nsset=None, keyset=None, registrant=None, auth_info=None), cleaned=True),
|
||||
call(commands.DeleteHost(name='ns1.cats-are-superior3.com'), cleaned=True)]
|
||||
|
||||
|
||||
self.mockedSendFunction.assert_has_calls(expectedCalls, any_order=True)
|
||||
self.assertFalse(self.domain.is_active())
|
||||
|
||||
@skip("not implemented yet")
|
||||
def test_user_replaces_nameservers(self):
|
||||
"""
|
||||
Scenario: Registrant simultaneously adds and removes some nameservers
|
||||
|
@ -700,9 +731,27 @@ class TestRegistrantNameservers(MockEppLib):
|
|||
And `commands.UpdateDomain` is sent to add #4 and #5 plus remove #2 and #3
|
||||
And `commands.DeleteHost` is sent to delete #2 and #3
|
||||
"""
|
||||
raise
|
||||
self.extendedValues=True
|
||||
self.domain.ready()
|
||||
self.domain.nameservers=[(self.nameserver1,), ("ns1.cats-are-superior1.com",), ("ns1.cats-are-superior2.com",)]
|
||||
print("self.mockedSendFunction.call_args_list is ")
|
||||
print(self.mockedSendFunction.call_args_list)
|
||||
expectedCalls=[call(commands.InfoDomain(name='my-nameserver.gov', auth_info=None), cleaned=True),
|
||||
call(commands.InfoHost(name='ns1.my-nameserver-1.com'), cleaned=True),
|
||||
call(commands.InfoHost(name='ns1.my-nameserver-2.com'), cleaned=True),
|
||||
call(commands.InfoHost(name='ns1.cats-are-superior3.com'), cleaned=True),
|
||||
call(commands.UpdateDomain(name='my-nameserver.gov', add=[], rem=[common.HostObjSet(hosts=['ns1.my-nameserver-2.com'])], nsset=None, keyset=None, registrant=None, auth_info=None), cleaned=True),
|
||||
call(commands.DeleteHost(name='ns1.my-nameserver-2.com'), cleaned=True),
|
||||
call(commands.CreateHost(name='ns1.cats-are-superior1.com', addrs=[]), cleaned=True),
|
||||
call(commands.UpdateDomain(name='my-nameserver.gov', add=[common.HostObjSet(hosts=['ns1.cats-are-superior1.com'])], rem=[], nsset=None, keyset=None, registrant=None, auth_info=None), cleaned=True),
|
||||
call(commands.CreateHost(name='ns1.cats-are-superior2.com', addrs=[]), cleaned=True),
|
||||
call(commands.UpdateDomain(name='my-nameserver.gov', add=[common.HostObjSet(hosts=['ns1.cats-are-superior2.com'])], rem=[], nsset=None, keyset=None, registrant=None, auth_info=None), cleaned=True)
|
||||
]
|
||||
|
||||
self.mockedSendFunction.assert_has_calls(expectedCalls, any_order=True)
|
||||
self.assertTrue(self.domain.is_active())
|
||||
|
||||
|
||||
@skip("not implemented yet")
|
||||
def test_user_cannot_add_subordinate_without_ip(self):
|
||||
"""
|
||||
Scenario: Registrant adds a nameserver which is a subdomain of their .gov
|
||||
|
@ -711,6 +760,8 @@ class TestRegistrantNameservers(MockEppLib):
|
|||
with a subdomain of the domain and no IP addresses
|
||||
Then Domain raises a user-friendly error
|
||||
"""
|
||||
#add a nameserver with a .gov and no ip
|
||||
##assertRaises error
|
||||
raise
|
||||
|
||||
@skip("not implemented yet")
|
||||
|
@ -758,6 +809,9 @@ class TestRegistrantNameservers(MockEppLib):
|
|||
"""
|
||||
raise
|
||||
|
||||
def tearDown(self):
|
||||
self.extendedValues=False
|
||||
return super().tearDown()
|
||||
|
||||
class TestRegistrantDNSSEC(TestCase):
|
||||
"""Rule: Registrants may modify their secure DNS data"""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue