Add docstrings to event models; remove redundant generic test
This commit is contained in:
parent
0ec06808ce
commit
560e0ed8dc
335
docs/actions.rst
335
docs/actions.rst
|
@ -38,43 +38,27 @@ to the `Swagger docs
|
|||
|
||||
Physical Actions
|
||||
****************
|
||||
The following actions describe and react on the physical condition
|
||||
The following actions describe and react on the
|
||||
:class:`ereuse_devicehub.resources.device.states.Physical` condition
|
||||
of the devices.
|
||||
|
||||
ToPrepare, Prepare
|
||||
==================
|
||||
Work has been performed to the device to a defined point of
|
||||
acceptance. Users using this event have to agree what is this point
|
||||
of acceptance; for some is when the device just works, for others
|
||||
when some testing has been performed.
|
||||
|
||||
**Prepare** dictates that the device has been prepared, whereas
|
||||
**ToPrepare** that the device has been selected to be prepared.
|
||||
|
||||
Usually **ToPrepare** is the next event done after registering the
|
||||
device.
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.Prepare
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.ToPrepare
|
||||
|
||||
ToRepair, Repair
|
||||
================
|
||||
ToRepair is the act of selecting a device to be repaired, and
|
||||
Repair the act of performing the actual reparations. If a repair
|
||||
without an error is performed, it represents that the reparation
|
||||
has been successful.
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.Repair
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.ToRepair
|
||||
|
||||
ReadyToUse
|
||||
==========
|
||||
The device is ready to be used. This involves greater preparation
|
||||
from the ``Prepare`` event, and users should only use a device
|
||||
after this event is performed.
|
||||
|
||||
Users usually require devices with this event before shipping them
|
||||
to costumers.
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.ReadyToUse
|
||||
|
||||
Live
|
||||
====
|
||||
A keep-alive from a device connected to the Internet with information
|
||||
about its state (in the form of a ``Snapshot`` event) and usage
|
||||
statistics.
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.Live
|
||||
|
||||
DisposeWaste, Recover
|
||||
=====================
|
||||
|
@ -86,6 +70,8 @@ DisposeWaste, Recover
|
|||
|
||||
See `ToDisposeProduct, DisposeProduct`_.
|
||||
|
||||
.. todo:: Events not developed yet.
|
||||
|
||||
Association actions
|
||||
*******************
|
||||
Actions that change the associations users have with devices;
|
||||
|
@ -99,43 +85,29 @@ and **organize** actions.
|
|||
|
||||
Trade actions
|
||||
=============
|
||||
Trade actions log the political exchange of devices between users,
|
||||
stating **owner** xor **usufructuaree**. Every time a trade event
|
||||
is performed, the old user looses its political possession in favor
|
||||
of another one.
|
||||
Not fully developed.
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.Trade
|
||||
|
||||
Sell
|
||||
----
|
||||
The act of taking money from a buyer in exchange of a device.
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.Sell
|
||||
|
||||
Donate
|
||||
------
|
||||
The act of giving devices without compensation.
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.Donate
|
||||
|
||||
Rent
|
||||
----
|
||||
The act of giving money in return for temporary use, but not
|
||||
ownership, of a device.
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.Rent
|
||||
|
||||
CancelTrade
|
||||
-----------
|
||||
The act of cancelling a `Sell`_, `Donate`_ or `Rent`_.
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.CancelTrade
|
||||
|
||||
ToDisposeProduct, DisposeProduct
|
||||
-------------------------
|
||||
``ToDispose`` and ``DisposeProduct`` manage the process of getting
|
||||
rid of devices by giving (selling, donating) to another organization
|
||||
like a waste manager.
|
||||
|
||||
``ToDispose`` marks a device for being disposed, and
|
||||
``DisposeProduct`` dictates that the device has been disposed.
|
||||
|
||||
See `DisposeWaste, Recover`_ events for disposing without trading
|
||||
the device.
|
||||
|
||||
.. note:: For usability purposes, users might not directly perform
|
||||
``Dispose``, but this could automatically be done when
|
||||
performing ``ToDispose`` + ``Receive`` to a ``RecyclingCenter``.
|
||||
--------------------------------
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.DisposeProduct
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.ToDisposeProduct
|
||||
|
||||
Transfer actions
|
||||
================
|
||||
|
@ -143,34 +115,27 @@ The act of transferring/moving devices from one place to another.
|
|||
|
||||
Receive
|
||||
-------
|
||||
The act of physically taking delivery of a device. The receiver
|
||||
confirms that the devices have arrived, and thus, they
|
||||
**physically possess** them. Note that
|
||||
there can only be one **physical possessor** per device, and
|
||||
``Receive`` changes it.
|
||||
|
||||
The receiver can optionally take a role in the reception, giving
|
||||
it meaning; an user that takes the ``FinalUser`` role in the
|
||||
reception express that it will use the device, whereas a role
|
||||
``Transporter`` is used by intermediaries in shipping.
|
||||
|
||||
.. todo:: how do we ensure users specify type of reception?
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.Receive
|
||||
.. autoclass:: ereuse_devicehub.resources.enums.ReceiverRole
|
||||
:members:
|
||||
:undoc-members:
|
||||
.. autoattribute:: ereuse_devicehub.resources.device.models.Device.physical_possessor
|
||||
|
||||
Organize actions
|
||||
================
|
||||
The act of manipulating/administering/supervising/controlling one or
|
||||
more devices.
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.Organize
|
||||
|
||||
Reserve, CancelReservation
|
||||
--------------------------
|
||||
The act of reserving devices and cancelling them.
|
||||
-------------------------
|
||||
Not fully developed.
|
||||
|
||||
After this event is performed, the user is the **reservee** of the
|
||||
devices. There can only be one non-cancelled reservation for
|
||||
a device, and a reservation can only have one reservee.
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.Reserve
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.CancelReservation
|
||||
|
||||
Assign, Accept, Reject
|
||||
----------------------
|
||||
Not developed.
|
||||
|
||||
``Assign`` allocates devices to an user. The purpose or meaning
|
||||
of the association is defined by the users.
|
||||
|
||||
|
@ -179,9 +144,7 @@ assignments.
|
|||
|
||||
.. todo:: shall we add ``Deassign`` or make ``Assign``
|
||||
always define all active users?
|
||||
|
||||
.. todo:: Assign won't be developed until further notice.
|
||||
|
||||
Assign won't be developed until further notice.
|
||||
|
||||
Internal state actions
|
||||
**********************
|
||||
|
@ -190,254 +153,88 @@ their state.
|
|||
|
||||
Snapshot
|
||||
========
|
||||
The Snapshot sets the physical information of the device (S/N, model...)
|
||||
and updates it with erasures, benchmarks, ratings, and tests; updates the
|
||||
composition of its components (adding / removing them), and links tags
|
||||
to the device.
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.Snapshot
|
||||
|
||||
When receiving a Snapshot, the DeviceHub creates, adds and removes
|
||||
components to match the Snapshot. For example, if a Snapshot of a computer
|
||||
contains a new component, the system searches for the component in its
|
||||
database and, if not found, its creates it; finally linking it to the
|
||||
computer.
|
||||
|
||||
A Snapshot is used with Remove to represent changes in components for
|
||||
a device:
|
||||
|
||||
1. ``Snapshot`` creates a device if it does not exist, and the same
|
||||
for its components. This is all done in one ``Snapshot``.
|
||||
2. If the device exists, it updates its component composition by
|
||||
*adding* and *removing* them. If,
|
||||
for example, this new Snasphot doesn't have a component, it means that
|
||||
this component is not present anymore in the device, thus removing it
|
||||
from it. Then we have that:
|
||||
|
||||
- Components that are added to the device: snapshot2.components -
|
||||
snapshot1.components
|
||||
- Components that are removed to the device: snapshot1.components -
|
||||
snapshot2.components
|
||||
|
||||
When adding a component, there may be the case this component existed
|
||||
before and it was inside another device. In such case, DeviceHub will
|
||||
perform ``Remove`` on the old parent.
|
||||
|
||||
Snapshots from Workbench
|
||||
------------------------
|
||||
When processing a device from the Workbench, this one performs a Snapshot
|
||||
and then performs more events (like testings, benchmarking...).
|
||||
|
||||
There are two ways of sending this information. In an async way,
|
||||
this is, submitting events as soon as Workbench performs then, or
|
||||
submitting only one Snapshot event with all the other events embedded.
|
||||
|
||||
Asynced
|
||||
^^^^^^^
|
||||
The use case, which is represented in the ``test_workbench_phases``,
|
||||
is as follows:
|
||||
|
||||
1. In **T1**, WorkbenchServer (as the middleware from Workbench and
|
||||
Devicehub) submits:
|
||||
|
||||
- A ``Snapshot`` event with the required information to **synchronize**
|
||||
and **rate** the device. This is:
|
||||
|
||||
- Identification information about the device and components
|
||||
(S/N, model, physical characteristics...)
|
||||
- ``Tags`` in a ``tags`` property in the ``device``.
|
||||
- ``Rate`` in an ``events`` property in the ``device``.
|
||||
- ``Benchmarks`` in an ``events`` property in each ``component``
|
||||
or ``device``.
|
||||
- ``TestDataStorage`` as in ``Benchmarks``.
|
||||
- An ordered set of **expected events**, defining which are the next
|
||||
events that Workbench will perform to the device in ideal
|
||||
conditions (device doesn't fail, no Internet drop...).
|
||||
|
||||
Devicehub **syncs** the device with the database and perform the
|
||||
``Benchmark``, the ``TestDataStorage``, and finally the ``Rate``.
|
||||
This leaves the Snapshot **open** to wait for the next events
|
||||
to come.
|
||||
2. Assuming that we expect all events, in **T2**, WorkbenchServer
|
||||
submits a ``StressTest`` with a ``snapshot`` field containing the
|
||||
ID of the Snapshot in 1, and Devicehub links the event with such
|
||||
``Snapshot``.
|
||||
3. In **T3**, WorkbenchServer submits the ``Erase`` with the ``Snapshot``
|
||||
and ``component`` IDs from 1, linking it to them. It repeats
|
||||
this for all the erased data storage devices; **T3+Tn** being
|
||||
*n* the erased data storage devices.
|
||||
4. WorkbenchServer does like in 3. but for the event ``Install``,
|
||||
finishing in **T3+Tn+Tx**, being *x* the number of data storage
|
||||
devices with an OS installed into.
|
||||
5. In **T3+Tn+Tx**, when all *expected events* have been performed,
|
||||
Devicehub **closes** the ``Snapshot`` from 1.
|
||||
|
||||
Synced
|
||||
^^^^^^
|
||||
Optionally, Devicehub understands receiving a ``Snapshot`` with all
|
||||
the events in an ``events`` property inside each affected ``component``
|
||||
or ``device``.
|
||||
|
||||
Add, Remove
|
||||
===========
|
||||
The act of adding and removing components of and from a device.
|
||||
|
||||
These are usually used internally from `Snapshot`_, or manually, for
|
||||
example, when removing a component (like a ``DataStorage`` unit) from
|
||||
a broken computer.
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.Add
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.Remove
|
||||
|
||||
EraseBasic, EraseSectors
|
||||
========================
|
||||
An erasure attempt to a ``DataStorage``. The event contains
|
||||
information about success and nature of the erasure.
|
||||
|
||||
``EraseBasic`` is a fast non-secured way of erasing data storage, and
|
||||
``EraseSectors`` is a slower secured, sector-by-sector, erasure
|
||||
method.
|
||||
|
||||
Users can generate erasure certificates from successful erasures.
|
||||
|
||||
Erasures are an accumulation of **erasure steps**, that are performed
|
||||
as separate actions, called ``StepRandom``, for an erasure step
|
||||
that has overwritten data with random bits, and ``StepZero``,
|
||||
for an erasure step that has overwritten data with zeros.
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.EraseBasic
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.EraseSectors
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.ErasePhysical
|
||||
|
||||
Install
|
||||
=======
|
||||
The action of install an Operative System to a data storage unit.
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.Install
|
||||
|
||||
Test
|
||||
====
|
||||
The act of testing the physical condition of a device and its
|
||||
components.
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.Test
|
||||
|
||||
TestDataStorage
|
||||
---------------
|
||||
The act of testing the data storage.
|
||||
|
||||
Testing is done using the `S.M.A.R.T self test
|
||||
<https://en.wikipedia.org/wiki/S.M.A.R.T.#Self-tests>`_. Note
|
||||
that not all data storage units, specially some new PCIe ones, do not
|
||||
support SMART testing.
|
||||
|
||||
The test takes to other SMART values indicators of the overall health
|
||||
of the data storage.
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.TestDataStorage
|
||||
|
||||
StressTest
|
||||
----------
|
||||
The act of stressing (putting to the maximum capacity)
|
||||
a device for an amount of minutes. If the device is not in great
|
||||
condition won't probably survive such test.
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.StressTest
|
||||
|
||||
Benchmark
|
||||
=========
|
||||
The act of gauging the performance of a device.
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.Benchmark
|
||||
|
||||
|
||||
BenchmarkDataStorage
|
||||
--------------------
|
||||
Benchmarks the data storage unit reading and writing speeds.
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.BenchmarkDataStorage
|
||||
|
||||
|
||||
BenchmarkWithRate
|
||||
-----------------
|
||||
The act of benchmarking a device with a single rate.
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.BenchmarkWithRate
|
||||
|
||||
|
||||
BenchmarkProcessor
|
||||
------------------
|
||||
Benchmarks a processor by executing `BogoMips
|
||||
<https://en.wikipedia.org/wiki/BogoMips>`_. Note that this is not
|
||||
a reliable way of rating processors and we keep it for compatibility
|
||||
purposes.
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.BenchmarkProcessor
|
||||
|
||||
|
||||
BenchmarkProcessorSysbench
|
||||
--------------------------
|
||||
Benchmarks a processor by using the processor benchmarking utility of
|
||||
`sysbench <https://github.com/akopytov/sysbench>`_.
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.BenchmarkProcessorSysbench
|
||||
|
||||
|
||||
BenchmarkRamSysbench
|
||||
--------------------
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.BenchmarkRamSysbench
|
||||
|
||||
Rate
|
||||
====
|
||||
Devicehub generates an rating for a device taking into consideration the
|
||||
visual, functional, and performance.
|
||||
|
||||
A Workflow is as follows:
|
||||
|
||||
1. An agent generates feedback from the device in the form of benchmark,
|
||||
visual, and functional information; which is filled in a ``Rate``
|
||||
event. This is done through a **software**, defining the type
|
||||
of ``Rate`` event. At the moment we have two rates: ``WorkbenchRate``
|
||||
and ``PhotoboxRate``.
|
||||
2. Devicehub gathers this information and computes a score that updates
|
||||
the ``Rate`` event.
|
||||
3. Devicehub aggregates different rates and computes a final score for
|
||||
the device by performing a new ``AggregateRating`` event.
|
||||
|
||||
There are three **types** of ``Rate``: ``WorkbenchRate``,
|
||||
``AppRate``, and ``PhotoboxRate``. ``WorkbenchRate`` can have different
|
||||
**software** algorithms, and each software algorithm can have several
|
||||
**versions**. So, we have 3 dimensions for ``WorkbenchRate``:
|
||||
type, software, version.
|
||||
|
||||
Devicehub generates a rate event for each software and version. So,
|
||||
if an agent fulfills a ``WorkbenchRate`` and there are 2 software
|
||||
algorithms and each has two versions, Devicehub will generate 4 rates.
|
||||
Devicehub understands that only one software and version are the
|
||||
**oficial** (set in the settings of each inventory),
|
||||
and it will generate an ``AggregateRating`` for only the official
|
||||
versions. At the same time, ``Price`` only computes the price of
|
||||
the **oficial** version.
|
||||
|
||||
The technical Workflow in Devicehub is as follows:
|
||||
|
||||
1. In **T1**, the user performs a ``Snapshot`` by processing the device
|
||||
through the Workbench. From the benchmarks and the visual and
|
||||
functional ratings the user does in the device, the system generates
|
||||
many ``WorkbenchRate`` (as many as software and versions defined).
|
||||
With only this information, the system generates an ``AggregateRating``,
|
||||
which is the event that the user will see in the web.
|
||||
2. In **T2**, the user takes pictures from the device through the
|
||||
Photobox, and DeviceHub crates an ``ImageSet`` with multiple
|
||||
``Image`` with information from the photobox.
|
||||
3. In **T3**, an agent (user or AI) rates the pictures, creating a
|
||||
``PhotoboxRate`` **for each** picture. When Devicehub receives the
|
||||
first ``PhotoboxRate`` it creates an ``AggregateRating`` linked
|
||||
to such ``PhotoboxRate``. So, the agent will perform as many
|
||||
``PhotoboxRate`` as pictures are in the ``ImageSet``, and Devicehub
|
||||
will link each ``PhotoboxRate`` to the same ``AggregateRating``.
|
||||
This will end in **T3+Tn**, being *n* the number of photos to rate.
|
||||
4. In **T3+Tn**, after the last photo is rated, Devicehub will generate
|
||||
a new rate for the device: it takes the ``AggregateRating`` from 3.
|
||||
and computes a rate from all the linked ``PhotoboxRate`` plus the
|
||||
last available ``WorkbenchRate`` for that device.
|
||||
|
||||
If the agent in 3. is an user, Devicehub creates ``PhotoboxUserRate``
|
||||
and if it is an AI it creates ``PhotoboxAIRate``.
|
||||
|
||||
The same ``ImageSet`` can be rated multiple times, generating a new
|
||||
``AggregateRating`` each time.
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.Rate
|
||||
|
||||
Price
|
||||
=====
|
||||
Price states a selling price for the device, but not necessariliy the
|
||||
final price this was sold (which is set in the Sell event).
|
||||
|
||||
Devicehub automatically computes a price from ``AggregateRating``
|
||||
events. As in a **Rate**, price can have **software** and **version**,
|
||||
and there is an **official** price that is used to automatically
|
||||
compute the price from an ``AggregateRating``. Only the official price
|
||||
is computed from an ``AggregateRating``.
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.Price
|
||||
|
||||
Migrate
|
||||
=======
|
||||
Moves the devices to a new database/inventory. Devices cannot be
|
||||
modified anymore at the previous database.
|
||||
|
||||
Donation
|
||||
========
|
||||
.. todo:: nextcloud/eReuse/99. Tasks/224. Definir datos necesarios
|
||||
configuración licencia
|
||||
Not done.
|
||||
|
||||
.. autoclass:: ereuse_devicehub.resources.event.models.Migrate
|
||||
|
||||
States
|
||||
******
|
||||
.. todo:: work on september.
|
||||
.. autoclass:: ereuse_devicehub.resources.device.states.State
|
||||
|
||||
.. uml:: states.puml
|
||||
|
||||
.. autoclass:: ereuse_devicehub.resources.device.states.Trading
|
||||
:members:
|
||||
:undoc-members:
|
||||
.. autoclass:: ereuse_devicehub.resources.device.states.Physical
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#
|
||||
# import os
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
# sys.path.insert(0, os.path.abspath('..'))
|
||||
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
@ -42,7 +42,8 @@ extensions = [
|
|||
'sphinx.ext.todo',
|
||||
'sphinx.ext.viewcode',
|
||||
'sphinxcontrib.plantuml',
|
||||
'sphinx.ext.autosectionlabel'
|
||||
'sphinx.ext.autosectionlabel',
|
||||
'sphinx.ext.autodoc'
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
|
@ -159,7 +160,7 @@ texinfo_documents = [
|
|||
# -- Options for intersphinx extension ---------------------------------------
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {'https://docs.python.org/': None}
|
||||
intersphinx_mapping = {'python': ('https://docs.python.org/3', None)}
|
||||
|
||||
# -- Options for todo extension ----------------------------------------------
|
||||
|
||||
|
@ -174,3 +175,4 @@ html_favicon = 'img/favicon.ico'
|
|||
|
||||
# autosectionlabel
|
||||
autosectionlabel_prefix_document = True
|
||||
autodoc_member_order = 'bysource'
|
||||
|
|
|
@ -46,3 +46,10 @@ The result is a JSON object with the following fields:
|
|||
or ``1``.
|
||||
- **perPage**: How many devices are in every page, fixed to ``30``.
|
||||
- **total**: How many total devices passed the filters.
|
||||
|
||||
Models
|
||||
******
|
||||
|
||||
.. automodule:: ereuse_devicehub.resources.device.models
|
||||
:members:
|
||||
:member-order: bysource
|
||||
|
|
|
@ -178,6 +178,10 @@ class Device(Thing):
|
|||
that has it physically. As an example, a transporter could
|
||||
be a physical possessor of a device although it does not
|
||||
own it legally.
|
||||
|
||||
Note that there can only be one physical possessor per device,
|
||||
and :class:`ereuse_devicehub.resources.event.models.Receive`
|
||||
changes it.
|
||||
"""
|
||||
from ereuse_devicehub.resources.event.models import Receive
|
||||
with suppress(LookupError):
|
||||
|
@ -190,7 +194,7 @@ class Device(Thing):
|
|||
device is working if the list is empty.
|
||||
|
||||
This property returns, for the last test performed of each type,
|
||||
the one with the worst severity of them, or None if no
|
||||
the one with the worst severity of them, or `None` if no
|
||||
test has been executed.
|
||||
"""
|
||||
from ereuse_devicehub.resources.event.models import Test
|
||||
|
|
|
@ -263,11 +263,19 @@ class EventDevice(db.Model):
|
|||
|
||||
|
||||
class Add(EventWithOneDevice):
|
||||
pass
|
||||
"""The act of adding components to a device.
|
||||
|
||||
It is usually used internally from a :class:`.Snapshot`, for
|
||||
example, when adding a secondary data storage to a computer.
|
||||
"""
|
||||
|
||||
|
||||
class Remove(EventWithOneDevice):
|
||||
pass
|
||||
"""The act of removing components from a device.
|
||||
|
||||
It is usually used internally from a :class:`.Snapshot`, for
|
||||
example, when removing a component from a broken computer.
|
||||
"""
|
||||
|
||||
|
||||
class Allocate(JoinedTableMixin, EventWithMultipleDevices):
|
||||
|
@ -283,6 +291,30 @@ class Deallocate(JoinedTableMixin, EventWithMultipleDevices):
|
|||
|
||||
|
||||
class EraseBasic(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
||||
"""An erasure attempt to a ``DataStorage``. The event contains
|
||||
information about success and nature of the erasure.
|
||||
|
||||
EraseBasic is a software-based fast non-100%-secured way of
|
||||
erasing data storage, performed
|
||||
by Workbench Computer when executing the open-source
|
||||
`shred <https://en.wikipedia.org/wiki/Shred_(Unix)>`_.
|
||||
|
||||
Users can generate erasure certificates from successful erasures.
|
||||
|
||||
Erasures are an accumulation of **erasure steps**, that are performed
|
||||
as separate actions, called ``StepRandom``, for an erasure step
|
||||
that has overwritten data with random bits, and ``StepZero``,
|
||||
for an erasure step that has overwritten data with zeros.
|
||||
|
||||
For example, if steps are set in the following order and the user
|
||||
used `EraseSectors`, the event represents a
|
||||
`British HMG Infosec Standard 5 (HMG IS5) <https://en.wikipedia.org/
|
||||
wiki/Infosec_Standard_5>`_:
|
||||
|
||||
1. A first step writing zeroes to the hard-drives.
|
||||
2. A second step erasing with random data, verifying the erasure
|
||||
success in each hard-drive sector.
|
||||
"""
|
||||
zeros = Column(Boolean, nullable=False)
|
||||
zeros.comment = """
|
||||
Whether this erasure had a first erasure step consisting of
|
||||
|
@ -296,11 +328,14 @@ class EraseBasic(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
|||
|
||||
|
||||
class EraseSectors(EraseBasic):
|
||||
pass
|
||||
"""A secured-way of erasing data storages, checking sector-by-sector
|
||||
the erasure, using `badblocks <https://en.wikipedia.org/wiki/Badblocks>`_.
|
||||
"""
|
||||
# todo make a property that says if the data wiping process is british...
|
||||
|
||||
|
||||
class ErasePhysical(EraseBasic):
|
||||
"""Physical destruction of a data storage unit."""
|
||||
"""The act of physically destroying a data storage unit."""
|
||||
# todo add attributes
|
||||
pass
|
||||
|
||||
|
@ -346,6 +381,92 @@ class StepRandom(Step):
|
|||
|
||||
|
||||
class Snapshot(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
||||
"""The Snapshot sets the physical information of the device (S/N, model...)
|
||||
and updates it with erasures, benchmarks, ratings, and tests; updates the
|
||||
composition of its components (adding / removing them), and links tags
|
||||
to the device.
|
||||
|
||||
When receiving a Snapshot, the DeviceHub creates, adds and removes
|
||||
components to match the Snapshot. For example, if a Snapshot of a computer
|
||||
contains a new component, the system searches for the component in its
|
||||
database and, if not found, its creates it; finally linking it to the
|
||||
computer.
|
||||
|
||||
A Snapshot is used with Remove to represent changes in components for
|
||||
a device:
|
||||
|
||||
1. ``Snapshot`` creates a device if it does not exist, and the same
|
||||
for its components. This is all done in one ``Snapshot``.
|
||||
2. If the device exists, it updates its component composition by
|
||||
*adding* and *removing* them. If,
|
||||
for example, this new Snasphot doesn't have a component, it means that
|
||||
this component is not present anymore in the device, thus removing it
|
||||
from it. Then we have that:
|
||||
|
||||
- Components that are added to the device: snapshot2.components -
|
||||
snapshot1.components
|
||||
- Components that are removed to the device: snapshot1.components -
|
||||
snapshot2.components
|
||||
|
||||
When adding a component, there may be the case this component existed
|
||||
before and it was inside another device. In such case, DeviceHub will
|
||||
perform ``Remove`` on the old parent.
|
||||
|
||||
**Snapshots from Workbench**
|
||||
|
||||
When processing a device from the Workbench, this one performs a Snapshot
|
||||
and then performs more events (like testings, benchmarking...).
|
||||
|
||||
There are two ways of sending this information. In an async way,
|
||||
this is, submitting events as soon as Workbench performs then, or
|
||||
submitting only one Snapshot event with all the other events embedded.
|
||||
|
||||
**Asynced**
|
||||
|
||||
The use case, which is represented in the ``test_workbench_phases``,
|
||||
is as follows:
|
||||
|
||||
1. In **T1**, WorkbenchServer (as the middleware from Workbench and
|
||||
Devicehub) submits:
|
||||
|
||||
- A ``Snapshot`` event with the required information to **synchronize**
|
||||
and **rate** the device. This is:
|
||||
|
||||
- Identification information about the device and components
|
||||
(S/N, model, physical characteristics...)
|
||||
- ``Tags`` in a ``tags`` property in the ``device``.
|
||||
- ``Rate`` in an ``events`` property in the ``device``.
|
||||
- ``Benchmarks`` in an ``events`` property in each ``component``
|
||||
or ``device``.
|
||||
- ``TestDataStorage`` as in ``Benchmarks``.
|
||||
- An ordered set of **expected events**, defining which are the next
|
||||
events that Workbench will perform to the device in ideal
|
||||
conditions (device doesn't fail, no Internet drop...).
|
||||
|
||||
Devicehub **syncs** the device with the database and perform the
|
||||
``Benchmark``, the ``TestDataStorage``, and finally the ``Rate``.
|
||||
This leaves the Snapshot **open** to wait for the next events
|
||||
to come.
|
||||
2. Assuming that we expect all events, in **T2**, WorkbenchServer
|
||||
submits a ``StressTest`` with a ``snapshot`` field containing the
|
||||
ID of the Snapshot in 1, and Devicehub links the event with such
|
||||
``Snapshot``.
|
||||
3. In **T3**, WorkbenchServer submits the ``Erase`` with the ``Snapshot``
|
||||
and ``component`` IDs from 1, linking it to them. It repeats
|
||||
this for all the erased data storage devices; **T3+Tn** being
|
||||
*n* the erased data storage devices.
|
||||
4. WorkbenchServer does like in 3. but for the event ``Install``,
|
||||
finishing in **T3+Tn+Tx**, being *x* the number of data storage
|
||||
devices with an OS installed into.
|
||||
5. In **T3+Tn+Tx**, when all *expected events* have been performed,
|
||||
Devicehub **closes** the ``Snapshot`` from 1.
|
||||
|
||||
**Synced**
|
||||
|
||||
Optionally, Devicehub understands receiving a ``Snapshot`` with all
|
||||
the events in an ``events`` property inside each affected ``component``
|
||||
or ``device``.
|
||||
"""
|
||||
uuid = Column(UUID(as_uuid=True), unique=True)
|
||||
version = Column(StrictVersionType(STR_SM_SIZE), nullable=False)
|
||||
software = Column(DBEnum(SnapshotSoftware), nullable=False)
|
||||
|
@ -361,6 +482,9 @@ class Snapshot(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
|||
|
||||
|
||||
class Install(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
||||
"""The action of installing an Operative System to a data
|
||||
storage unit.
|
||||
"""
|
||||
elapsed = Column(Interval, nullable=False)
|
||||
|
||||
|
||||
|
@ -375,6 +499,48 @@ class SnapshotRequest(db.Model):
|
|||
|
||||
|
||||
class Rate(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
||||
"""Devicehub generates an rating for a device taking into consideration the
|
||||
visual, functional, and performance.
|
||||
|
||||
A Workflow is as follows:
|
||||
|
||||
1. An agent generates feedback from the device in the form of benchmark,
|
||||
visual, and functional information; which is filled in a ``Rate``
|
||||
event. This is done through a **software**, defining the type
|
||||
of ``Rate`` event. At the moment we have ``WorkbenchRate``.
|
||||
2. Devicehub gathers this information and computes a score that updates
|
||||
the ``Rate`` event.
|
||||
3. Devicehub aggregates different rates and computes a final score for
|
||||
the device by performing a new ``AggregateRating`` event.
|
||||
|
||||
There are two base **types** of ``Rate``: ``WorkbenchRate``,
|
||||
``ManualRate``. ``WorkbenchRate`` can have different
|
||||
**software** algorithms, and each software algorithm can have several
|
||||
**versions**. So, we have 3 dimensions for ``WorkbenchRate``:
|
||||
type, software, version.
|
||||
|
||||
Devicehub generates a rate event for each software and version. So,
|
||||
if an agent fulfills a ``WorkbenchRate`` and there are 2 software
|
||||
algorithms and each has two versions, Devicehub will generate 4 rates.
|
||||
Devicehub understands that only one software and version are the
|
||||
**oficial** (set in the settings of each inventory),
|
||||
and it will generate an ``AggregateRating`` for only the official
|
||||
versions. At the same time, ``Price`` only computes the price of
|
||||
the **oficial** version.
|
||||
|
||||
The technical Workflow in Devicehub is as follows:
|
||||
|
||||
1. In **T1**, the user performs a ``Snapshot`` by processing the device
|
||||
through the Workbench. From the benchmarks and the visual and
|
||||
functional ratings the user does in the device, the system generates
|
||||
many ``WorkbenchRate`` (as many as software and versions defined).
|
||||
With only this information, the system generates an ``AggregateRating``,
|
||||
which is the event that the user will see in the web.
|
||||
2. In **T2**, the agent can optionally visually re-rate the device
|
||||
using the mobile app, generating an ``AppRate``. This new
|
||||
action generates a new ``AggregateRating`` with the ``AppRate``
|
||||
plus the ``WorkbenchRate`` from 1.
|
||||
"""
|
||||
rating = Column(Float(decimal_return_scale=2), check_range('rating', *RATE_POSITIVE))
|
||||
rating.comment = """The rating for the content."""
|
||||
software = Column(DBEnum(RatingSoftware))
|
||||
|
@ -572,6 +738,16 @@ class AggregateRate(Rate):
|
|||
|
||||
|
||||
class Price(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
||||
"""Price states a selling price for the device, but not
|
||||
necessarily the final price this is sold (which is set in the Sell
|
||||
event).
|
||||
|
||||
Devicehub automatically computes a price from ``AggregateRating``
|
||||
events. As in a **Rate**, price can have **software** and **version**,
|
||||
and there is an **official** price that is used to automatically
|
||||
compute the price from an ``AggregateRating``. Only the official price
|
||||
is computed from an ``AggregateRating``.
|
||||
"""
|
||||
SCALE = 4
|
||||
ROUND = ROUND_HALF_EVEN
|
||||
currency = Column(DBEnum(Currency), nullable=False)
|
||||
|
@ -713,6 +889,12 @@ class EreusePrice(Price):
|
|||
|
||||
|
||||
class Test(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
||||
"""The act of testing the physical condition of a device and its
|
||||
components.
|
||||
|
||||
Testing errors and warnings are easily taken in
|
||||
:attr:`ereuse_devicehub.resources.device.models.Device.working`.
|
||||
"""
|
||||
elapsed = Column(Interval, nullable=False)
|
||||
|
||||
@declared_attr
|
||||
|
@ -731,6 +913,17 @@ class Test(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
|||
|
||||
|
||||
class TestDataStorage(Test):
|
||||
"""
|
||||
The act of testing the data storage.
|
||||
|
||||
Testing is done using the `S.M.A.R.T self test
|
||||
<https://en.wikipedia.org/wiki/S.M.A.R.T.#Self-tests>`_. Note
|
||||
that not all data storage units, specially some new PCIe ones, do not
|
||||
support SMART testing.
|
||||
|
||||
The test takes to other SMART values indicators of the overall health
|
||||
of the data storage.
|
||||
"""
|
||||
id = Column(UUID(as_uuid=True), ForeignKey(Test.id), primary_key=True)
|
||||
length = Column(DBEnum(TestDataStorageLength), nullable=False) # todo from type
|
||||
status = Column(Unicode(), check_lower('status'), nullable=False)
|
||||
|
@ -768,6 +961,10 @@ class TestDataStorage(Test):
|
|||
|
||||
|
||||
class StressTest(Test):
|
||||
"""The act of stressing (putting to the maximum capacity)
|
||||
a device for an amount of minutes. If the device is not in great
|
||||
condition won't probably survive such test.
|
||||
"""
|
||||
|
||||
@validates('elapsed')
|
||||
def is_minute_and_bigger_than_1_minute(self, _, value: timedelta):
|
||||
|
@ -781,6 +978,7 @@ class StressTest(Test):
|
|||
|
||||
|
||||
class Benchmark(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
||||
"""The act of gauging the performance of a device."""
|
||||
elapsed = Column(Interval)
|
||||
|
||||
@declared_attr
|
||||
|
@ -799,6 +997,7 @@ class Benchmark(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
|||
|
||||
|
||||
class BenchmarkDataStorage(Benchmark):
|
||||
"""Benchmarks the data storage unit reading and writing speeds."""
|
||||
id = Column(UUID(as_uuid=True), ForeignKey(Benchmark.id), primary_key=True)
|
||||
read_speed = Column(Float(decimal_return_scale=2), nullable=False)
|
||||
write_speed = Column(Float(decimal_return_scale=2), nullable=False)
|
||||
|
@ -808,6 +1007,7 @@ class BenchmarkDataStorage(Benchmark):
|
|||
|
||||
|
||||
class BenchmarkWithRate(Benchmark):
|
||||
"""The act of benchmarking a device with a single rate."""
|
||||
id = Column(UUID(as_uuid=True), ForeignKey(Benchmark.id), primary_key=True)
|
||||
rate = Column(Float, nullable=False)
|
||||
|
||||
|
@ -816,11 +1016,18 @@ class BenchmarkWithRate(Benchmark):
|
|||
|
||||
|
||||
class BenchmarkProcessor(BenchmarkWithRate):
|
||||
"""Benchmarks a processor by executing `BogoMips
|
||||
<https://en.wikipedia.org/wiki/BogoMips>`_. Note that this is not
|
||||
a reliable way of rating processors and we keep it for compatibility
|
||||
purposes.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class BenchmarkProcessorSysbench(BenchmarkProcessor):
|
||||
pass
|
||||
"""Benchmarks a processor by using the processor benchmarking
|
||||
utility of `sysbench <https://github.com/akopytov/sysbench>`_.
|
||||
"""
|
||||
|
||||
|
||||
class BenchmarkRamSysbench(BenchmarkWithRate):
|
||||
|
@ -828,26 +1035,54 @@ class BenchmarkRamSysbench(BenchmarkWithRate):
|
|||
|
||||
|
||||
class ToRepair(EventWithMultipleDevices):
|
||||
pass
|
||||
"""Select a device to be repaired."""
|
||||
|
||||
|
||||
class Repair(EventWithMultipleDevices):
|
||||
pass
|
||||
"""Repair is the act of performing reparations.
|
||||
|
||||
If a repair without an error is performed,
|
||||
it represents that the reparation has been successful.
|
||||
"""
|
||||
|
||||
|
||||
class ReadyToUse(EventWithMultipleDevices):
|
||||
pass
|
||||
"""The device is ready to be used.
|
||||
|
||||
This involves greater preparation from the ``Prepare`` event,
|
||||
and users should only use a device after this event is performed.
|
||||
|
||||
Users usually require devices with this event before shipping them
|
||||
to costumers.
|
||||
"""
|
||||
|
||||
|
||||
class ToPrepare(EventWithMultipleDevices):
|
||||
"""The device has been selected for preparation.
|
||||
|
||||
See Prepare for more info.
|
||||
|
||||
Usually **ToPrepare** is the next event done after registering the
|
||||
device.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class Prepare(EventWithMultipleDevices):
|
||||
pass
|
||||
"""Work has been performed to the device to a defined point of
|
||||
acceptance.
|
||||
|
||||
Users using this event have to agree what is this point
|
||||
of acceptance; for some is when the device just works, for others
|
||||
when some testing has been performed.
|
||||
"""
|
||||
|
||||
|
||||
class Live(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
||||
"""A keep-alive from a device connected to the Internet with
|
||||
information about its state (in the form of a ``Snapshot`` event)
|
||||
and usage statistics.
|
||||
"""
|
||||
ip = Column(IP, nullable=False,
|
||||
comment='The IP where the live was triggered.')
|
||||
subdivision_confidence = Column(SmallInteger,
|
||||
|
@ -870,18 +1105,34 @@ class Live(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
|||
|
||||
|
||||
class Organize(JoinedTableMixin, EventWithMultipleDevices):
|
||||
pass
|
||||
"""The act of manipulating/administering/supervising/controlling
|
||||
one or more devices.
|
||||
"""
|
||||
|
||||
|
||||
class Reserve(Organize):
|
||||
pass
|
||||
"""The act of reserving devices and cancelling them.
|
||||
|
||||
After this event is performed, the user is the **reservee** of the
|
||||
devices. There can only be one non-cancelled reservation for
|
||||
a device, and a reservation can only have one reservee.
|
||||
"""
|
||||
|
||||
|
||||
class CancelReservation(Organize):
|
||||
pass
|
||||
"""The act of cancelling a reservation."""
|
||||
|
||||
|
||||
class Trade(JoinedTableMixin, EventWithMultipleDevices):
|
||||
"""Trade actions log the political exchange of devices between users.
|
||||
Every time a trade event is performed, the old user looses its
|
||||
political possession, for example ownership, in favor of another
|
||||
user.
|
||||
|
||||
|
||||
Performing trade events changes the *Trading* state of the
|
||||
device —:class:`ereuse_devicehub.resources.device.states.Trading`.
|
||||
"""
|
||||
shipping_date = Column(DateTime)
|
||||
shipping_date.comment = """
|
||||
When are the devices going to be ready for shipping?
|
||||
|
@ -924,36 +1175,67 @@ class Trade(JoinedTableMixin, EventWithMultipleDevices):
|
|||
|
||||
|
||||
class Sell(Trade):
|
||||
pass
|
||||
"""The act of taking money from a buyer in exchange of a device."""
|
||||
|
||||
|
||||
class Donate(Trade):
|
||||
pass
|
||||
"""The act of giving devices without compensation."""
|
||||
|
||||
|
||||
class Rent(Trade):
|
||||
pass
|
||||
"""The act of giving money in return for temporary use, but not
|
||||
ownership, of a device.
|
||||
"""
|
||||
|
||||
|
||||
class CancelTrade(Trade):
|
||||
pass
|
||||
"""The act of cancelling a `Sell`_, `Donate`_ or `Rent`_."""
|
||||
# todo cancelTrade does not do anything
|
||||
|
||||
|
||||
class ToDisposeProduct(Trade):
|
||||
pass
|
||||
"""The act of setting a device for being disposed.
|
||||
|
||||
See :class:`.DisposeProduct`.
|
||||
"""
|
||||
# todo test this
|
||||
|
||||
|
||||
class DisposeProduct(Trade):
|
||||
pass
|
||||
"""The act of getting rid of devices by giving (selling, donating)
|
||||
to another organization, like a waste manager.
|
||||
|
||||
|
||||
See :class:`.ToDispose` and :class:`.DisposeProduct` for
|
||||
disposing without trading the device. See :class:`.DisposeWaste`
|
||||
and :class:`.Recover` for disposing in-house, this is,
|
||||
without trading the device.
|
||||
"""
|
||||
# todo For usability purposes, users might not directly perform
|
||||
# *DisposeProduct*, but this could automatically be done when
|
||||
# performing :class:`.ToDispose` + :class:`.Receive` to a
|
||||
# ``RecyclingCenter``.
|
||||
|
||||
|
||||
class Receive(JoinedTableMixin, EventWithMultipleDevices):
|
||||
"""The act of physically taking delivery of a device.
|
||||
|
||||
The receiver confirms that the devices have arrived, and thus,
|
||||
they are the
|
||||
:attr:`ereuse_devicehub.resources.device.models.Device.physical_possessor`.
|
||||
|
||||
The receiver can optionally take a
|
||||
:class:`ereuse_devicehub.resources.enums.ReceiverRole`.
|
||||
"""
|
||||
role = Column(DBEnum(ReceiverRole),
|
||||
nullable=False,
|
||||
default=ReceiverRole.Intermediary)
|
||||
|
||||
|
||||
class Migrate(JoinedTableMixin, EventWithMultipleDevices):
|
||||
"""Moves the devices to a new database/inventory. Devices cannot be
|
||||
modified anymore at the previous database.
|
||||
"""
|
||||
other = Column(URL(), nullable=False)
|
||||
other.comment = """
|
||||
The URL of the Migrate in the other end.
|
||||
|
|
|
@ -14,7 +14,7 @@ from teal.db import CASCADE_OWN, UUIDLtree
|
|||
from teal.resource import url_for_resource
|
||||
|
||||
from ereuse_devicehub.db import create_view, db
|
||||
from ereuse_devicehub.resources.device.models import Component, Computer, Device
|
||||
from ereuse_devicehub.resources.device.models import Component, Device
|
||||
from ereuse_devicehub.resources.models import Thing
|
||||
from ereuse_devicehub.resources.user.models import User
|
||||
|
||||
|
@ -90,16 +90,6 @@ class Lot(Thing):
|
|||
_id = UUIDLtree.convert(id)
|
||||
return (cls.id == Path.lot_id) & Path.path.lquery(exp.cast('*.{}.*'.format(_id), LQUERY))
|
||||
|
||||
@classmethod
|
||||
def device_in_lotq(cls):
|
||||
parent = Computer.__table__.alias()
|
||||
device_inside_lot = (Device.id == LotDevice.device_id) & (Lot.id == LotDevice.lot_id)
|
||||
parent_device_in_lot = (Device.id == Component.id) \
|
||||
& (Component.parent_id == parent.c.id) \
|
||||
& (parent.c.id == LotDevice.device_id) \
|
||||
& (Lot.id == LotDevice.lot_id)
|
||||
return device_inside_lot | parent_device_in_lot
|
||||
|
||||
@property
|
||||
def parents(self):
|
||||
return self.parentsq(self.id)
|
||||
|
|
|
@ -209,7 +209,6 @@ def test_update_parent():
|
|||
(models.Repair, states.Physical.Repaired),
|
||||
(models.ToPrepare, states.Physical.Preparing),
|
||||
(models.ReadyToUse, states.Physical.ReadyToBeUsed),
|
||||
(models.ToPrepare, states.Physical.Preparing),
|
||||
(models.Prepare, states.Physical.Prepared)
|
||||
])
|
||||
def test_generic_event(event_model_state: Tuple[models.Event, states.Trading], user: UserClient):
|
||||
|
|
Reference in New Issue