Skip to content

Commit

Permalink
Improve cross-platform implementation (martomi#68)
Browse files Browse the repository at this point in the history
Made the following changes to fix a Pathlib bug where the log file could not be found in the event of a Windows-run chiadog connecting to a remote Linux harvester:

- Renamed `_get_remote_platform()` to `get_host_info()` and made it static.
- Moved `get_host_info()` from class initializer to `create_log_consumer_from_config()`
- Replaced `Path` with either `PosixPurePath` or `WindowsPurePath` depending on  remote host OS info
- Added line to `.gitignore` to allow multi-remote testing
- Updated `util.py` (code formatter output)
  • Loading branch information
pieterhelsen authored May 2, 2021
1 parent cd5c2be commit 5653063
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 28 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# secrets
config.yaml
config.*.yaml

# dev files
.idea
Expand Down
64 changes: 40 additions & 24 deletions src/chia_log/log_consumer.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,17 @@
import logging
import subprocess
from abc import ABC, abstractmethod
from pathlib import Path
from pathlib import Path, PurePosixPath, PureWindowsPath, PurePath
from threading import Thread
from typing import List, Optional
from typing import List, Optional, Tuple

# project
from src.config import check_keys, is_win_platform
from src.util import OS

# lib
import paramiko

from src.util import OS


class LogConsumerSubscriber(ABC):
"""Interface for log consumer subscribers (i.e. handlers)"""
Expand Down Expand Up @@ -83,20 +82,19 @@ def _consume_loop(self):
class NetworkLogConsumer(LogConsumer):
"""Consume logs over the network"""

def __init__(self, remote_log_path: Path, remote_user, remote_host):
def __init__(self, remote_log_path: PurePath, remote_user: str, remote_host: str, remote_platform: OS):
logging.info("Enabled network log consumer.")
super().__init__()

self._remote_user = remote_user
self._remote_host = remote_host
self._remote_log_path = remote_log_path
self._remote_platform = remote_platform

self._ssh_client = paramiko.client.SSHClient()
self._ssh_client.load_system_host_keys()
self._ssh_client.connect(hostname=self._remote_host, username=self._remote_user)

self._remote_platform = self._get_remote_platform()

# Start thread
self._is_running = True
self._thread = Thread(target=self._consume_loop)
Expand All @@ -107,32 +105,42 @@ def stop(self):
self._is_running = False

def _consume_loop(self):
logging.info(f"Consuming remote log file {self._remote_log_path} from {self._remote_host} ({self._remote_platform})")
logging.info(
f"Consuming remote log file {self._remote_log_path} from {self._remote_host} ({self._remote_platform})"
)

if self._remote_platform == OS.WINDOWS:
stdin, stdout, stderr = self._ssh_client.exec_command(f"powershell.exe Get-Content {self._remote_log_path} -Wait -Tail 1")
stdin, stdout, stderr = self._ssh_client.exec_command(
f"powershell.exe Get-Content {self._remote_log_path} -Wait -Tail 1"
)
else:
stdin, stdout, stderr = self._ssh_client.exec_command(f"tail -F {self._remote_log_path}")

while self._is_running:
log_line = stdout.readline()
self._notify_subscribers(log_line)

def _get_remote_platform(self):
stdin, stdout, stderr = self._ssh_client.exec_command(f"uname -a")
fout: str = stdout.readline().lower()
ferr: str = stderr.readline().lower()

if 'linux' in fout:
return OS.LINUX
elif 'darwin' in fout:
return OS.MACOS
elif 'not recognized' in ferr:
return OS.WINDOWS
else:
logging.error(f"Found unsupported platform on remote host, assuming Linux and hope for the best.")

return OS.LINUX
def get_host_info(host: str, user: str, path: str) -> Tuple[OS, PurePath]:

client = paramiko.client.SSHClient()
client.load_system_host_keys()
client.connect(hostname=host, username=user)

stdin, stdout, stderr = client.exec_command("uname -a")
fout: str = stdout.readline().lower()
ferr: str = stderr.readline().lower()

if "linux" in fout:
return OS.LINUX, PurePosixPath(path)
elif "darwin" in fout:
return OS.MACOS, PurePosixPath(path)
elif "not recognized" in ferr:
return OS.WINDOWS, PureWindowsPath(path)
else:
logging.error("Found unsupported platform on remote host, assuming Linux and hope for the best.")

return OS.LINUX, PurePosixPath(path)


def create_log_consumer_from_config(config: dict) -> Optional[LogConsumer]:
Expand All @@ -159,10 +167,18 @@ def create_log_consumer_from_config(config: dict) -> Optional[LogConsumer]:
required_keys=["remote_file_path", "remote_host", "remote_user"], config=enabled_consumer_config
):
return None

platform, path = get_host_info(
enabled_consumer_config["remote_host"],
enabled_consumer_config["remote_user"],
enabled_consumer_config["remote_file_path"],
)

return NetworkLogConsumer(
remote_log_path=Path(enabled_consumer_config["remote_file_path"]),
remote_log_path=path,
remote_host=enabled_consumer_config["remote_host"],
remote_user=enabled_consumer_config["remote_user"],
remote_platform=platform,
)

logging.error("Unhandled consumer type")
Expand Down
7 changes: 3 additions & 4 deletions src/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

class OS(Enum):

LINUX = 'LINUX'
MACOS = 'MACOS'
WINDOWS = 'WINDOWS'

LINUX = "LINUX"
MACOS = "MACOS"
WINDOWS = "WINDOWS"

0 comments on commit 5653063

Please sign in to comment.