Much better code

This commit is contained in:
Andrea Mistrali 2024-06-28 17:14:01 +02:00
parent 8e4c0b5ce4
commit e90cac77db
52 changed files with 1931 additions and 731 deletions

1633
headscale.openapi.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,26 +1,42 @@
from pydantic import BaseModel, Field
from typing import Optional, List
from datetime import datetime
from .model import HSAPICall
from headscale_api_client.schemas import (v1CreateApiKeyRequest,
v1ListApiKeysResponse,
v1CreateApiKeyResponse,
v1ExpireApiKeyRequest,
v1ExpireApiKeyResponse,
v1DeleteApiKeyResponse)
from .schemas import v1ApiKey
class v1CreateApiKeyRequest(BaseModel):
expiration: str = Field(alias="expiration", default=None)
class v1ExpireApiKeyRequest(BaseModel):
prefix: str = Field(alias="prefix", default=None)
class v1ListApiKeysResponse(BaseModel):
apiKeys: Optional[List[Optional[v1ApiKey]]] = Field(
alias="apiKeys", default=None)
class v1CreateApiKeyResponse(BaseModel):
apiKey: str = Field(alias="apiKey", default=None)
class APIKey(HSAPICall):
objectPath = "apikey"
def list(self) -> v1ListApiKeysResponse:
response = self.call('get', 'apikey')
response = self.call('get')
return v1ListApiKeysResponse(**response.json())
def create(self, data: v1CreateApiKeyRequest) -> v1CreateApiKeyResponse:
response = self.call('post', 'apikey', data)
response = self.call('post', data=data)
return v1CreateApiKeyResponse(**response.json())
def expire(self, data: v1ExpireApiKeyRequest) -> v1ExpireApiKeyResponse:
response = self.call('post', 'apikey/expire', data)
return v1ExpireApiKeyResponse(**response.json())
def expire(self, data: v1ExpireApiKeyRequest) -> None:
self.call('post', call_path='expire', data=data)
def delete(self, prefix: str) -> v1DeleteApiKeyResponse:
response = self.call('delete', f'apikey/{prefix}')
return v1DeleteApiKeyResponse(**response.json())
def delete(self, prefix: str) -> None:
self.call('delete', call_path=prefix)

View File

@ -1,15 +1,29 @@
from .schemas import *
from typing import Union, Optional, Dict, Any
from .config import APISettings, HTTPException
import requests
def formatTags(tagList: Union[list, None] = []) -> list:
"""
Get a list of tags and prepend `tag:` to all the ones that
do not start with `tag:`
"""
formattedTags = []
if tagList:
for tag in tagList:
formatted = f"tag:{tag}" if not tag.startswith('tag:') else tag
formattedTags.append(formatted)
return formattedTags
class HSAPICall:
"""
Generic API call.
It has a call() method that wants:
- a method (GET, POST, DELETE);
- a subpath, that is appended to <server>/api/v1
- optional `data` payload
- a subpath, that is appended to <server>/api/v1/{self.objectPath}
- optional `data` payload, the body of the request
"""
objectPath: str = ""
@ -22,7 +36,7 @@ class HSAPICall:
self.base_path = f"{
self.api_settings.server}{self.api_settings.api_path}/{self.objectPath}"
def call(self, method, call_path: str = "", data=None):
def call(self, method, call_path: str = "", data=None, query: dict = {}):
headers = {
"Content-Type": "application/json",
"Accept": "application/json",
@ -31,6 +45,10 @@ class HSAPICall:
json_ = data.dict() if data else dict()
query_params: Dict[str, Any] = {}
query_params = {key: value for (
key, value) in query.items() if value is not None}
path = '/'.join([self.base_path, str(call_path)]
) if call_path else self.base_path
@ -38,6 +56,7 @@ class HSAPICall:
method,
path,
headers=headers,
params=query_params,
verify=self.api_settings.ssl_verify,
json=json_
)

View File

@ -1,14 +1,40 @@
from .model import HSAPICall
from headscale_api_client.schemas import (v1ListNodesResponse,
v1GetNodeResponse,
v1DeleteNodeResponse,
v1ExpireNodeResponse, v1MoveNodeRequest,
v1RenameNodeResponse,
v1MoveNodeRequest,
v1MoveNodeResponse,
v1GetNodeRoutesResponse,
v1SetTagsResponse,
HeadscaleServiceSetTagsBody)
from .model import HSAPICall, formatTags
from .schemas import v1Route, v1Node
from typing import Optional, List
from pydantic import BaseModel, Field
class v1SetTagsNodeRequest(BaseModel):
tags: Optional[List[str]] = Field(alias="tags", default=None)
def model_post_init(self, ctx):
self.tags = formatTags(self.tags)
class v1MoveNodeRequest(BaseModel):
user: Optional[str] = Field(alias="user", default=None)
class v1BackfillNodeIPsRequest(BaseModel):
confirmed: Optional[bool] = Field(alias="confirmed", default=True)
class v1ListNodesResponse(BaseModel):
nodes: Optional[List[Optional[v1Node]]] = Field(
alias="nodes", default=None)
class v1NodeResponse(BaseModel):
node: Optional[v1Node] = Field(alias="node", default=None)
class v1GetNodeRoutesResponse(BaseModel):
routes: Optional[List[Optional[v1Route]]] = Field(
alias="routes", default=None)
class v1BackfillNodeIPsResponse(BaseModel):
changes: Optional[List[str]] = Field(alias="changes", default=None)
class Node(HSAPICall):
@ -19,30 +45,34 @@ class Node(HSAPICall):
response = self.call('get')
return v1ListNodesResponse(**response.json())
def get(self, nodeId: str) -> v1GetNodeResponse:
def get(self, nodeId: str) -> v1NodeResponse:
response = self.call('get', call_path=nodeId)
return v1GetNodeResponse(**response.json())
return v1NodeResponse(**response.json())
def delete(self, nodeId: str) -> v1DeleteNodeResponse:
response = self.call('delete', call_path=nodeId)
return v1DeleteNodeResponse(**response.json())
def delete(self, nodeId: str) -> None:
self.call('delete', call_path=nodeId)
def expire(self, nodeId: str) -> v1ExpireNodeResponse:
response = self.call('post', f'{nodeId}/expire')
return v1ExpireNodeResponse()(**response.json())
def expire(self, nodeId: str) -> None:
self.call('post', f'{nodeId}/expire')
def rename(self, nodeId: str, newName: str) -> v1RenameNodeResponse:
def rename(self, nodeId: str, newName: str) -> v1NodeResponse:
response = self.call('post', f'{nodeId}/rename/{newName}')
return v1RenameNodeResponse(**response.json())
return v1NodeResponse(**response.json())
def move(self, nodeId: str, data: v1MoveNodeRequest) -> v1MoveNodeResponse:
def move(self, nodeId: str, data: v1MoveNodeRequest) -> v1NodeResponse:
response = self.call('post', f'{nodeId}/user', data)
return v1MoveNodeResponse()(**response.json())
return v1NodeResponse(**response.json())
def routes(self, nodeId: str) -> v1GetNodeRoutesResponse:
response = self.call('get', f'{nodeId}/routes')
return v1GetNodeRoutesResponse(**response.json())
def setTags(self, nodeId: str, data: HeadscaleServiceSetTagsBody) -> v1SetTagsResponse:
def setTags(self, nodeId: str, data: v1SetTagsNodeRequest) -> v1NodeResponse:
response = self.call('post', f'{nodeId}/tags', data)
return v1SetTagsResponse(**response.json())
return v1NodeResponse(**response.json())
# Broken on server
def backfillips(self, confirmed: bool = True) -> v1BackfillNodeIPsResponse:
response = self.call(
'post', f'/backfillips?confirmed={confirmed}')
return v1BackfillNodeIPsResponse(**response.json())

View File

@ -0,0 +1,49 @@
from typing import Optional, List
from pydantic import BaseModel, Field
from .schemas import v1PreAuthKey
from .model import HSAPICall, formatTags
class v1ListPreAuthKeysResponse(BaseModel):
preAuthKeys: Optional[List[Optional[v1PreAuthKey]]
] = Field(alias="preAuthKeys", default=None)
class v1PreAuthKeyResponse(BaseModel):
preAuthKey: Optional[v1PreAuthKey] = Field(
alias="preAuthKey", default=None)
class v1ExpirePreAuthKeyRequest(BaseModel):
user: str = Field(alias="user", default=None)
key: int = Field(alias="key", default=None)
class v1CreatePreAuthKeyRequest(BaseModel):
user: str = Field(alias="user", default=None)
reusable: Optional[bool] = Field(alias="reusable", default=None)
ephemeral: Optional[bool] = Field(alias="ephemeral", default=None)
expiration: Optional[str] = Field(alias="expiration", default=None)
aclTags: Optional[List[str]] = Field(alias="aclTags", default=None)
class v1ListPreAuthKeyRequest(BaseModel):
user: Optional[str] = Field(
alias="user", default=None)
class PreAuthKey(HSAPICall):
objectPath = "preauthkey"
def list(self, data: v1ListPreAuthKeyRequest) -> v1ListPreAuthKeysResponse:
response = self.call('get', query=data.model_dump())
return v1ListPreAuthKeysResponse(**response.json())
def create(self, data: v1CreatePreAuthKeyRequest) -> v1PreAuthKeyResponse:
data.aclTags = formatTags(data.aclTags)
response = self.call('post', data=data)
return v1PreAuthKeyResponse(**response.json())
def expire(self, data: v1ExpirePreAuthKeyRequest) -> None:
self.call('post', data=data)

View File

@ -1,27 +1,27 @@
from typing import Optional, List
from pydantic import BaseModel, Field
from .model import HSAPICall
from headscale_api_client.schemas import (v1GetRoutesResponse,
v1DeleteRouteResponse,
v1EnableRouteResponse,
v1DisableRouteResponse,
)
from .schemas import v1Route
class v1ListRoutesResponse(BaseModel):
routes: Optional[List[Optional[v1Route]]] = Field(
alias="routes", default=None)
class Route(HSAPICall):
objectPath = "routes"
def list(self) -> v1GetRoutesResponse:
def list(self) -> v1ListRoutesResponse:
response = self.call('get')
return v1GetRoutesResponse(**response.json())
return v1ListRoutesResponse(**response.json())
def delete(self, routeId: str) -> v1DeleteRouteResponse:
response = self.call('delete', call_path=routeId)
return v1DeleteRouteResponse(**response.json())
def delete(self, routeId: str) -> None:
self.call('delete', call_path=routeId)
def enable(self, routeId: str) -> v1EnableRouteResponse:
response = self.call('post', f'{routeId}/enable')
return v1EnableRouteResponse(**response.json())
def enable(self, routeId: str) -> None:
self.call('post', f'{routeId}/enable')
def disable(self, routeId: str) -> v1DisableRouteResponse:
response = self.call('post', f'{routeId}/disable')
return v1DisableRouteResponse(**response.json())
def disable(self, routeId: str) -> None:
self.call('post', f'{routeId}/disable')

View File

@ -0,0 +1,101 @@
from typing import Optional, List
from pydantic import BaseModel, Field, computed_field
from datetime import datetime, timezone, timedelta
from enum import Enum
class v1RegisterMethod(str, Enum):
REGISTER_METHOD_UNSPECIFIED = "REGISTER_METHOD_UNSPECIFIED"
REGISTER_METHOD_AUTH_KEY = "REGISTER_METHOD_AUTH_KEY"
REGISTER_METHOD_CLI = "REGISTER_METHOD_CLI"
REGISTER_METHOD_OIDC = "REGISTER_METHOD_OIDC"
class v1ApiKey(BaseModel):
id: int = Field(alias="id", default=None)
prefix: str = Field(alias="prefix", default=None)
expiration: datetime = Field(alias="expiration", default=None)
createdAt: datetime = Field(alias="createdAt", default=None)
lastSeen: Optional[datetime] = Field(alias="lastSeen", default=None)
@computed_field
@property
def expired(self) -> bool:
tzinfo = timezone(timedelta(hours=0)) # UTC
now = datetime.now(tzinfo)
return self.expiration < now # type: ignore
class v1PreAuthKey(BaseModel):
id: int = Field(alias="id", default=None)
user: str = Field(alias="user", default=None)
key: str = Field(alias="key", default=None)
reusable: bool = Field(alias="reusable", default=True)
ephemeral: bool = Field(alias="ephemeral", default=False)
used: bool = Field(alias="used", default=None)
expiration: datetime = Field(alias="expiration", default=None)
createdAt: datetime = Field(alias="createdAt", default=None)
aclTags: Optional[List[str]] = Field(alias="aclTags", default=None)
@computed_field
@property
def expired(self) -> bool:
tzinfo = timezone(timedelta(hours=0)) # UTC
now = datetime.now(tzinfo)
return self.expiration < now # type: ignore
class v1User(BaseModel):
id: int = Field(alias="id", default=None)
name: str = Field(alias="name", default=None)
createdAt: datetime = Field(alias="createdAt", default=None)
class v1Node(BaseModel):
"""
None model
"""
id: int = Field(alias="id", default=None)
machineKey: str = Field(alias="machineKey", default=None)
nodeKey: str = Field(alias="nodeKey", default=None)
discoKey: str = Field(alias="discoKey", default=None)
ipAddresses: List[str] = Field(alias="ipAddresses", default=None)
name: str = Field(alias="name", default=None)
user: v1User = Field(alias="user", default=None)
lastSeen: datetime = Field(alias="lastSeen", default=None)
expiry: datetime = Field(alias="expiry", default=None)
preAuthKey: Optional[v1PreAuthKey] = Field(
alias="preAuthKey", default=None)
createdAt: datetime = Field(alias="createdAt", default=None)
registerMethod: Optional[v1RegisterMethod] = Field(
alias="registerMethod", default=None)
forcedTags: Optional[List[str]] = Field(alias="forcedTags", default=None)
invalidTags: Optional[List[str]] = Field(alias="invalidTags", default=None)
validTags: Optional[List[str]] = Field(alias="validTags", default=None)
givenName: str = Field(alias="givenName", default=None)
online: bool = Field(alias="online", default=None)
class v1Route(BaseModel):
"""
None model
"""
id: Optional[int] = Field(alias="id", default=None)
node: v1Node = Field(alias="node", default=None)
prefix: str = Field(alias="prefix", default=None)
advertised: bool = Field(alias="advertised", default=None)
enabled: bool = Field(alias="enabled", default=None)
isPrimary: bool = Field(alias="isPrimary", default=None)
createdAt: datetime = Field(alias="createdAt", default=None)
updatedAt: datetime = Field(alias="updatedAt", default=None)
deletedAt: Optional[datetime] = Field(alias="deletedAt", default=None)

View File

@ -1,12 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
class HeadscaleServiceSetTagsBody(BaseModel):
"""
None model
"""
tags: Optional[List[str]] = Field(alias="tags", default=None)

View File

@ -1,42 +0,0 @@
from .HeadscaleServiceSetTagsBody import *
from .protobufAny import *
from .rpcStatus import *
from .v1ApiKey import *
from .v1BackfillNodeIPsResponse import *
from .v1CreateApiKeyRequest import *
from .v1CreateApiKeyResponse import *
from .v1CreatePreAuthKeyRequest import *
from .v1CreatePreAuthKeyResponse import *
from .v1CreateUserRequest import *
from .v1CreateUserResponse import *
from .v1DebugCreateNodeRequest import *
from .v1DebugCreateNodeResponse import *
from .v1DeleteApiKeyResponse import *
from .v1DeleteNodeResponse import *
from .v1DeleteRouteResponse import *
from .v1DeleteUserResponse import *
from .v1DisableRouteResponse import *
from .v1EnableRouteResponse import *
from .v1ExpireApiKeyRequest import *
from .v1ExpireApiKeyResponse import *
from .v1ExpireNodeResponse import *
from .v1ExpirePreAuthKeyRequest import *
from .v1ExpirePreAuthKeyResponse import *
from .v1GetNodeResponse import *
from .v1GetNodeRoutesResponse import *
from .v1GetRoutesResponse import *
from .v1GetUserResponse import *
from .v1ListApiKeysResponse import *
from .v1ListNodesResponse import *
from .v1ListPreAuthKeysResponse import *
from .v1ListUsersResponse import *
from .v1MoveNodeResponse import *
from .v1Node import *
from .v1PreAuthKey import *
from .v1RegisterMethod import *
from .v1RegisterNodeResponse import *
from .v1RenameNodeResponse import *
from .v1RenameUserResponse import *
from .v1Route import *
from .v1SetTagsResponse import *
from .v1User import *

View File

@ -1,12 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
class protobufAny(BaseModel):
"""
None model
"""
type: Optional[str] = Field(alias="@type", default=None)

View File

@ -1,18 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
from .protobufAny import protobufAny
class rpcStatus(BaseModel):
"""
None model
"""
code: Optional[int] = Field(alias="code", default=None)
message: Optional[str] = Field(alias="message", default=None)
details: Optional[List[Optional[protobufAny]]] = Field(alias="details", default=None)

View File

@ -1,20 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
class v1ApiKey(BaseModel):
"""
None model
"""
id: Optional[str] = Field(alias="id", default=None)
prefix: Optional[str] = Field(alias="prefix", default=None)
expiration: Optional[str] = Field(alias="expiration", default=None)
createdAt: Optional[str] = Field(alias="createdAt", default=None)
lastSeen: Optional[str] = Field(alias="lastSeen", default=None)

View File

@ -1,12 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
class v1BackfillNodeIPsResponse(BaseModel):
"""
None model
"""
changes: Optional[List[str]] = Field(alias="changes", default=None)

View File

@ -1,12 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
class v1CreateApiKeyRequest(BaseModel):
"""
None model
"""
expiration: Optional[str] = Field(alias="expiration", default=None)

View File

@ -1,12 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
class v1CreateApiKeyResponse(BaseModel):
"""
None model
"""
apiKey: Optional[str] = Field(alias="apiKey", default=None)

View File

@ -1,20 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
class v1CreatePreAuthKeyRequest(BaseModel):
"""
None model
"""
user: Optional[str] = Field(alias="user", default=None)
reusable: Optional[bool] = Field(alias="reusable", default=None)
ephemeral: Optional[bool] = Field(alias="ephemeral", default=None)
expiration: Optional[str] = Field(alias="expiration", default=None)
aclTags: Optional[List[str]] = Field(alias="aclTags", default=None)

View File

@ -1,14 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
from .v1PreAuthKey import v1PreAuthKey
class v1CreatePreAuthKeyResponse(BaseModel):
"""
None model
"""
preAuthKey: Optional[v1PreAuthKey] = Field(alias="preAuthKey", default=None)

View File

@ -1,12 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
class v1CreateUserRequest(BaseModel):
"""
None model
"""
name: Optional[str] = Field(alias="name", default=None)

View File

@ -1,14 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
from .v1User import v1User
class v1CreateUserResponse(BaseModel):
"""
None model
"""
user: Optional[v1User] = Field(alias="user", default=None)

View File

@ -1,18 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
class v1DebugCreateNodeRequest(BaseModel):
"""
None model
"""
user: Optional[str] = Field(alias="user", default=None)
key: Optional[str] = Field(alias="key", default=None)
name: Optional[str] = Field(alias="name", default=None)
routes: Optional[List[str]] = Field(alias="routes", default=None)

View File

@ -1,14 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
from .v1Node import v1Node
class v1DebugCreateNodeResponse(BaseModel):
"""
None model
"""
node: Optional[v1Node] = Field(alias="node", default=None)

View File

@ -1,10 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
class v1DeleteApiKeyResponse(BaseModel):
"""
None model
"""

View File

@ -1,10 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
class v1DeleteNodeResponse(BaseModel):
"""
None model
"""

View File

@ -1,10 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
class v1DeleteRouteResponse(BaseModel):
"""
None model
"""

View File

@ -1,10 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
class v1DeleteUserResponse(BaseModel):
"""
None model
"""

View File

@ -1,10 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
class v1DisableRouteResponse(BaseModel):
"""
None model
"""

View File

@ -1,10 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
class v1EnableRouteResponse(BaseModel):
"""
None model
"""

View File

@ -1,12 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
class v1ExpireApiKeyRequest(BaseModel):
"""
None model
"""
prefix: Optional[str] = Field(alias="prefix", default=None)

View File

@ -1,10 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
class v1ExpireApiKeyResponse(BaseModel):
"""
None model
"""

View File

@ -1,14 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
from .v1Node import v1Node
class v1ExpireNodeResponse(BaseModel):
"""
None model
"""
node: Optional[v1Node] = Field(alias="node", default=None)

View File

@ -1,14 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
class v1ExpirePreAuthKeyRequest(BaseModel):
"""
None model
"""
user: Optional[str] = Field(alias="user", default=None)
key: Optional[str] = Field(alias="key", default=None)

View File

@ -1,10 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
class v1ExpirePreAuthKeyResponse(BaseModel):
"""
None model
"""

View File

@ -1,14 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
from .v1Node import v1Node
class v1GetNodeResponse(BaseModel):
"""
None model
"""
node: Optional[v1Node] = Field(alias="node", default=None)

View File

@ -1,14 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
from .v1Route import v1Route
class v1GetNodeRoutesResponse(BaseModel):
"""
None model
"""
routes: Optional[List[Optional[v1Route]]] = Field(alias="routes", default=None)

View File

@ -1,15 +0,0 @@
from typing import Optional, List
from pydantic import BaseModel, Field
from .v1Route import v1Route
class v1GetRoutesResponse(BaseModel):
"""
None model
"""
routes: Optional[List[Optional[v1Route]]] = Field(
alias="routes", default=None)

View File

@ -1,14 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
from .v1User import v1User
class v1GetUserResponse(BaseModel):
"""
None model
"""
user: Optional[v1User] = Field(alias="user", default=None)

View File

@ -1,14 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
from .v1ApiKey import v1ApiKey
class v1ListApiKeysResponse(BaseModel):
"""
None model
"""
apiKeys: Optional[List[Optional[v1ApiKey]]] = Field(alias="apiKeys", default=None)

View File

@ -1,14 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
from .v1Node import v1Node
class v1ListNodesResponse(BaseModel):
"""
None model
"""
nodes: Optional[List[Optional[v1Node]]] = Field(alias="nodes", default=None)

View File

@ -1,14 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
from .v1PreAuthKey import v1PreAuthKey
class v1ListPreAuthKeysResponse(BaseModel):
"""
None model
"""
preAuthKeys: Optional[List[Optional[v1PreAuthKey]]] = Field(alias="preAuthKeys", default=None)

View File

@ -1,14 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
from .v1User import v1User
class v1ListUsersResponse(BaseModel):
"""
None model
"""
users: Optional[List[Optional[v1User]]] = Field(alias="users", default=None)

View File

@ -1,12 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
class v1DebugCreateNodeRequest(BaseModel):
"""
None model
"""
user: Optional[str] = Field(alias="user", default=None)

View File

@ -1,14 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
from .v1Node import v1Node
class v1MoveNodeResponse(BaseModel):
"""
None model
"""
node: Optional[v1Node] = Field(alias="node", default=None)

View File

@ -1,36 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
from .v1PreAuthKey import v1PreAuthKey
from .v1RegisterMethod import v1RegisterMethod
from .v1User import v1User
class v1Node(BaseModel):
"""
None model
"""
id: Optional[int] = Field(alias="id", default=None)
machineKey: Optional[str] = Field(alias="machineKey", default=None)
nodeKey: Optional[str] = Field(alias="nodeKey", default=None)
discoKey: Optional[str] = Field(alias="discoKey", default=None)
ipAddresses: Optional[List[str]] = Field(alias="ipAddresses", default=None)
name: Optional[str] = Field(alias="name", default=None)
user: Optional[v1User] = Field(alias="user", default=None)
lastSeen: Optional[str] = Field(alias="lastSeen", default=None)
expiry: Optional[str] = Field(alias="expiry", default=None)
preAuthKey: Optional[v1PreAuthKey] = Field(
alias="preAuthKey", default=None)
createdAt: Optional[str] = Field(alias="createdAt", default=None)
registerMethod: Optional[v1RegisterMethod] = Field(
alias="registerMethod", default=None)
forcedTags: Optional[List[str]] = Field(alias="forcedTags", default=None)
invalidTags: Optional[List[str]] = Field(alias="invalidTags", default=None)
validTags: Optional[List[str]] = Field(alias="validTags", default=None)
givenName: Optional[str] = Field(alias="givenName", default=None)
online: Optional[bool] = Field(alias="online", default=None)

View File

@ -1,28 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
class v1PreAuthKey(BaseModel):
"""
None model
"""
user: Optional[str] = Field(alias="user", default=None)
id: Optional[str] = Field(alias="id", default=None)
key: Optional[str] = Field(alias="key", default=None)
reusable: Optional[bool] = Field(alias="reusable", default=None)
ephemeral: Optional[bool] = Field(alias="ephemeral", default=None)
used: Optional[bool] = Field(alias="used", default=None)
expiration: Optional[str] = Field(alias="expiration", default=None)
createdAt: Optional[str] = Field(alias="createdAt", default=None)
aclTags: Optional[List[str]] = Field(alias="aclTags", default=None)

View File

@ -1,9 +0,0 @@
from enum import Enum
class v1RegisterMethod(str, Enum):
REGISTER_METHOD_UNSPECIFIED = "REGISTER_METHOD_UNSPECIFIED"
REGISTER_METHOD_AUTH_KEY = "REGISTER_METHOD_AUTH_KEY"
REGISTER_METHOD_CLI = "REGISTER_METHOD_CLI"
REGISTER_METHOD_OIDC = "REGISTER_METHOD_OIDC"

View File

@ -1,14 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
from .v1Node import v1Node
class v1RegisterNodeResponse(BaseModel):
"""
None model
"""
node: Optional[v1Node] = Field(alias="node", default=None)

View File

@ -1,14 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
from .v1Node import v1Node
class v1RenameNodeResponse(BaseModel):
"""
None model
"""
node: Optional[v1Node] = Field(alias="node", default=None)

View File

@ -1,14 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
from .v1User import v1User
class v1RenameUserResponse(BaseModel):
"""
None model
"""
user: Optional[v1User] = Field(alias="user", default=None)

View File

@ -1,22 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
from .v1Node import v1Node
class v1Route(BaseModel):
"""
None model
"""
id: Optional[int] = Field(alias="id", default=None)
node: Optional[v1Node] = Field(alias="node", default=None)
prefix: Optional[str] = Field(alias="prefix", default=None)
advertised: Optional[bool] = Field(alias="advertised", default=None)
enabled: Optional[bool] = Field(alias="enabled", default=None)
isPrimary: Optional[bool] = Field(alias="isPrimary", default=None)
createdAt: Optional[str] = Field(alias="createdAt", default=None)
updatedAt: Optional[str] = Field(alias="updatedAt", default=None)
deletedAt: Optional[str] = Field(alias="deletedAt", default=None)

View File

@ -1,14 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
from .v1Node import v1Node
class v1SetTagsResponse(BaseModel):
"""
None model
"""
node: Optional[v1Node] = Field(alias="node", default=None)

View File

@ -1,14 +0,0 @@
from typing import *
from pydantic import BaseModel, Field
class v1User(BaseModel):
"""
None model
"""
id: Optional[int] = Field(alias="id", default=None)
name: Optional[str] = Field(alias="name", default=None)
createdAt: Optional[str] = Field(alias="createdAt", default=None)

View File

@ -1,11 +1,20 @@
from typing import Optional, List
from pydantic import BaseModel, Field
from .schemas import v1User
from .model import HSAPICall
from headscale_api_client.schemas import (v1CreateUserRequest,
v1CreateUserResponse,
v1DeleteUserResponse,
v1ListUsersResponse,
v1GetUserResponse,
v1RenameUserResponse,
)
class v1CreateUserRequest(BaseModel):
name: str = Field(alias="name", default=None)
class v1ListUsersResponse(BaseModel):
users: Optional[List[Optional[v1User]]] = Field(
alias="users", default=None)
class v1UserResponse(BaseModel):
user: Optional[v1User] = Field(alias="user", default=None)
class User(HSAPICall):
@ -16,18 +25,17 @@ class User(HSAPICall):
response = self.call('get')
return v1ListUsersResponse(**response.json())
def get(self, name: str) -> v1GetUserResponse:
def get(self, name: str) -> v1UserResponse:
response = self.call('get', call_path=name)
return v1GetUserResponse(**response.json())
return v1UserResponse(**response.json())
def create(self, data: v1CreateUserRequest) -> v1CreateUserResponse:
def create(self, data: v1CreateUserRequest) -> v1UserResponse:
response = self.call('post', data=data)
return v1CreateUserResponse(**response.json())
return v1UserResponse(**response.json())
def delete(self, name: str) -> v1DeleteUserResponse:
response = self.call('delete', name)
return v1DeleteUserResponse(**response.json())
def delete(self, name: str) -> None:
self.call('delete', name)
def rename(self, oldName: str, newName: str) -> v1RenameUserResponse:
def rename(self, oldName: str, newName: str) -> v1UserResponse:
response = self.call('post', call_path=f"{oldName}/rename/{newName}")
return v1RenameUserResponse(**response.json())
return v1UserResponse(**response.json())