Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dbus service to read file stat #142

Merged
merged 2 commits into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions host_modules/file_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""File stat handler"""

from host_modules import host_service
import subprocess

MOD_NAME = 'file'
EXIT_FAILURE = 1

import os

class FileService(host_service.HostModule):
"""
Dbus endpoint that executes the file command
"""
@host_service.method(host_service.bus_name(MOD_NAME), in_signature='s', out_signature='ia{ss}')
def get_file_stat(self, path):
isabelmsft marked this conversation as resolved.
Show resolved Hide resolved
if not path:
return EXIT_FAILURE, {'error': 'Dbus get_file_stat called with no path specified'}

try:
file_stat = os.stat(path)

# Get last modified time in nanoseconds since epoch
last_modified = int(file_stat.st_mtime * 1e9) # Convert seconds to nanoseconds

# Get permissions in octal format
permissions = oct(file_stat.st_mode)[-3:]

# Get file size in bytes
size = file_stat.st_size

# Get current umask
current_umask = os.umask(0)
os.umask(current_umask) # Reset umask to previous value

return 0, {
'path': path,
'last_modified': str(last_modified), # Converting to string to maintain consistency
'permissions': permissions,
'size': str(size), # Converting to string to maintain consistency
'umask': oct(current_umask)[-3:]
}

except Exception as e:
return EXIT_FAILURE, {'error': str(e)}
5 changes: 3 additions & 2 deletions scripts/sonic-host-server
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import dbus.service
import dbus.mainloop.glib

from gi.repository import GObject
from host_modules import config_engine, gcu, host_service, showtech, systemd_service
from host_modules import config_engine, gcu, host_service, showtech, systemd_service, file_service


def register_dbus():
Expand All @@ -22,7 +22,8 @@ def register_dbus():
'gcu': gcu.GCU('gcu'),
'host_service': host_service.HostService('host_service'),
'showtech': showtech.Showtech('showtech'),
'systemd': systemd_service.SystemdService('systemd')
'systemd': systemd_service.SystemdService('systemd'),
'file_stat': file_service.FileService('file')
}
for mod_name, handler_class in mod_dict.items():
handlers[mod_name] = handler_class
Expand Down
57 changes: 57 additions & 0 deletions tests/host_modules/file_stat_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import sys
import os
import pytest
from unittest import mock
from host_modules import file_service

class TestFileService(object):
@mock.patch("dbus.SystemBus")
@mock.patch("dbus.service.BusName")
@mock.patch("dbus.service.Object.__init__")
@mock.patch("os.stat")
@mock.patch("os.umask")
def test_get_file_stat_valid(self, mock_umask, mock_stat, MockInit, MockBusName, MockSystemBus):
mock_stat_result = mock.Mock()
mock_stat_result.st_mtime = 1609459200.0 # 2021-01-01 00:00:00 in nanoseconds
mock_stat_result.st_mode = 0o100644 # Regular file with permissions
mock_stat_result.st_size = 1024
mock_stat.return_value = mock_stat_result

mock_umask.return_value = 0o022 # Default umask

file_service_stub = file_service.FileService(file_service.MOD_NAME)
path = "/valid/path"
ret, msg = file_service_stub.get_file_stat(path)

assert ret == 0
assert msg['path'] == path
assert msg['last_modified'] == "1609459200000000000"
assert msg['permissions'] == "644"
assert msg['size'] == "1024"
assert msg['umask'] == "o22"

@mock.patch("dbus.SystemBus")
@mock.patch("dbus.service.BusName")
@mock.patch("dbus.service.Object.__init__")
@mock.patch("os.stat")
def test_get_file_stat_invalid_path(self, mock_stat, MockInit, MockBusName, MockSystemBus):
mock_stat.side_effect = FileNotFoundError("[Errno 2] No such file or directory")

file_service_stub = file_service.FileService(file_service.MOD_NAME)
path = "/invalid/path"
ret, msg = file_service_stub.get_file_stat(path)

assert ret == 1
assert 'error' in msg
assert "No such file or directory" in msg['error']

@mock.patch("dbus.SystemBus")
@mock.patch("dbus.service.BusName")
@mock.patch("dbus.service.Object.__init__")
def test_get_file_stat_empty_path(self, MockInit, MockBusName, MockSystemBus):
file_service_stub = file_service.FileService(file_service.MOD_NAME)
path = ""
ret, msg = file_service_stub.get_file_stat(path)

assert ret == 1
assert "Dbus get_file_stat called with no path specified" in msg['error']
Loading