Repository: google/turbinia (language: python)

Issue:
[FR]: API server - provide endpoint "config download" to download original configuration
The current API call config.list will output the configuration as JSON by design. Provide endpoint that will output original Turbinia config file so it can be edited/re-used with Turbinia.


Discussion / hints:
Not a bug. That API output by design is JSON format.  It seems you're asking for a feature that just lets you download the configuration file instead.
Understood, rewritten and labeled as enhancement.

Fix patch:
diff --git a/turbinia/api/openapi.yaml b/turbinia/api/openapi.yaml
index b8c1282d7..a336b1d05 100644
--- a/turbinia/api/openapi.yaml
+++ b/turbinia/api/openapi.yaml
@@ -203,6 +203,20 @@ paths:
         summary: Get Version
         tags:
         - Turbinia Configuration
+  /api/config/download:
+      get:
+        description: Downloads the Turbinia configuration.
+        operationId: download_config
+        responses:
+          '200':
+            content:
+              application/text:
+                schema:
+                  type: string
+            description: Successful Response
+        summary: Download Configuration
+        tags:
+        - Turbinia Configuration
   /api/evidence/query:
     get:
       description: "Queries evidence in Redis that have the specified attribute value.\n\
diff --git a/turbinia/api/routes/config.py b/turbinia/api/routes/config.py
index e0579525f..02671903a 100644
--- a/turbinia/api/routes/config.py
+++ b/turbinia/api/routes/config.py
@@ -18,7 +18,7 @@
 import logging
 
 from fastapi import HTTPException, APIRouter
-from fastapi.responses import JSONResponse
+from fastapi.responses import JSONResponse, FileResponse
 from fastapi.requests import Request
 
 from turbinia import __version__
@@ -58,3 +58,16 @@ async def get_version(request: Request):
   """Returns the Turbinia version."""
   response = {'version': __version__}
   return JSONResponse(content=response, status_code=200)
+
+
+@router.get('/download')
+async def download_config(request: Request):
+  """Downloads Turbinia configuration."""
+  try:
+    path = turbinia_config.CONFIG.__file__
+    return FileResponse(path)
+  except Exception as exception:
+    log.error(f'Error reading configuration file: {exception!s}')
+    raise HTTPException(
+        status_code=500,
+        detail='Error reading configuration file') from exception


Test patch:
diff --git a/turbinia/api/api_server_test.py b/turbinia/api/api_server_test.py
index dde0b6828..2e0158a8f 100644
--- a/turbinia/api/api_server_test.py
+++ b/turbinia/api/api_server_test.py
@@ -209,6 +209,14 @@ def testGetConfig(self):
     response = self.client.get('/api/config')
     self.assertEqual(response.json(), config_dict)
 
+  def testDownloadConfig(self):
+    """Test downloading current Turbinia server config."""
+    with open(turbinia_config.CONFIG.__file__, mode='r',
+              encoding='utf-8') as file:
+      content = ''.join(file.readlines())
+    response = self.client.get('/api/config/download')
+    self.assertEqual(response.text, content)
+
   def testRequestResultsNotFound(self):
     """Test getting empty request result files."""
     request_id = self._REQUEST_STATUS_TEST_DATA.get('request_id')