Skip to content

Commit 3b7ff66

Browse files
authored
[docs/ui] Improve docs of send commands API endpoint #1047
Closes #1047
1 parent 6b33d73 commit 3b7ff66

File tree

4 files changed

+135
-1
lines changed

4 files changed

+135
-1
lines changed

docs/user/rest-api.rst

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,13 +347,110 @@ List Commands of a Device
347347
348348
GET /api/v1/controller/device/{device_id}/command/
349349
350+
.. _controller_execute_command_api:
351+
350352
Execute a Command on a Device
351353
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
352354

353355
.. code-block:: text
354356
355357
POST /api/v1/controller/device/{device_id}/command/
356358
359+
This endpoint allows you to execute various types of commands on a device.
360+
361+
**Request Parameters**
362+
363+
============== ========================================================
364+
Parameter Description
365+
============== ========================================================
366+
``type`` The type of command to execute (**required**)
367+
``input`` Input data for the command (format varies by type)
368+
(**required**)
369+
``connection`` UUID of specific device connection to use (**optional**)
370+
============== ========================================================
371+
372+
The ``input`` field requires data in a specific format that depends on the
373+
command type being executed.
374+
375+
.. note::
376+
377+
The following examples show payloads for the default commands shipped
378+
with OpenWISP. The available commands on a device depend on your
379+
configuration of :ref:`OPENWISP_CONTROLLER_USER_COMMANDS
380+
<openwisp_controller_user_commands>` and
381+
:ref:`OPENWISP_CONTROLLER_ORGANIZATION_ENABLED_COMMANDS` settings. For
382+
detailed information about command execution, including how to add
383+
command types, and restrict available commands per organization, see
384+
:doc:`shell-commands`.
385+
386+
**Available Command Types**
387+
388+
1. **Custom Command** (``custom``)
389+
390+
Execute a custom command on the device.
391+
392+
**Input format:** ``{"command": "shell_command"}``
393+
394+
**Example payload:**
395+
396+
.. code-block:: json
397+
398+
{
399+
"type": "custom",
400+
"input": {
401+
"command": "iwinfo"
402+
}
403+
}
404+
405+
2. **Reboot** (``reboot``)
406+
407+
Reboot the device.
408+
409+
**Input format:** ``null`` (no input required)
410+
411+
**Example payload:**
412+
413+
.. code-block:: json
414+
415+
{
416+
"type": "reboot",
417+
"input": null
418+
}
419+
420+
3. **Change Password** (``change_password``)
421+
422+
Change the device's root password.
423+
424+
**Input format:** ``{"password": "new_pass", "confirm_password":
425+
"new_pass"}``
426+
427+
**Example payload:**
428+
429+
.. code-block:: json
430+
431+
{
432+
"type": "change_password",
433+
"input": {
434+
"password": "newpassword123",
435+
"confirm_password": "newpassword123"
436+
}
437+
}
438+
439+
**Example Request:**
440+
441+
.. code-block:: shell
442+
443+
curl -X POST \
444+
http://127.0.0.1:8000/api/v1/controller/device/76b7d9cc-4ffd-4a43-b1b0-8f8befd1a7c0/command/ \
445+
-H 'authorization: Bearer yoursecretauthtoken' \
446+
-H 'content-type: application/json' \
447+
-d '{
448+
"type": "custom",
449+
"input": {
450+
"command": "uptime"
451+
}
452+
}'
453+
357454
Get Command Details
358455
~~~~~~~~~~~~~~~~~~~
359456

docs/user/shell-commands.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ used often in your network regardless of your users' knowledge of Linux
3636
shell commands, you can add new commands by following instructions in the
3737
:ref:`defining_new_menu_options` section below.
3838

39+
.. note::
40+
41+
You can also use the `REST API <controller_execute_command_api>`_ to
42+
execute commands on a device.
43+
3944
.. note::
4045

4146
If you're an advanced user and want to learn how to register commands

openwisp_controller/connection/api/serializers.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from django.utils.safestring import mark_safe
2+
from django.utils.translation import gettext_lazy as _
13
from rest_framework import serializers
24
from swapper import load_model
35

@@ -20,7 +22,18 @@ def validate(self, data):
2022

2123

2224
class CommandSerializer(ValidatedDeviceFieldSerializer):
23-
input = serializers.JSONField(allow_null=True)
25+
input = serializers.JSONField(
26+
allow_null=True,
27+
help_text=mark_safe(
28+
_(
29+
"JSON object containing the command input data. "
30+
"The structure of this object depends on the command type. "
31+
'Refer to the <a href="https://openwisp.io/docs/dev/controller/'
32+
'user/rest-api.html#execute-a-command-on-a-device" target="_blank">'
33+
"OpenWISP documentation</a> for details."
34+
)
35+
),
36+
)
2437
device = serializers.PrimaryKeyRelatedField(
2538
read_only=True, pk_field=serializers.UUIDField(format="hex_verbose")
2639
)

openwisp_controller/connection/api/views.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
from django.core.exceptions import ValidationError
2+
from django.utils.translation import gettext_lazy as _
3+
from drf_yasg import openapi
4+
from drf_yasg.utils import swagger_auto_schema
25
from rest_framework import pagination
36
from rest_framework.exceptions import NotFound
47
from rest_framework.generics import (
@@ -73,6 +76,22 @@ def create(self, request, *args, **kwargs):
7376
self.assert_parent_exists()
7477
return super().create(request, *args, **kwargs)
7578

79+
@swagger_auto_schema(
80+
operation_description=_("Execute a command on a device"),
81+
operation_summary=_("Execute device command"),
82+
request_body=CommandSerializer,
83+
responses={
84+
201: openapi.Response(
85+
description=_("Command created successfully"),
86+
schema=CommandSerializer,
87+
),
88+
400: openapi.Response(description=_("Invalid request data")),
89+
404: openapi.Response(description=_("Device not found")),
90+
},
91+
)
92+
def post(self, request, *args, **kwargs):
93+
return super().post(request, *args, **kwargs)
94+
7695

7796
class CommandDetailsView(BaseCommandView, RetrieveAPIView):
7897
def get_object(self):

0 commit comments

Comments
 (0)