Skip to content

Commit

Permalink
Merge pull request #1249 from Bastian-Krause/bst/provider-improvements
Browse files Browse the repository at this point in the history
Provider Improvements and Fixes
  • Loading branch information
Emantor authored Oct 12, 2023
2 parents 2906645 + c345273 commit 6a11213
Show file tree
Hide file tree
Showing 9 changed files with 140 additions and 28 deletions.
6 changes: 6 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ Breaking changes in 23.1
- The `BareboxDriver` now remembers the log level, sets it to ``0`` on initial
activation/reset and recovers it on ``boot()``. During
``run()``/``run_check()`` the initially detected log level is used.
- The `NFSProviderDriver` now returns mount and path information on ``stage()``
instead of the path to be used on the target. The previous return value did
not fit the NFS mount use case.
- The `NFSProvider` and `RemoteNFSProvider` resources no longer expect the
``internal`` and ``external`` arguments as they do not fit the NFS mount use
case.

Known issues in 23.1
~~~~~~~~~~~~~~~~~~~~
Expand Down
95 changes: 78 additions & 17 deletions doc/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1165,20 +1165,22 @@ This is useful for software installation in the bootloader (via TFTP) or
downloading update artifacts under Linux (via HTTP).

They are used with the ManagedFile helper, which ensures that the file is
available on the server and then creates a symlink from the internal directory
to the uploaded file.
available on the server. For HTTP and TFTP, a symlink from the internal
directory to the uploaded file is created.
The path for the target is generated by replacing the internal prefix with the
external prefix.
For NFS, it is assumed that ``/var/cache/labgrid`` is exported.
The information required for mounting and accessing staged files are returned,
see below.

For now, the TFTP/NFS/HTTP server needs to be configured before using it from
labgrid.

.. _TFTPProvider:
.. _NFSProvider:
.. _HTTPProvider:

TFTPProvider / NFSProvider / HTTPProvider
+++++++++++++++++++++++++++++++++++++++++
TFTPProvider / HTTPProvider
+++++++++++++++++++++++++++

.. code-block:: yaml
Expand All @@ -1196,23 +1198,65 @@ Arguments:

Used by:
- `TFTPProviderDriver`_
- `NFSProviderDriver`_
- `HTTPProviderDriver`_

NFSProvider
+++++++++++

.. code-block:: yaml
NFSProvider: {}
Arguments:
- None

Used by:
- `NFSProviderDriver`_

.. _RemoteTFTPProvider:
.. _RemoteNFSProvider:
.. _RemoteHTTPProvider:

RemoteTFTPProvider / RemoteNFSProvider / RemoteHTTPProvider
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
These describe a `TFTPProvider`_, `NFSProvider`_ or `HTTPProvider`_ resource
available on a remote computer
RemoteTFTPProvider / RemoteHTTPProvider
+++++++++++++++++++++++++++++++++++++++
These describe a `TFTPProvider`_ or `HTTPProvider`_ resource available on a
remote computer.

.. code-block:: yaml
RemoteTFTPProvider
host: "tftphost"
internal: "/srv/tftp/board-23/"
external: "board-23/"
RemoteHTTPProvider:
host: "httphost"
internal: "/srv/www/board-23/"
external: "http://192.168.1.1/board-23/"
Arguments:
- host (str): hostname of the remote host
- internal (str): path prefix to the HTTP/TFTP root directory on ``host``
- external (str): corresponding path prefix for use by the target

Used by:
- `TFTPProviderDriver`_
- `NFSProviderDriver`_
- `HTTPProviderDriver`_

RemoteNFSProvider
+++++++++++++++++
An `NFSProvider`_ resource available on a remote computer.

.. code-block:: yaml
RemoteNFSProvider:
host: "nfshost"
Arguments:
- host (str): hostname of the remote host

Used by:
- `NFSProviderDriver`_

RemotePlace
~~~~~~~~~~~
A RemotePlace describes a set of resources attached to a labgrid remote place.
Expand Down Expand Up @@ -2345,20 +2389,17 @@ Arguments:
- None

.. _TFTPProviderDriver:
.. _NFSProviderDriver:
.. _HTTPProviderDriver:

TFTPProviderDriver / NFSProviderDriver / HTTPProviderDriver
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TFTPProviderDriver / HTTPProviderDriver
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
These drivers control their corresponding Provider resources, either locally or
remotely.

Binds to:
provider:
- `TFTPProvider`_
- `RemoteTFTPProvider`_
- `NFSProvider`_
- `RemoteNFSProvider`_
- `HTTPProvider`_
- `RemoteHTTPProvider`_

Expand All @@ -2372,6 +2413,26 @@ Arguments:
The driver can be used in test cases by calling the `stage()` function, which
returns the path to be used by the target.

NFSProviderDriver
~~~~~~~~~~~~~~~~~
An NFSProviderDriver controls an `NFSProvider` resource.

Binds to:
provider:
- `NFSProvider`_
- `RemoteNFSProvider`_

.. code-block:: yaml
NFSProviderDriver: {}
Arguments:
- None

The driver can be used in test cases by calling the `stage()` function, which
returns an NFSFile object with ``host``, ``export`` and ``relative_file_path``
attributes.

QEMUDriver
~~~~~~~~~~
The QEMUDriver allows the usage of a QEMU instance as a target. It requires
Expand Down
2 changes: 1 addition & 1 deletion labgrid/driver/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
from .usbvideodriver import USBVideoDriver
from .httpvideodriver import HTTPVideoDriver
from .networkinterfacedriver import NetworkInterfaceDriver
from .provider import HTTPProviderDriver, NFSPProviderDriver, TFTPProviderDriver
from .provider import HTTPProviderDriver, NFSProviderDriver, TFTPProviderDriver
from .mqtt import TasmotaPowerDriver
from .manualswitchdriver import ManualSwitchDriver
from .usbtmcdriver import USBTMCDriver
Expand Down
32 changes: 28 additions & 4 deletions labgrid/driver/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@

@attr.s(eq=False)
class BaseProviderDriver(Driver):
def __attrs_post_init__(self):
super().__attrs_post_init__()

@Driver.check_bound
def get_export_vars(self):
return {
Expand Down Expand Up @@ -41,13 +38,40 @@ class TFTPProviderDriver(BaseProviderDriver):
}


@attr.s
class NFSFile:
host = attr.ib(validator=attr.validators.instance_of(str))
export = attr.ib(validator=attr.validators.instance_of(str))
relative_file_path = attr.ib(validator=attr.validators.instance_of(str))


@target_factory.reg_driver
@attr.s(eq=False)
class NFSPProviderDriver(BaseProviderDriver):
class NFSProviderDriver(Driver):
bindings = {
"provider": {"NFSProvider", "RemoteNFSProvider"},
}

@Driver.check_bound
def get_export_vars(self):
return {
"host": self.provider.host,
}

@Driver.check_active
@step(args=['filename'], result=True)
def stage(self, filename):
# always copy the file to he user cache path:
# locally available files might not be NFS-exported
mf = ManagedFile(filename, self.provider, detect_nfs=False)
mf.sync_to_resource()
mf.get_remote_path()

# assuming /var/cache/labgrid is NFS-exported, return required information for mounting and
# file access
relate_file_path = os.path.join(mf.get_hash(), os.path.basename(mf.local_path))
return NFSFile(self.provider.host, mf.get_user_cache_path(), relate_file_path)


@target_factory.reg_driver
@attr.s(eq=False)
Expand Down
2 changes: 1 addition & 1 deletion labgrid/resource/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
from .docker import DockerManager, DockerDaemon, DockerConstants
from .lxaiobus import LXAIOBusPIO
from .pyvisa import PyVISADevice
from .provider import TFTPProvider
from .provider import TFTPProvider, NFSProvider, HTTPProvider
from .mqtt import TasmotaPowerPort
from .httpvideostream import HTTPVideoStream
from .dediprogflasher import DediprogFlasher, NetworkDediprogFlasher
Expand Down
10 changes: 8 additions & 2 deletions labgrid/resource/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ class BaseProvider(Resource):
internal = attr.ib(validator=attr.validators.instance_of(str))
external = attr.ib(validator=attr.validators.instance_of(str))

def __attrs_post_init__(self):
self.host = "localhost"
super().__attrs_post_init__()


@target_factory.reg_resource
@attr.s(eq=False)
Expand All @@ -18,8 +22,10 @@ class TFTPProvider(BaseProvider):

@target_factory.reg_resource
@attr.s(eq=False)
class NFSProvider(BaseProvider):
pass
class NFSProvider(Resource):
def __attrs_post_init__(self):
self.host = "localhost"
super().__attrs_post_init__()


@target_factory.reg_resource
Expand Down
2 changes: 1 addition & 1 deletion labgrid/resource/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ class RemoteTFTPProvider(RemoteBaseProvider):

@target_factory.reg_resource
@attr.s(eq=False)
class RemoteNFSProvider(RemoteBaseProvider):
class RemoteNFSProvider(NetworkResource):
pass


Expand Down
5 changes: 4 additions & 1 deletion labgrid/util/managedfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def sync_to_resource(self, symlink=None):
self.logger.info("File %s is accessible on %s, skipping copy", self.local_path, host)
self.rpath = os.path.dirname(self.local_path) + "/"
else:
self.rpath = f"/var/cache/labgrid/{get_user()}/{self.get_hash()}/"
self.rpath = f"{self.get_user_cache_path()}/{self.get_hash()}/"
self.logger.info("Synchronizing %s to %s", self.local_path, host)
conn.run_check(f"mkdir -p {self.rpath}")
conn.put_file(
Expand Down Expand Up @@ -150,3 +150,6 @@ def get_hash(self):
self.hash = hasher.hexdigest()

return self.hash

def get_user_cache_path(self):
return f"/var/cache/labgrid/{get_user()}"
14 changes: 13 additions & 1 deletion tests/test_export.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest

from labgrid.resource import Resource, NetworkSerialPort
from labgrid.resource import Resource, NetworkSerialPort, TFTPProvider
from labgrid.resource.remote import RemoteNetworkInterface, RemoteTFTPProvider
from labgrid.driver import Driver, SerialDriver, NetworkInterfaceDriver, TFTPProviderDriver
from labgrid.strategy import Strategy
Expand Down Expand Up @@ -88,6 +88,18 @@ def test_export_remote_network_interface(target):
}


def test_export_tftp_provider(target):
TFTPProvider(target, None, internal='/srv/tftp/testboard/', external='testboard/')
TFTPProviderDriver(target, "tftp")

exported = target.export()
assert exported == {
'LG__TFTP_HOST': 'localhost',
'LG__TFTP_INTERNAL': '/srv/tftp/testboard/',
'LG__TFTP_EXTERNAL': 'testboard/',
}


def test_export_remote_tftp_provider(target):
RemoteTFTPProvider(target, None, host='testhost', internal='/srv/tftp/testboard/', external='testboard/')
TFTPProviderDriver(target, "tftp")
Expand Down

0 comments on commit 6a11213

Please sign in to comment.