feat(task-service)!: add spec compliant task service support#107
Conversation
Adding this support for RMS firmware upload status checks. Signed-off-by: Jay Zhu <jayzhu@nvidia.com>
dbf067b to
8843eb4
Compare
Signed-off-by: Jay Zhu <jayzhu@nvidia.com>
7d49e50 to
815cfe1
Compare
| /// # Errors | ||
| /// | ||
| /// Returns error if retrieving task data fails. | ||
| pub async fn task(&self, task_path: impl ToString) -> Result<Arc<Task>, Error<B>> { |
There was a problem hiding this comment.
If I understand correctly then it is from Location header from the result of the operation. It would be nice to:
- Introduce type for a Location header value
- Use it here and task service should check that Location header value corresponds to its own odata.id.
This will express additional knowledge trough type system and better errors if somebody by mistake will use task service for non-task values (I think some vendors may have their own async job services, see Dell OEM jobs for example).
There was a problem hiding this comment.
Maybe we also should add separate function that can check that Location is valid Task resource.
There was a problem hiding this comment.
This is a very good and thoughtful call, thanks!
After some thinking, I see two options here:
-
add a Location type. The intent is clearer to the caller but it wouldn't prevent caller mistakes of calling a wrong task service instance - we would still need validation in
taskcalling. -
keep the API simple and only add validation inside TaskService::task(). The caller passes the task path, and TaskService checks it is under the BMC's Tasks collection before polling.
Option 2 seems to have the right tradeoff to me because the validation is task-specific, and TaskService already has the Tasks collection needed to do it.
Signed-off-by: Jay Zhu <jayzhu@nvidia.com>
Signed-off-by: Jay Zhu <jayzhu@nvidia.com>
| /// ``` | ||
| pub struct TaskService<B: Bmc> { | ||
| data: Arc<TaskServiceSchema>, | ||
| task_collection: TaskCollectionPath, |
There was a problem hiding this comment.
Think we should not keep this information inside TaskService. All information is in data (odata.id). Just add method to ODataId type that can check that one OdataId is_path_prefix for another. No need to trim_end_matheces etc. Just add one method here and use it is needed.
Line 51 in b5dc784
There was a problem hiding this comment.
Agreed, I've updated the implementation.
| use crate::schema::task_service::TaskService as TaskServiceSchema; | ||
|
|
||
| #[doc(inline)] | ||
| pub use crate::schema::task::Task; |
There was a problem hiding this comment.
nv-redfish has two concept:
- Full wrapper like Chassis where you have different custom methods
- Link that internally contains just odata-id reference for the object.
It seems that Task should be a link here:
| pub use crate::schema::task::Task; | |
| use crate::entity_link::EntityLink; | |
| use crate::schema::task::Task as TaskSchema; | |
| /// Link for accessing task. | |
| pub type TaskLink<B> = EntityLink<B, TaskSchema>; |
| /// | ||
| /// Returns error if the service does not expose a Tasks collection, if the | ||
| /// path is outside that collection, or if retrieving task data fails. | ||
| pub async fn task(&self, task_path: impl AsRef<str>) -> Result<Arc<Task>, Error<B>> { |
There was a problem hiding this comment.
use crate::core::AsyncTask;
| pub async fn task(&self, task_path: impl AsRef<str>) -> Result<Arc<Task>, Error<B>> { | |
| pub fn task_link(&self, async_task: AsyncTask) -> Result<TaskLink, Error<B>> { |
Internally task_link should check that task service odata id is parent path for AsyncTask::id and constructs link only if this is true.
Note that this method doesn't retrieve any data, just creates handle that can be used to retrieve data. See:
nv-redfish/redfish/src/entity_link.rs
Line 94 in b5dc784
There was a problem hiding this comment.
Thanks for sharing this! This utility seems to be the right pattern to use. I've updated the implementation.
…taId Add ODataId prefix checks and use them to validate async task links without caching path prefixes. Signed-off-by: Jay Zhu <jayzhu@nvidia.com>
| pub struct TaskService<B: Bmc> { | ||
| data: Arc<TaskServiceSchema>, | ||
| task_collection: TaskCollectionPath, | ||
| task_collection: ODataId, |
There was a problem hiding this comment.
This copy of odata_id is redundant. You can use data.odata_id() when this value is needed.
There was a problem hiding this comment.
Replaced it with data.tasks.odata_id.
| if !task_path.starts_with(self.task_collection.prefix.as_str()) { | ||
| /// Returns error if the task ID is not a child of this service's Tasks | ||
| /// collection. | ||
| pub fn task_link(&self, task: &AsyncTask) -> Result<TaskLink<B>, Error<B>> { |
There was a problem hiding this comment.
To avoid "clones" just use task: AsyncTask.
There was a problem hiding this comment.
The tradeoff is around consuming the task versus cloning just the id (current implementation). I chose the latter in case the caller still needs the task (for the retry_after_secs field).
Signed-off-by: Jay Zhu <jayzhu@nvidia.com>
If a caller needs other fields in the AsyncTask, it can choose to clone other fields or the entire AsyncTask before it's consumed by task_link. The idea is that task_link doesn't implicitly clone the ID string within the method - cloning happens based on the choice of the caller. Signed-off-by: Jay Zhu <jayzhu@nvidia.com>
Rename async task IDs to task locations, convert retry_after_secs to std::time::Duration, align TaskService errors, docs, examples, and tests with the new naming. Signed-off-by: Jay Zhu <jayzhu@nvidia.com>
8784288 to
79d1c27
Compare
Adding this support for RMS firmware upload status checks.
Breaking change:
task-servicefeature is enabled, the redfish::Error now has 2 new variants.