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

xiangfu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git


The following commit(s) were added to refs/heads/master by this push:
     new df4d33b747 [timeseries] Adding working E2E quickstart for 
TimeSeriesEngineAuth (#16169)
df4d33b747 is described below

commit df4d33b74783058465c0a34cba483df790758ac8
Author: Shaurya Chaturvedi <[email protected]>
AuthorDate: Sun Jun 22 12:25:18 2025 -0700

    [timeseries] Adding working E2E quickstart for TimeSeriesEngineAuth (#16169)
    
    * [timeseries] Adding working E2E quickstart for TimeSeriesEngineAuth
    
    * Added license header
    
    * Added script info to time series quickstart classes
    
    * Addressed comments
    
    ---------
    
    Co-authored-by: Shaurya Chaturvedi <[email protected]>
---
 .../org/apache/pinot/tools/AuthQuickstart.java     | 39 +--------
 .../tools/TimeSeriesEngineAuthQuickStart.java      | 62 ++++++++++++++
 .../pinot/tools/TimeSeriesEngineQuickStart.java    | 10 ++-
 .../tools/admin/command/QuickstartRunner.java      |  7 ++
 .../{AuthQuickstart.java => utils/AuthUtils.java}  | 45 +++--------
 .../main/resources/scripts/timeseries/query.txt    |  4 +
 .../resources/scripts/timeseries/run_ts_query.py   | 94 ++++++++++++++++++++++
 7 files changed, 190 insertions(+), 71 deletions(-)

diff --git 
a/pinot-tools/src/main/java/org/apache/pinot/tools/AuthQuickstart.java 
b/pinot-tools/src/main/java/org/apache/pinot/tools/AuthQuickstart.java
index 4930c8f6b0..303d10bce7 100644
--- a/pinot-tools/src/main/java/org/apache/pinot/tools/AuthQuickstart.java
+++ b/pinot-tools/src/main/java/org/apache/pinot/tools/AuthQuickstart.java
@@ -26,6 +26,7 @@ import org.apache.pinot.common.auth.AuthProviderUtils;
 import org.apache.pinot.common.auth.BasicAuthUtils;
 import org.apache.pinot.spi.auth.AuthProvider;
 import org.apache.pinot.spi.plugin.PluginManager;
+import org.apache.pinot.tools.utils.AuthUtils;
 
 
 public class AuthQuickstart extends Quickstart {
@@ -42,43 +43,7 @@ public class AuthQuickstart extends Quickstart {
   @Override
   public Map<String, Object> getConfigOverrides() {
     Map<String, Object> properties = new HashMap<>(super.getConfigOverrides());
-
-    // controller
-    properties.put("pinot.controller.segment.fetcher.auth.token", "Basic 
YWRtaW46dmVyeXNlY3JldA==");
-    properties.put("controller.admin.access.control.factory.class",
-        
"org.apache.pinot.controller.api.access.BasicAuthAccessControlFactory");
-    properties.put("controller.admin.access.control.principals", "admin, user, 
service, tableonly");
-    
properties.put("controller.admin.access.control.principals.admin.password", 
"verysecret");
-    
properties.put("controller.admin.access.control.principals.service.password", 
"verysecrettoo");
-    properties.put("controller.admin.access.control.principals.user.password", 
"secret");
-    
properties.put("controller.admin.access.control.principals.user.permissions", 
"READ");
-    
properties.put("controller.admin.access.control.principals.tableonly.password", 
"secrettoo");
-    
properties.put("controller.admin.access.control.principals.tableonly.permissions",
 "READ");
-    
properties.put("controller.admin.access.control.principals.tableonly.tables", 
"baseballStats");
-
-    // broker
-    properties.put("pinot.broker.access.control.class", 
"org.apache.pinot.broker.broker.BasicAuthAccessControlFactory");
-    properties.put("pinot.broker.access.control.principals", "admin, user, 
service, tableonly");
-    properties.put("pinot.broker.access.control.principals.admin.password", 
"verysecret");
-    properties.put("pinot.broker.access.control.principals.service.password", 
"verysecrettoo");
-    properties.put("pinot.broker.access.control.principals.user.password", 
"secret");
-    
properties.put("pinot.broker.access.control.principals.tableonly.password", 
"secrettoo");
-    properties.put("pinot.broker.access.control.principals.tableonly.tables", 
"baseballStats");
-
-    // server
-    properties.put("pinot.server.segment.fetcher.auth.token", "Basic 
YWRtaW46dmVyeXNlY3JldA==");
-    properties.put("pinot.server.segment.uploader.auth.token", "Basic 
YWRtaW46dmVyeXNlY3JldA==");
-    properties.put("pinot.server.instance.auth.token", "Basic 
YWRtaW46dmVyeXNlY3JldA==");
-
-    // minion
-    properties.put("segment.fetcher.auth.token", "Basic 
YWRtaW46dmVyeXNlY3JldA==");
-    properties.put("task.auth.token", "Basic YWRtaW46dmVyeXNlY3JldA==");
-
-    // loggers
-    properties.put("pinot.controller.logger.root.dir", "logs");
-    properties.put("pinot.broker.logger.root.dir", "logs");
-    properties.put("pinot.server.logger.root.dir", "logs");
-    properties.put("pinot.minion.logger.root.dir", "logs");
+    properties.putAll(AuthUtils.getAuthQuickStartDefaultConfigs());
     return properties;
   }
 
diff --git 
a/pinot-tools/src/main/java/org/apache/pinot/tools/TimeSeriesEngineAuthQuickStart.java
 
b/pinot-tools/src/main/java/org/apache/pinot/tools/TimeSeriesEngineAuthQuickStart.java
new file mode 100644
index 0000000000..f34e9c2e08
--- /dev/null
+++ 
b/pinot-tools/src/main/java/org/apache/pinot/tools/TimeSeriesEngineAuthQuickStart.java
@@ -0,0 +1,62 @@
+/**
+ * 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.
+ */
+package org.apache.pinot.tools;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.pinot.common.auth.AuthProviderUtils;
+import org.apache.pinot.common.auth.BasicAuthUtils;
+import org.apache.pinot.spi.auth.AuthProvider;
+import org.apache.pinot.spi.plugin.PluginManager;
+import org.apache.pinot.tools.utils.AuthUtils;
+
+
+/**
+ * Quick start for Time Series Engine with authentication.
+ *
+ * To test this quick start, you can run the following command in 
pinot-tools/src/main/resources/scripts/timeseries/
+ * python3 run_ts_query.py --auth
+ */
+public class TimeSeriesEngineAuthQuickStart extends TimeSeriesEngineQuickStart 
{
+
+  @Override
+  public List<String> types() {
+    return Collections.singletonList("TIME_SERIES_AUTH");
+  }
+
+  @Override
+  public AuthProvider getAuthProvider() {
+    return 
AuthProviderUtils.makeAuthProvider(BasicAuthUtils.toBasicAuthToken("admin", 
"verysecret"));
+  }
+
+  @Override
+  public Map<String, Object> getConfigOverrides() {
+    Map<String, Object> properties = new HashMap<>(super.getConfigOverrides());
+    properties.putAll(AuthUtils.getAuthQuickStartDefaultConfigs());
+    return properties;
+  }
+
+  public static void main(String[] args) throws Exception {
+    PluginManager.get().init();
+    new TimeSeriesEngineAuthQuickStart().execute();
+    printStatus(Color.GREEN, "Default login credential to login controller is 
admin/verysecret.");
+  }
+}
diff --git 
a/pinot-tools/src/main/java/org/apache/pinot/tools/TimeSeriesEngineQuickStart.java
 
b/pinot-tools/src/main/java/org/apache/pinot/tools/TimeSeriesEngineQuickStart.java
index b64bec82f8..2a81a5cce2 100644
--- 
a/pinot-tools/src/main/java/org/apache/pinot/tools/TimeSeriesEngineQuickStart.java
+++ 
b/pinot-tools/src/main/java/org/apache/pinot/tools/TimeSeriesEngineQuickStart.java
@@ -29,7 +29,12 @@ import org.apache.pinot.tools.admin.command.QuickstartRunner;
 import org.apache.pinot.tsdb.spi.PinotTimeSeriesConfiguration;
 import org.apache.pinot.tsdb.spi.series.SimpleTimeSeriesBuilderFactory;
 
-
+/**
+ * Quick start for Time Series Engine.
+ *
+ * To test this quick start, you can run the following command in 
pinot-tools/src/main/resources/scripts/timeseries/
+ * python3 run_ts_query.py
+ */
 public class TimeSeriesEngineQuickStart extends Quickstart {
   private static final String[] TIME_SERIES_TABLE_DIRECTORIES = new String[]{
       "examples/batch/airlineStats",
@@ -77,7 +82,8 @@ public class TimeSeriesEngineQuickStart extends Quickstart {
     Preconditions.checkState(quickstartRunnerDir.mkdirs());
     List<QuickstartTableRequest> quickstartTableRequests = 
bootstrapStreamTableDirectories(quickstartTmpDir);
     final QuickstartRunner runner =
-        new QuickstartRunner(quickstartTableRequests, 1, 1, 2, 1, 
quickstartRunnerDir, getConfigOverrides());
+        new QuickstartRunner(quickstartTableRequests, 1, 1, 2, 1, 
quickstartRunnerDir, getConfigOverrides(),
+          getAuthProvider());
 
     startKafka();
     startAllDataStreams(_kafkaStarter, quickstartTmpDir);
diff --git 
a/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/QuickstartRunner.java
 
b/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/QuickstartRunner.java
index 85a878b936..2d396ec46a 100644
--- 
a/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/QuickstartRunner.java
+++ 
b/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/QuickstartRunner.java
@@ -91,6 +91,13 @@ public class QuickstartRunner {
         true, Map.of());
   }
 
+  public QuickstartRunner(List<QuickstartTableRequest> tableRequests, int 
numControllers, int numBrokers,
+    int numServers, int numMinions, File tempDir, Map<String, Object> 
configOverrides, AuthProvider authProvider)
+    throws Exception {
+    this(tableRequests, numControllers, numBrokers, numServers, numMinions, 
tempDir, true, authProvider,
+      configOverrides, null, true, Map.of());
+  }
+
   public QuickstartRunner(List<QuickstartTableRequest> tableRequests, int 
numControllers, int numBrokers,
       int numServers, int numMinions, File tempDir, boolean enableIsolation, 
AuthProvider authProvider,
       Map<String, Object> configOverrides, String zkExternalAddress, boolean 
deleteExistingData,
diff --git 
a/pinot-tools/src/main/java/org/apache/pinot/tools/AuthQuickstart.java 
b/pinot-tools/src/main/java/org/apache/pinot/tools/utils/AuthUtils.java
similarity index 66%
copy from pinot-tools/src/main/java/org/apache/pinot/tools/AuthQuickstart.java
copy to pinot-tools/src/main/java/org/apache/pinot/tools/utils/AuthUtils.java
index 4930c8f6b0..82081b990a 100644
--- a/pinot-tools/src/main/java/org/apache/pinot/tools/AuthQuickstart.java
+++ b/pinot-tools/src/main/java/org/apache/pinot/tools/utils/AuthUtils.java
@@ -16,37 +16,24 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.pinot.tools;
+package org.apache.pinot.tools.utils;
 
-import java.util.Collections;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
-import org.apache.pinot.common.auth.AuthProviderUtils;
-import org.apache.pinot.common.auth.BasicAuthUtils;
-import org.apache.pinot.spi.auth.AuthProvider;
-import org.apache.pinot.spi.plugin.PluginManager;
 
 
-public class AuthQuickstart extends Quickstart {
-  @Override
-  public List<String> types() {
-    return Collections.singletonList("AUTH");
-  }
+public class AuthUtils {
+  private static final String DEFAULT_AUTH_TOKEN = "Basic 
YWRtaW46dmVyeXNlY3JldA==";
 
-  @Override
-  public AuthProvider getAuthProvider() {
-    return 
AuthProviderUtils.makeAuthProvider(BasicAuthUtils.toBasicAuthToken("admin", 
"verysecret"));
+  private AuthUtils() {
   }
 
-  @Override
-  public Map<String, Object> getConfigOverrides() {
-    Map<String, Object> properties = new HashMap<>(super.getConfigOverrides());
-
+  public static Map<String, Object> getAuthQuickStartDefaultConfigs() {
+    Map<String, Object> properties = new HashMap<>();
     // controller
-    properties.put("pinot.controller.segment.fetcher.auth.token", "Basic 
YWRtaW46dmVyeXNlY3JldA==");
+    properties.put("pinot.controller.segment.fetcher.auth.token", 
DEFAULT_AUTH_TOKEN);
     properties.put("controller.admin.access.control.factory.class",
-        
"org.apache.pinot.controller.api.access.BasicAuthAccessControlFactory");
+      "org.apache.pinot.controller.api.access.BasicAuthAccessControlFactory");
     properties.put("controller.admin.access.control.principals", "admin, user, 
service, tableonly");
     
properties.put("controller.admin.access.control.principals.admin.password", 
"verysecret");
     
properties.put("controller.admin.access.control.principals.service.password", 
"verysecrettoo");
@@ -66,13 +53,13 @@ public class AuthQuickstart extends Quickstart {
     properties.put("pinot.broker.access.control.principals.tableonly.tables", 
"baseballStats");
 
     // server
-    properties.put("pinot.server.segment.fetcher.auth.token", "Basic 
YWRtaW46dmVyeXNlY3JldA==");
-    properties.put("pinot.server.segment.uploader.auth.token", "Basic 
YWRtaW46dmVyeXNlY3JldA==");
-    properties.put("pinot.server.instance.auth.token", "Basic 
YWRtaW46dmVyeXNlY3JldA==");
+    properties.put("pinot.server.segment.fetcher.auth.token", 
DEFAULT_AUTH_TOKEN);
+    properties.put("pinot.server.segment.uploader.auth.token", 
DEFAULT_AUTH_TOKEN);
+    properties.put("pinot.server.instance.auth.token", DEFAULT_AUTH_TOKEN);
 
     // minion
-    properties.put("segment.fetcher.auth.token", "Basic 
YWRtaW46dmVyeXNlY3JldA==");
-    properties.put("task.auth.token", "Basic YWRtaW46dmVyeXNlY3JldA==");
+    properties.put("segment.fetcher.auth.token", DEFAULT_AUTH_TOKEN);
+    properties.put("task.auth.token", DEFAULT_AUTH_TOKEN);
 
     // loggers
     properties.put("pinot.controller.logger.root.dir", "logs");
@@ -81,10 +68,4 @@ public class AuthQuickstart extends Quickstart {
     properties.put("pinot.minion.logger.root.dir", "logs");
     return properties;
   }
-
-  public static void main(String[] args)
-      throws Exception {
-    PluginManager.get().init();
-    new AuthQuickstart().execute();
-  }
 }
diff --git a/pinot-tools/src/main/resources/scripts/timeseries/query.txt 
b/pinot-tools/src/main/resources/scripts/timeseries/query.txt
new file mode 100644
index 0000000000..25b5e4564f
--- /dev/null
+++ b/pinot-tools/src/main/resources/scripts/timeseries/query.txt
@@ -0,0 +1,4 @@
+fetch{table="meetupRsvp_REALTIME",filter="",ts_column="__metadata$recordTimestamp",ts_unit="MILLISECONDS",value="1"}
+  | max{group_city}
+  | transformNull{0}
+  | keepLastValue{}
\ No newline at end of file
diff --git a/pinot-tools/src/main/resources/scripts/timeseries/run_ts_query.py 
b/pinot-tools/src/main/resources/scripts/timeseries/run_ts_query.py
new file mode 100644
index 0000000000..c261992e76
--- /dev/null
+++ b/pinot-tools/src/main/resources/scripts/timeseries/run_ts_query.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+
+import argparse
+import requests
+import time
+import logging
+import sys
+
+# === Constants ===
+DEFAULT_QUERY_FILE = "query.txt"
+DEFAULT_API_URL = "http://localhost:8000/timeseries/api/v1/query_range";
+DEFAULT_DURATION_SECONDS = 3600
+AUTH_TOKEN = "Basic YWRtaW46dmVyeXNlY3JldA=="
+
+# === Logger Setup ===
+def setup_logger():
+    logger = logging.getLogger("TimeseriesQuery")
+    handler = logging.StreamHandler(sys.stdout)
+    formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
+    handler.setFormatter(formatter)
+    logger.setLevel(logging.INFO)
+    logger.addHandler(handler)
+    return logger
+
+# === File Reader ===
+def read_query_file(path, logger):
+    try:
+        with open(path, 'r') as f:
+            return f.read()
+    except Exception as e:
+        logger.error(f"Failed to read query file '{path}': {e}")
+        sys.exit(1)
+
+# === Request Builder ===
+def build_request(query, start, end, token=None):
+    params = {
+        'language': 'm3ql',
+        'start': start,
+        'end': end,
+        'query': query
+    }
+    headers = {}
+    if token:
+        headers['Authorization'] = token
+    return params, headers
+
+# === Main Entry ===
+def main():
+    parser = argparse.ArgumentParser(description="Query a time series API 
endpoint.")
+    parser.add_argument('--query-file', default=DEFAULT_QUERY_FILE, 
help=f'Path to the query file (default: {DEFAULT_QUERY_FILE})')
+    parser.add_argument('--url', default=DEFAULT_API_URL, help=f'API endpoint 
URL (default: {DEFAULT_API_URL})')
+    parser.add_argument('--auth', action='store_true', help='Enable 
Authorization header using default token')
+    parser.add_argument('--duration', type=int, 
default=DEFAULT_DURATION_SECONDS, help=f'Query time range duration in seconds 
(default: {DEFAULT_DURATION_SECONDS})')
+    args = parser.parse_args()
+
+    logger = setup_logger()
+    logger.info(f"Using query file: {args.query_file}")
+    query = read_query_file(args.query_file, logger)
+
+    start_time = int(time.time())
+    end_time = start_time + args.duration
+
+    token = AUTH_TOKEN if args.auth else None
+    params, headers = build_request(query, start_time, end_time, token)
+
+    try:
+        logger.info(f"Sending request to {args.url}")
+        response = requests.get(args.url, params=params, headers=headers)
+        logger.info(f"Response text: {response.text}")
+        response.raise_for_status()
+    except requests.RequestException as e:
+        logger.error(f"Request failed: {e}")
+        sys.exit(1)
+
+if __name__ == '__main__':
+    main()


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to