refactor vscale output provider

reuse client with headers, base_url
enable http2
This commit is contained in:
Dmitry Belyaev 2024-02-20 15:27:30 +03:00
parent 952d043fc9
commit cb57ed07de
Signed by: b4tman
GPG Key ID: 41A00BF15EA7E5F3

View File

@ -11,111 +11,85 @@ class VscaleDomains(BaseOutputProvider):
self.__token = self.get_api_token() self.__token = self.get_api_token()
if not self.__token: if not self.__token:
raise KeyError("no api token, use env VSCALE_API_TOKEN") raise KeyError("no api token, use env VSCALE_API_TOKEN")
target = self.config["target"]
self.domain = self.config["domain"]
self.target = f"{target}.{self.domain}"
self.ttl = self.config.get("ttl", 300)
def get_api_token(self) -> str: def get_api_token(self) -> str:
token_env = self.config.get("api_token_env", "VSCALE_API_TOKEN") token_env = self.config.get("api_token_env", "VSCALE_API_TOKEN")
return os.environ[token_env] return os.environ[token_env]
async def find_domain_id(self, transport) -> Optional[int]: async def find_domain_id(self, client) -> Optional[int]:
domain = self.config["domain"] response = await client.get("/domains/")
headers = {"X-Token": self.__token} if httpx.codes.is_success(response.status_code):
async with httpx.AsyncClient(transport=transport) as client: data = response.json()
response = await client.get( if isinstance(data, list):
"https://api.vscale.io/v1/domains/", headers=headers for entry in data:
) if entry["name"] == self.domain:
if httpx.codes.is_success(response.status_code): return entry["id"]
data = response.json()
if isinstance(data, list):
for entry in data:
if entry["name"] == domain:
return entry["id"]
else:
raise TypeError(
"failed to find domain id, unexpected response type"
)
else: else:
raise ValueError( raise TypeError("failed to find domain id, unexpected response type")
f"failed to find domain id, code: {response.status_code}" else:
) raise ValueError(f"failed to find domain id, code: {response.status_code}")
async def find_record(self, transport, domain_id, record_type) -> Optional[int]: async def find_record(self, client, domain_id, record_type) -> Optional[int]:
target = self.config["target"] response = await client.get(
domain = self.config["domain"] f"/domains/{domain_id}/records/",
target = f"{target}.{domain}" )
headers = {"X-Token": self.__token} if httpx.codes.is_success(response.status_code):
async with httpx.AsyncClient(transport=transport) as client: data = response.json()
response = await client.get( if isinstance(data, list):
f"https://api.vscale.io/v1/domains/{domain_id}/records/", for entry in data:
headers=headers, if entry["name"] == self.target and entry["type"] == record_type:
return entry["id"]
else:
raise RuntimeError(
f"error list records {domain_id=}: ", response.status_code
) )
if httpx.codes.is_success(response.status_code):
data = response.json()
if isinstance(data, list):
for entry in data:
if entry["name"] == target and entry["type"] == record_type:
return entry["id"]
else:
raise RuntimeError(
f"error list records {domain_id=}: ", response.status_code
)
async def get_record_value(self, transport, domain_id, record_id) -> str: async def get_record_value(self, client, domain_id, record_id) -> str:
headers = {"X-Token": self.__token} response = await client.get(f"/domains/{domain_id}/records/{record_id}")
async with httpx.AsyncClient(transport=transport) as client: if httpx.codes.is_success(response.status_code):
response = await client.get( data = response.json()
f"https://api.vscale.io/v1/domains/{domain_id}/records/{record_id}", if isinstance(data, dict):
headers=headers, return data["content"]
)
if httpx.codes.is_success(response.status_code):
data = response.json()
if isinstance(data, dict):
return data["content"]
async def change_record(self, transport, domain_id, record_id, record_type, value): async def change_record(self, client, domain_id, record_id, record_type, value):
target = self.config["target"]
domain = self.config["domain"]
target = f"{target}.{domain}"
ttl = self.config.get("ttl", 300)
headers = {"X-Token": self.__token, "Content-Type": "application/json"}
data = { data = {
"content": value, "content": value,
"name": target, "name": self.target,
"ttl": ttl, "ttl": self.ttl,
"type": record_type, "type": record_type,
"id": record_id, "id": record_id,
} }
async with httpx.AsyncClient(transport=transport) as client:
response = await client.put(
f"https://api.vscale.io/v1/domains/{domain_id}/records/{record_id}",
headers=headers,
json=data,
)
if not httpx.codes.is_success(response.status_code):
raise RuntimeError(
f"failed to change record: {target=},{domain_id=}, {record_id=}, {record_type=}, {value=}"
)
async def create_record(self, transport, domain_id, record_type, value): response = await client.put(
target = self.config["target"] f"/domains/{domain_id}/records/{record_id}",
domain = self.config["domain"] json=data,
target = f"{target}.{domain}" )
ttl = self.config.get("ttl", 300) if not httpx.codes.is_success(response.status_code):
headers = {"X-Token": self.__token, "Content-Type": "application/json"} raise RuntimeError(
data = {"content": value, "name": target, "ttl": ttl, "type": record_type} f"failed to change record: {self.target=},{domain_id=}, {record_id=}, {record_type=}, {value=}"
async with httpx.AsyncClient(transport=transport) as client: )
response = await client.post(
f"https://api.vscale.io/v1/domains/{domain_id}/records/", async def create_record(self, client, domain_id, record_type, value):
headers=headers, data = {
json=data, "content": value,
"name": self.target,
"ttl": self.ttl,
"type": record_type,
}
response = await client.post(
f"/domains/{domain_id}/records/",
json=data,
)
if not httpx.codes.is_success(response.status_code):
raise RuntimeError(
f"failed to create record: {self.target=},{domain_id=}, {record_type=}, {value=}, {response.status_code=}"
) )
if not httpx.codes.is_success(response.status_code):
raise RuntimeError(
f"failed to create record: {target=},{domain_id=}, {record_type=}, {value=}, {response.status_code=}"
)
async def set_addrs_imp(self, source_provider, addr_v4, addr_v6): async def set_addrs_imp(self, source_provider, addr_v4, addr_v6):
transport = self.best_transport(addr_v4, addr_v6)
domain_id = await self.find_domain_id(transport)
save_ipv4 = self.config.get("ipv4", False) save_ipv4 = self.config.get("ipv4", False)
save_ipv6 = self.config.get("ipv6", False) save_ipv6 = self.config.get("ipv6", False)
if "ipv4" not in self.config and "ipv6" not in self.config: if "ipv4" not in self.config and "ipv6" not in self.config:
@ -128,15 +102,26 @@ class VscaleDomains(BaseOutputProvider):
if addr_v6 and save_ipv6: if addr_v6 and save_ipv6:
save_addrs.append(("AAAA", addr_v6)) save_addrs.append(("AAAA", addr_v6))
for record_type, value in save_addrs: transport = self.best_transport(addr_v4, addr_v6)
record_id = await self.find_record(transport, domain_id, record_type) api_base = self.config.get("api_base", "https://api.vscale.io/v1/")
if record_id: headers = {"X-Token": self.__token}
old_value = await self.get_record_value(transport, domain_id, record_id) async with httpx.AsyncClient(
if old_value != value: transport=transport, base_url=api_base, headers=headers, http2=True
await self.change_record( ) as client:
transport, domain_id, record_id, record_type, value domain_id = await self.find_domain_id(client)
for record_type, value in save_addrs:
record_id = await self.find_record(client, domain_id, record_type)
if record_id:
old_value = await self.get_record_value(
client, domain_id, record_id
) )
if old_value != value:
await self.change_record(
client, domain_id, record_id, record_type, value
)
else:
print(
f"vscale: skip record change ({record_type=}), value equal"
)
else: else:
print(f"vscale: skip record change ({record_type=}), value equal") await self.create_record(client, domain_id, record_type, value)
else:
await self.create_record(transport, domain_id, record_type, value)