ryerraguntla commented on code in PR #4398:
URL: https://github.com/apache/iggy/pull/4398#discussion_r4205908043


##########
gateways/kafka/README.md:
##########
@@ -1,11 +1,12 @@
 # Kafka gateway (`iggy-gateway-kafka`)
 
-Foundation layer for 
[apache/iggy#3421](https://github.com/apache/iggy/issues/3421): a TCP listener 
on the Kafka wire port that decodes requests and validates scoped API keys and 
versions. With a bridge, Produce, Fetch, ListOffsets, Metadata and CreateTopics 
use Iggy. InitProducerId and consumer group coordination work with or without 
one.
+Foundation layer for 
[apache/iggy#3421](https://github.com/apache/iggy/issues/3421): a TCP listener 
on the Kafka wire port that decodes requests and validates scoped API keys and 
versions. With a bridge, Produce, Fetch, ListOffsets, Metadata, CreateTopics, 
DescribeConfigs and AlterConfigs use Iggy. InitProducerId and consumer group 
coordination work with or without one.
 
-> **Stub warning:** with `IGGY_KAFKA_BRIDGE_ENABLED=true`, Produce, Fetch, 
ListOffsets, Metadata and
-> CreateTopics use Iggy. With the bridge off (the default), those five are 
stubs: Produce, Fetch and
-> ListOffsets answer retriable `NOT_LEADER_OR_FOLLOWER` (6), CreateTopics 
answers `NOT_CONTROLLER`
-> (41), and Metadata reports every requested topic unknown. **CreateTopics 
runs as the bridge's own
+> **Stub warning:** with `IGGY_KAFKA_BRIDGE_ENABLED=true`, Produce, Fetch, 
ListOffsets, Metadata,
+> CreateTopics, DescribeConfigs and AlterConfigs use Iggy. With the bridge off 
(the default), those
+> seven are stubs: Produce, Fetch and ListOffsets answer retriable 
`NOT_LEADER_OR_FOLLOWER` (6),
+> CreateTopics, DescribeConfigs and AlterConfigs answer `NOT_CONTROLLER` (41), 
and Metadata reports
+> every requested topic unknown. **CreateTopics runs as the bridge's own

Review Comment:
   fixed



##########
gateways/kafka/src/protocol/handlers/describe_configs.rs:
##########
@@ -0,0 +1,693 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+//! `DescribeConfigs` (API key 32).
+
+use bytes::Bytes;
+use iggy::prelude::{IggyExpiry, ResourceOptions};
+use kafka_protocol::messages::DescribeConfigsRequest;
+use 
kafka_protocol::messages::describe_configs_request::DescribeConfigsResource;
+use kafka_protocol::messages::describe_configs_response::{
+    DescribeConfigsResourceResult, DescribeConfigsResponse, 
DescribeConfigsResult,
+    DescribeConfigsSynonym,
+};
+use kafka_protocol::protocol::StrBytes;
+use tokio::time::Instant;
+
+use crate::bridge::topic_map::validate_kafka_topic_name;
+use crate::bridge::{IggyBridge, StreamTopicCache, TopicLoad};
+use crate::protocol::api::{
+    API_KEY_DESCRIBE_CONFIGS, ApiVersionRange, ERROR_INVALID_CONFIG, 
ERROR_INVALID_REQUEST,
+    ERROR_INVALID_TOPIC_EXCEPTION, ERROR_NONE, ERROR_NOT_CONTROLLER, 
ERROR_POLICY_VIOLATION,
+    ERROR_REQUEST_TIMED_OUT, ERROR_UNKNOWN_TOPIC_OR_PARTITION, GatewayState, 
HandleOutcome,
+    REQUEST_DEADLINE,
+};
+use crate::protocol::bounds_guard::validate_describe_configs_shape;
+use crate::protocol::handlers::topic_config::{
+    CLEANUP_DOC, CLEANUP_POLICY, CLEANUP_POLICY_VALUE, CONFIG_SOURCE_DEFAULT, 
CONFIG_SOURCE_TOPIC,
+    CONFIG_TYPE_LONG, CONFIG_TYPE_STRING, IggyTopicKey, ListedKey, 
MILLIS_PER_HOUR,
+    MILLIS_PER_MINUTE, ONLY_TOPIC_RESOURCES, RESOURCE_TYPE_TOPIC, 
RETENTION_DOC, RETENTION_HOURS,
+    RETENTION_HOURS_DOC, RETENTION_MINUTES, RETENTION_MINUTES_DOC, 
RETENTION_MS, RetentionMs,
+    RetentionSynonyms, bridge_failure, exceeds_topic_cap, 
find_duplicate_names, listed_keys,
+    message_expiry_is_explicit, name_reason, retention_in_unit, retention_ms, 
static_text,
+    topic_cap_message,
+};
+use crate::protocol::handlers::{
+    decode_guarded, encode_message, is_supported_version, respond_or_close,
+    unsupported_version_response,
+};
+
+pub const RANGE: ApiVersionRange = ApiVersionRange {
+    api_key: API_KEY_DESCRIBE_CONFIGS,
+    min_version: 1,
+    max_version: 4,
+};
+
+pub async fn handle(state: &GatewayState, api_version: i16, body: Bytes) -> 
HandleOutcome {
+    if !is_supported_version(API_KEY_DESCRIBE_CONFIGS, api_version) {
+        return unsupported_version_response(API_KEY_DESCRIBE_CONFIGS, 
api_version, |version| {
+            encode_error_response(version, ERROR_INVALID_REQUEST)
+        });
+    }
+
+    let req = match decode_guarded::<DescribeConfigsRequest>(api_version, 
body, |version, body| {
+        validate_describe_configs_shape(version, body, state.max_frame_size)
+    }) {
+        Ok(req) => req,
+        Err(error) => {
+            tracing::debug!(%error, "Failed to decode DescribeConfigs 
request");
+            return respond_or_close(
+                encode_error_response(api_version, ERROR_INVALID_REQUEST),
+                "DescribeConfigs",
+            );
+        }
+    };
+
+    let Some(bridge) = &state.bridge else {
+        let results = req
+            .resources
+            .iter()
+            .map(|resource| resource_error(resource, ERROR_NOT_CONTROLLER, 
None, Vec::new()))
+            .collect();
+        return respond_or_close(
+            encode_message(&response(results), api_version, 256),
+            "DescribeConfigs",
+        );
+    };
+
+    let deadline = Instant::now() + REQUEST_DEADLINE;
+    let results = describe_all(state, bridge, &req, deadline).await;
+    respond_or_close(
+        encode_message(&response(results), api_version, 256),
+        "DescribeConfigs",
+    )
+}
+
+/// # Errors
+///
+/// Returns an error when `kafka_protocol` cannot encode the response at 
`version`.
+pub fn encode_error_response(version: i16, error_code: i16) -> 
crate::error::Result<Bytes> {
+    let results = vec![
+        DescribeConfigsResult::default()
+            .with_error_code(error_code)
+            .with_error_message(None)
+            .with_resource_type(RESOURCE_TYPE_TOPIC)
+            .with_resource_name(StrBytes::from_static_str(""))
+            .with_configs(Vec::new()),
+    ];
+    encode_message(&response(results), version, 128)
+}
+
+fn response(results: Vec<DescribeConfigsResult>) -> DescribeConfigsResponse {
+    DescribeConfigsResponse::default()
+        .with_throttle_time_ms(0)
+        .with_results(results)
+}
+
+async fn describe_all(
+    state: &GatewayState,
+    bridge: &IggyBridge,
+    req: &DescribeConfigsRequest,
+    deadline: Instant,
+) -> Vec<DescribeConfigsResult> {
+    if !req.unknown_tagged_fields.is_empty() {

Review Comment:
   fixed



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to