gnetclisdk 1.0.101__py3-none-any.whl → 1.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of gnetclisdk might be problematic. Click here for more details.
- gnetclisdk/config.py +54 -0
- gnetclisdk/starter.py +102 -0
- {gnetclisdk-1.0.101.dist-info → gnetclisdk-1.1.0.dist-info}/METADATA +2 -1
- {gnetclisdk-1.0.101.dist-info → gnetclisdk-1.1.0.dist-info}/RECORD +6 -4
- {gnetclisdk-1.0.101.dist-info → gnetclisdk-1.1.0.dist-info}/WHEEL +0 -0
- {gnetclisdk-1.0.101.dist-info → gnetclisdk-1.1.0.dist-info}/top_level.txt +0 -0
gnetclisdk/config.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from dataclasses import dataclass, asdict, field
|
|
2
|
+
from datetime import timedelta
|
|
3
|
+
|
|
4
|
+
import yaml
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class LogConfig:
|
|
9
|
+
level: str = "info"
|
|
10
|
+
json: bool = False
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class AuthAppConfig:
|
|
15
|
+
login: str = ""
|
|
16
|
+
password: str = ""
|
|
17
|
+
private_key: str = "" # path to private key file
|
|
18
|
+
proxy_jump: str = ""
|
|
19
|
+
use_agent: bool = False
|
|
20
|
+
ssh_config: bool = False
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class Config:
|
|
25
|
+
logging: LogConfig = field(default_factory=LogConfig)
|
|
26
|
+
port: str = "" # Listen address
|
|
27
|
+
http_port: str = "" # Http listen address
|
|
28
|
+
dev_auth: AuthAppConfig = field(default_factory=AuthAppConfig)
|
|
29
|
+
dev_conf: str = "" # Path to yaml with device types
|
|
30
|
+
tls: bool = False
|
|
31
|
+
cert_file: str = ""
|
|
32
|
+
key_file: str = ""
|
|
33
|
+
basic_auth: str = ""
|
|
34
|
+
disable_tcp: bool = False
|
|
35
|
+
unix_socket: str = "" # Unix socket pat
|
|
36
|
+
default_read_timeout: timedelta = timedelta(seconds=0)
|
|
37
|
+
default_cmd_timeout: timedelta = timedelta(seconds=0)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def dict_factory(data):
|
|
41
|
+
return {
|
|
42
|
+
key: (
|
|
43
|
+
f"{value.total_seconds()}s"
|
|
44
|
+
if isinstance(value, timedelta)
|
|
45
|
+
else value
|
|
46
|
+
)
|
|
47
|
+
for key, value in data
|
|
48
|
+
if value != "" # skip empty strings
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def config_to_yaml(cfg: Config) -> str:
|
|
53
|
+
cfg_dict = asdict(cfg, dict_factory=dict_factory)
|
|
54
|
+
return yaml.safe_dump(cfg_dict, sort_keys=False)
|
gnetclisdk/starter.py
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import json
|
|
3
|
+
import logging
|
|
4
|
+
from asyncio.subprocess import Process
|
|
5
|
+
from json import JSONDecodeError
|
|
6
|
+
from subprocess import DEVNULL, PIPE, TimeoutExpired
|
|
7
|
+
|
|
8
|
+
from gnetclisdk.config import Config, LogConfig, AuthAppConfig, config_to_yaml
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
DEFAULT_GNETCLI_SERVER_CONF = Config(
|
|
13
|
+
logging=LogConfig(level="debug", json=True),
|
|
14
|
+
dev_auth=AuthAppConfig(use_agent=True, ssh_config=True),
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class GnetcliStarter:
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
server_path: str,
|
|
22
|
+
server_conf: Config = DEFAULT_GNETCLI_SERVER_CONF,
|
|
23
|
+
start_timeout: int = 5,
|
|
24
|
+
stop_timeout: int = 10,
|
|
25
|
+
):
|
|
26
|
+
self._server_path = server_path
|
|
27
|
+
self._server_conf = server_conf
|
|
28
|
+
self._running = False
|
|
29
|
+
self._proc: Process | None = None
|
|
30
|
+
self._start_timeout = start_timeout
|
|
31
|
+
self._stop_timeout = stop_timeout
|
|
32
|
+
|
|
33
|
+
async def _start(self) -> Process:
|
|
34
|
+
logger.debug("Starting Gnetcli server: %s", self._server_path)
|
|
35
|
+
proc = await asyncio.create_subprocess_exec(
|
|
36
|
+
self._server_path,
|
|
37
|
+
"--conf-file",
|
|
38
|
+
"-",
|
|
39
|
+
stdout=DEVNULL, # we do not read stdout
|
|
40
|
+
stderr=PIPE,
|
|
41
|
+
stdin=PIPE,
|
|
42
|
+
)
|
|
43
|
+
self._running = True
|
|
44
|
+
conf_yaml = config_to_yaml(self._server_conf)
|
|
45
|
+
proc.stdin.write(conf_yaml.encode())
|
|
46
|
+
await proc.stdin.drain()
|
|
47
|
+
proc.stdin.close()
|
|
48
|
+
return proc
|
|
49
|
+
|
|
50
|
+
async def _wait_url(self) -> str:
|
|
51
|
+
while proc := self._proc:
|
|
52
|
+
output = await proc.stderr.readline()
|
|
53
|
+
if output == "" and proc.returncode is not None:
|
|
54
|
+
break
|
|
55
|
+
if not output:
|
|
56
|
+
continue
|
|
57
|
+
logger.debug("gnetcli output: %s", output.strip())
|
|
58
|
+
try:
|
|
59
|
+
data = json.loads(output)
|
|
60
|
+
except JSONDecodeError:
|
|
61
|
+
logger.error("cannot decode data")
|
|
62
|
+
continue
|
|
63
|
+
if data.get("msg") == "init tcp socket":
|
|
64
|
+
logger.debug("Tcp socket found")
|
|
65
|
+
return data.get("address")
|
|
66
|
+
if data.get("msg") == "init unix socket":
|
|
67
|
+
logger.debug("Unix socket found")
|
|
68
|
+
return "unix:" + data.get("path")
|
|
69
|
+
if data.get("level") == "panic":
|
|
70
|
+
logger.error("gnetcli error %s", data)
|
|
71
|
+
return "" # stopped
|
|
72
|
+
|
|
73
|
+
async def __aenter__(self) -> str:
|
|
74
|
+
self._proc = await self._start()
|
|
75
|
+
try:
|
|
76
|
+
return await asyncio.wait_for(
|
|
77
|
+
self._wait_url(), timeout=self._start_timeout
|
|
78
|
+
)
|
|
79
|
+
except asyncio.TimeoutError:
|
|
80
|
+
logger.error("gnetcli _wait_url timeout, terminating")
|
|
81
|
+
await self._terminate()
|
|
82
|
+
raise RuntimeError("gnetcli start failed")
|
|
83
|
+
|
|
84
|
+
async def _terminate(self) -> None:
|
|
85
|
+
if (proc := self._proc) is None:
|
|
86
|
+
return
|
|
87
|
+
if proc.returncode is not None:
|
|
88
|
+
logger.error(
|
|
89
|
+
"gnetcli already terminated with code: %s", proc.returncode
|
|
90
|
+
)
|
|
91
|
+
return
|
|
92
|
+
proc.terminate()
|
|
93
|
+
try:
|
|
94
|
+
await asyncio.wait_for(proc.wait(), timeout=self._stop_timeout)
|
|
95
|
+
except TimeoutExpired:
|
|
96
|
+
logger.debug("gnetcli terminate failed, killing")
|
|
97
|
+
self._proc.kill()
|
|
98
|
+
self._proc = None
|
|
99
|
+
|
|
100
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
101
|
+
self.running = False
|
|
102
|
+
await self._terminate()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gnetclisdk
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.1.0
|
|
4
4
|
Summary: Client for Gnetcli GRPC-server
|
|
5
5
|
Home-page: https://github.com/annetutil/gnetcli
|
|
6
6
|
Author: Alexander Balezin
|
|
@@ -16,6 +16,7 @@ Description-Content-Type: text/markdown
|
|
|
16
16
|
Requires-Dist: protobuf>=4.24.4
|
|
17
17
|
Requires-Dist: grpcio>=1.59.2
|
|
18
18
|
Requires-Dist: googleapis-common-protos>=1.61.0
|
|
19
|
+
Requires-Dist: pyyaml
|
|
19
20
|
Dynamic: author
|
|
20
21
|
Dynamic: author-email
|
|
21
22
|
Dynamic: classifier
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
gnetclisdk/auth.py,sha256=GwM7H7Ecb-gwqUTkQorifNB_mtnZfgeS46gOW2Vx1U4,1246
|
|
2
2
|
gnetclisdk/client.py,sha256=5LEIvHqWk2EVSw4xsaVWPOFahPAiuMObMe2bb9YStu8,19806
|
|
3
|
+
gnetclisdk/config.py,sha256=8Zj9oJdZXE27fMHQy2DBdC6KXdL8flDQ2w3fgc7xXNs,1364
|
|
3
4
|
gnetclisdk/exceptions.py,sha256=Cg94IdDAzQ9Q56Tdif6ladV1IcdBUg0TPa54OBVhJD0,4038
|
|
4
5
|
gnetclisdk/interceptors.py,sha256=apj3l4lnR2ZcsA49odptrBC0kTDmP6Mp0EzYkeEJz9Y,7010
|
|
6
|
+
gnetclisdk/starter.py,sha256=h3Qd6STKGfoobmxSUf2R8DdOqqd7HA4HDcTyEj0eygM,3432
|
|
5
7
|
gnetclisdk/proto/server_pb2.py,sha256=v_A3rRjuWKa7rPOrsAPOl_oLmfD4sqT5ELpAyM3cUI0,8126
|
|
6
8
|
gnetclisdk/proto/server_pb2.pyi,sha256=66Oq_YbkGgEQt9ea-P64H58hiUZoMhqptlMQdl2IAaw,8402
|
|
7
9
|
gnetclisdk/proto/server_pb2_grpc.py,sha256=H_CmevWcjvGTvp4TmzEV-TJRPq2SsQ6UgoCDc-hosyo,12805
|
|
8
|
-
gnetclisdk-1.0.
|
|
9
|
-
gnetclisdk-1.0.
|
|
10
|
-
gnetclisdk-1.0.
|
|
11
|
-
gnetclisdk-1.0.
|
|
10
|
+
gnetclisdk-1.1.0.dist-info/METADATA,sha256=QPnFLuTdBzkK3SfYS6LbxVTQ_3bXHQYh6RdehItUUlY,1814
|
|
11
|
+
gnetclisdk-1.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
12
|
+
gnetclisdk-1.1.0.dist-info/top_level.txt,sha256=MNjS8LEt6d2rZ-dUbV2cnqkuTMu3EqEL2eiSvUZuUlA,11
|
|
13
|
+
gnetclisdk-1.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|