This commit is contained in:
parent
6e16ac7ec6
commit
7360e0d614
@ -14,6 +14,7 @@
|
|||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with Scone. If not, see <https://www.gnu.org/licenses/>.
|
# along with Scone. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
import logging
|
||||||
from asyncio import Lock
|
from asyncio import Lock
|
||||||
from typing import Any, Dict, List, Optional, Tuple, Union
|
from typing import Any, Dict, List, Optional, Tuple, Union
|
||||||
|
|
||||||
@ -25,14 +26,62 @@ from scone.head.kitchen import Kitchen, Preparation
|
|||||||
from scone.head.recipe import HeadRecipe, RecipeContext
|
from scone.head.recipe import HeadRecipe, RecipeContext
|
||||||
from scone.head.utils import check_type
|
from scone.head.utils import check_type
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@attr.s(auto_attribs=True)
|
@attr.s(auto_attribs=True)
|
||||||
class DnsRecord:
|
class DnsRecord:
|
||||||
pass
|
subdomain: str
|
||||||
|
kind: str
|
||||||
|
value: str
|
||||||
|
ttl: Optional[str]
|
||||||
|
priority: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
def parse_records(given: Union[Any, Dict[str, Any]]) -> List[DnsRecord]:
|
def parse_records(given_raw: Union[Any, Dict[str, Dict[str, str]]]) -> List[DnsRecord]:
|
||||||
pass
|
given = check_type(given_raw, dict, "records")
|
||||||
|
|
||||||
|
the_list: List[DnsRecord] = []
|
||||||
|
|
||||||
|
for key, attributes in given.items():
|
||||||
|
# keys: "xyz A"
|
||||||
|
# values: dicts, with keys:
|
||||||
|
# - v: 1.2.3.4
|
||||||
|
# - ttl: 86400
|
||||||
|
# - priority: 50 (for MXes)
|
||||||
|
|
||||||
|
pieces = key.split(" ")
|
||||||
|
if len(pieces) > 2:
|
||||||
|
raise ValueError(
|
||||||
|
f"Key {key} should be space-separable with 2 or less pieces."
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(pieces) == 2:
|
||||||
|
subdomain, kind = pieces
|
||||||
|
else:
|
||||||
|
assert len(pieces) == 1
|
||||||
|
(kind,) = pieces
|
||||||
|
subdomain = ""
|
||||||
|
|
||||||
|
ttl_raw = attributes.get("ttl")
|
||||||
|
prio_raw = attributes.get("priority")
|
||||||
|
|
||||||
|
record_value = attributes.get("v", attributes.get("value", None))
|
||||||
|
|
||||||
|
if record_value is None:
|
||||||
|
raise ValueError("No record value")
|
||||||
|
|
||||||
|
the_list.append(
|
||||||
|
DnsRecord(
|
||||||
|
subdomain=subdomain,
|
||||||
|
kind=kind,
|
||||||
|
value=record_value,
|
||||||
|
ttl=None if ttl_raw is None else str(ttl_raw),
|
||||||
|
priority=None if prio_raw is None else str(prio_raw),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return the_list
|
||||||
|
|
||||||
|
|
||||||
@attr.s(auto_attribs=True)
|
@attr.s(auto_attribs=True)
|
||||||
@ -117,10 +166,43 @@ class HurricaneElectricDns(HeadRecipe):
|
|||||||
return domain.records
|
return domain.records
|
||||||
|
|
||||||
async def cook(self, kitchen: Kitchen) -> None:
|
async def cook(self, kitchen: Kitchen) -> None:
|
||||||
|
# TODO(correctness): can't handle multiple DNS records
|
||||||
|
# with same (type, subdomain)
|
||||||
kitchen.get_dependency_tracker().ignore()
|
kitchen.get_dependency_tracker().ignore()
|
||||||
cached = await self._get_client(kitchen.head)
|
cached = await self._get_client(kitchen.head)
|
||||||
|
|
||||||
records = await self._get_records(cached, cached.domains[self.domain])
|
records = await self._get_records(cached, cached.domains[self.domain])
|
||||||
|
|
||||||
|
records_cache: Dict[Tuple[str, str], HeRecord] = {}
|
||||||
|
|
||||||
for record in records:
|
for record in records:
|
||||||
print(record)
|
dotted_subdomain_suffix = f".{self.domain}"
|
||||||
|
if record.host == self.domain:
|
||||||
|
subdomain = ""
|
||||||
|
elif record.host.endswith(dotted_subdomain_suffix):
|
||||||
|
subdomain = record.host[: -len(dotted_subdomain_suffix)]
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Can't figure out subdomain for {record.host}")
|
||||||
|
|
||||||
|
records_cache[(subdomain, record.type)] = record
|
||||||
|
|
||||||
|
logger.debug("Present records: %r", records_cache.keys())
|
||||||
|
|
||||||
|
for wanted_record in self.records:
|
||||||
|
wr_key = (wanted_record.subdomain, wanted_record.kind)
|
||||||
|
logger.debug("Want %r: %r", wr_key, wanted_record)
|
||||||
|
existing_record = records_cache.get(wr_key)
|
||||||
|
if existing_record is not None:
|
||||||
|
# TODO(correctness): amend as needed
|
||||||
|
logger.debug("Found existing %r", existing_record)
|
||||||
|
else:
|
||||||
|
logger.debug("Will need to create new one")
|
||||||
|
async with cached.lock:
|
||||||
|
cached.client.add_record(
|
||||||
|
self.domain,
|
||||||
|
wanted_record.subdomain,
|
||||||
|
wanted_record.kind,
|
||||||
|
wanted_record.value,
|
||||||
|
wanted_record.priority or None,
|
||||||
|
wanted_record.ttl or 86400,
|
||||||
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user