This is an automated email from the ASF dual-hosted git repository.

dstandish pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new 783aa9cecb Add `section` query param in get config rest API (#30936)
783aa9cecb is described below

commit 783aa9cecbf47b4d0e5509d1919f644b9689b6b3
Author: Pankaj Singh <[email protected]>
AuthorDate: Fri Apr 28 22:54:24 2023 +0530

    Add `section` query param in get config rest API (#30936)
---
 airflow/api_connexion/endpoints/config_endpoint.py |  9 ++++-
 airflow/api_connexion/openapi/v1.yaml              |  7 ++++
 airflow/www/static/js/types/api-generated.ts       |  9 +++++
 .../endpoints/test_config_endpoint.py              | 38 ++++++++++++++++++++++
 4 files changed, 62 insertions(+), 1 deletion(-)

diff --git a/airflow/api_connexion/endpoints/config_endpoint.py 
b/airflow/api_connexion/endpoints/config_endpoint.py
index a9353234f0..3f3d5de4ce 100644
--- a/airflow/api_connexion/endpoints/config_endpoint.py
+++ b/airflow/api_connexion/endpoints/config_endpoint.py
@@ -24,6 +24,7 @@ from airflow.api_connexion import security
 from airflow.api_connexion.exceptions import PermissionDenied
 from airflow.api_connexion.schemas.config_schema import Config, ConfigOption, 
ConfigSection, config_schema
 from airflow.configuration import conf
+from airflow.exceptions import AirflowNotFoundException
 from airflow.security import permissions
 from airflow.settings import json
 
@@ -67,7 +68,7 @@ def _config_to_json(config: Config) -> str:
 
 
 @security.requires_access([(permissions.ACTION_CAN_READ, 
permissions.RESOURCE_CONFIG)])
-def get_config() -> Response:
+def get_config(*, section: str | None = None) -> Response:
     """Get current configuration."""
     serializer = {
         "text/plain": _config_to_text,
@@ -77,7 +78,13 @@ def get_config() -> Response:
     if return_type not in serializer:
         return Response(status=HTTPStatus.NOT_ACCEPTABLE)
     elif conf.getboolean("webserver", "expose_config"):
+        if section and not conf.has_section(section):
+            raise AirflowNotFoundException(f"section={section} not found")
         conf_dict = conf.as_dict(display_source=False, display_sensitive=True)
+        if section:
+            conf_section_value = conf_dict[section]
+            conf_dict.clear()
+            conf_dict[section] = conf_section_value
         config = _conf_dict_to_config(conf_dict)
         config_text = serializer[return_type](config)
         return Response(config_text, headers={"Content-Type": return_type})
diff --git a/airflow/api_connexion/openapi/v1.yaml 
b/airflow/api_connexion/openapi/v1.yaml
index bcd96442dd..f7edbe3c13 100644
--- a/airflow/api_connexion/openapi/v1.yaml
+++ b/airflow/api_connexion/openapi/v1.yaml
@@ -1955,6 +1955,13 @@ paths:
       x-openapi-router-controller: 
airflow.api_connexion.endpoints.config_endpoint
       operationId: get_config
       tags: [Config]
+      parameters:
+        - name: section
+          in: query
+          schema:
+            type: string
+          required: false
+          description: If given, only return config of this section.
       responses:
         '200':
           description: Success.
diff --git a/airflow/www/static/js/types/api-generated.ts 
b/airflow/www/static/js/types/api-generated.ts
index df89725669..2439b7a610 100644
--- a/airflow/www/static/js/types/api-generated.ts
+++ b/airflow/www/static/js/types/api-generated.ts
@@ -4176,6 +4176,12 @@ export interface operations {
     };
   };
   get_config: {
+    parameters: {
+      query: {
+        /** If given, only return config of this section. */
+        section?: string;
+      };
+    };
     responses: {
       /** Success. */
       200: {
@@ -4989,6 +4995,9 @@ export type GetDatasetVariables = 
CamelCasedPropertiesDeep<
 export type GetDatasetEventsVariables = CamelCasedPropertiesDeep<
   operations["get_dataset_events"]["parameters"]["query"]
 >;
+export type GetConfigVariables = CamelCasedPropertiesDeep<
+  operations["get_config"]["parameters"]["query"]
+>;
 export type GetPluginsVariables = CamelCasedPropertiesDeep<
   operations["get_plugins"]["parameters"]["query"]
 >;
diff --git a/tests/api_connexion/endpoints/test_config_endpoint.py 
b/tests/api_connexion/endpoints/test_config_endpoint.py
index b611e02786..940cc3764c 100644
--- a/tests/api_connexion/endpoints/test_config_endpoint.py
+++ b/tests/api_connexion/endpoints/test_config_endpoint.py
@@ -105,6 +105,44 @@ class TestGetConfig:
         }
         assert expected == response.json
 
+    @patch("airflow.api_connexion.endpoints.config_endpoint.conf.as_dict", 
return_value=MOCK_CONF)
+    def test_should_respond_200_single_section_as_text_plain(self, 
mock_as_dict):
+        response = self.client.get(
+            "/api/v1/config?section=smtp",
+            headers={"Accept": "text/plain"},
+            environ_overrides={"REMOTE_USER": "test"},
+        )
+        assert response.status_code == 200
+        expected = textwrap.dedent(
+            """\
+        [smtp]
+        smtp_host = localhost
+        smtp_mail_from = [email protected]
+        """
+        )
+        assert expected == response.data.decode()
+
+    @patch("airflow.api_connexion.endpoints.config_endpoint.conf.as_dict", 
return_value=MOCK_CONF)
+    def test_should_respond_200_single_section_as_json(self, mock_as_dict):
+        response = self.client.get(
+            "/api/v1/config?section=smtp",
+            headers={"Accept": "application/json"},
+            environ_overrides={"REMOTE_USER": "test"},
+        )
+        assert response.status_code == 200
+        expected = {
+            "sections": [
+                {
+                    "name": "smtp",
+                    "options": [
+                        {"key": "smtp_host", "value": "localhost"},
+                        {"key": "smtp_mail_from", "value": 
"[email protected]"},
+                    ],
+                },
+            ]
+        }
+        assert expected == response.json
+
     @patch("airflow.api_connexion.endpoints.config_endpoint.conf.as_dict", 
return_value=MOCK_CONF)
     def test_should_respond_406(self, mock_as_dict):
         response = self.client.get(

Reply via email to