Skip to content
Open
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b7dcd56
* Add boilerplate
ag-ramachandran Sep 2, 2025
420a906
* Add boilerplate and code generator
ag-ramachandran Sep 2, 2025
ab0d587
* Add boilerplate and code generator
ag-ramachandran Sep 2, 2025
8badc85
* Edits to code
ag-ramachandran Sep 3, 2025
67c8b15
* Edits to code
ag-ramachandran Sep 3, 2025
6f8a41c
* Move code forward
ag-ramachandran Sep 8, 2025
d7f4662
* Move code forward
ag-ramachandran Sep 8, 2025
3f34273
*Additional edits
ag-ramachandran Sep 9, 2025
847e7dc
*Additional edits
ag-ramachandran Sep 9, 2025
2215353
*Additional edits
ag-ramachandran Sep 9, 2025
dff5d6c
*Add tests
ag-ramachandran Sep 9, 2025
503c93b
*Add changes to content negotiation
ag-ramachandran Sep 9, 2025
9036adc
Remove Java8 from the test matrix
ag-ramachandran Sep 10, 2025
8d554ad
*Update tests and POM
ag-ramachandran Sep 10, 2025
73afddd
*Minor edits
ag-ramachandran Sep 10, 2025
428b46a
*Reformat code
ag-ramachandran Sep 10, 2025
75c6545
* Remove gitignore
ag-ramachandran Sep 18, 2025
c28e9fa
*Address some of the review comments
ag-ramachandran Sep 18, 2025
1794659
* Fix some more review comments
ag-ramachandran Sep 26, 2025
723a166
* Fix comments and push this as the base branch for IngestV2
ag-ramachandran Oct 16, 2025
635fb8d
* Reformat code changes
ag-ramachandran Oct 16, 2025
9d9f336
* Rename retry data class
ag-ramachandran Oct 16, 2025
8cc94f5
* Rename retry data class
ag-ramachandran Oct 16, 2025
87f4fed
* Remove unused classes
ag-ramachandran Oct 30, 2025
dca3002
* Remove unused classes
ag-ramachandran Oct 30, 2025
31ff143
* Fix comment on substring chaining
ag-ramachandran Oct 31, 2025
b484e73
Feature/add ingestion source blob (#440)
tanmaya-panda1 Dec 2, 2025
5ac8080
Feature/add local file source v2 (#443)
tanmaya-panda1 Dec 2, 2025
dc308e1
disabled serialized execution
tanmaya-panda1 Dec 3, 2025
533cd35
optimized QueuedIngestionClientTests execution
tanmaya-panda1 Dec 4, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
contents: read
strategy:
matrix:
java: ['8', '11','17','21']
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you remove java 8?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

initial thought:

Some internal projects (spark specifically) were using Java8. However newer distributions start at 11 (and are moving to 17 as well).

java: ['11','17','21']
name: Java ${{ matrix.java }}
steps:
- name: Azure login
Expand Down
16 changes: 0 additions & 16 deletions data/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,6 @@
<version>${revision}</version>
</parent>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-sdk-bom</artifactId>
<version>${azure-bom-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<build>
<plugins>
<plugin>
Expand Down Expand Up @@ -187,12 +175,10 @@
<dependency>
<artifactId>jackson-databind</artifactId>
<groupId>com.fasterxml.jackson.core</groupId>
<version>${fasterxml.jackson.core.version}</version>
</dependency>
<dependency>
<artifactId>jackson-annotations</artifactId>
<groupId>com.fasterxml.jackson.core</groupId>
<version>${fasterxml.jackson.core.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
Expand Down Expand Up @@ -245,12 +231,10 @@
<dependency>
<artifactId>jackson-core</artifactId>
<groupId>com.fasterxml.jackson.core</groupId>
<version>${fasterxml.jackson.core.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>${fasterxml.jackson.core.version}</version>
</dependency>
<dependency>
<groupId>io.github.resilience4j</groupId>
Expand Down
38 changes: 38 additions & 0 deletions ingest-v2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# ingest-v2

This project was created using the [Ktor Project Generator](https://start.ktor.io).

Here are some useful links to get you started:

- [Ktor Documentation](https://ktor.io/docs/home.html)
- [Ktor GitHub page](https://github.com/ktorio/ktor)
- The [Ktor Slack chat](https://app.slack.com/client/T09229ZC6/C0A974TJ9). You'll need to [request an invite](https://surveys.jetbrains.com/s3/kotlin-slack-sign-up) to join.

## Features

Here's a list of features included in this project:

| Name | Description |
|------------------------------------------------------------------------|------------------------------------------------------------------------------------|
| [Content Negotiation](https://start.ktor.io/p/content-negotiation) | Provides automatic content conversion according to Content-Type and Accept headers |
| [Routing](https://start.ktor.io/p/routing) | Provides a structured routing DSL |
| [kotlinx.serialization](https://start.ktor.io/p/kotlinx-serialization) | Handles JSON serialization using kotlinx.serialization library |
| [AsyncAPI](https://start.ktor.io/p/asyncapi) | Generates and serves AsyncAPI documentation |

## Building & Running

To build or run the project, use one of the following tasks:

| Task | Description |
|--------------------------------------------------------------|-------------------|
| `mvn test` | Run the tests |
| `mvn package` | Build the project |
| `java -jar target/ingest-v2-0.0.1-jar-with-dependencies.jar` | Run the server |

If the server starts successfully, you'll see the following output:

```
2024-12-04 14:32:45.584 [main] INFO Application - Application started in 0.303 seconds.
2024-12-04 14:32:45.682 [main] INFO Application - Responding at http://0.0.0.0:8080
```

215 changes: 215 additions & 0 deletions ingest-v2/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>ingest-v2</artifactId>
<version>${revision}</version>
<name>ingest-v2</name>
<description>ingest-v2</description>
<properties>
<kotlin.code.style>official</kotlin.code.style>
<kotlin.version>2.2.20</kotlin.version>
<ktor.version>3.3.0</ktor.version>
<ktor.async.api.version>3.1.1</ktor.async.api.version>
<kotlinx.coroutines.debug.version>1.10.2</kotlinx.coroutines.debug.version>
<logback.version>1.4.14</logback.version>
<junit.version>5.10.0</junit.version>
<openapi.generator.version>7.15.0</openapi.generator.version>
<slf4j.version>2.0.9</slf4j.version>
<spotless.version>2.46.1</spotless.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<kotlin.compiler.incremental>true</kotlin.compiler.incremental>
</properties>
<parent>
<artifactId>kusto-client</artifactId>
<groupId>com.microsoft.azure.kusto</groupId>
<!--suppress MavenPropertyInParent -->
<version>${revision}</version>
</parent>
<dependencies>
<dependency>
<groupId>io.ktor</groupId>
<artifactId>ktor-client-auth-jvm</artifactId>
<version>${ktor.version}</version>
</dependency>
<dependency>
<groupId>io.ktor</groupId>
<artifactId>ktor-client-content-negotiation-jvm</artifactId>
<version>${ktor.version}</version>
</dependency>
<dependency>
<groupId>io.ktor</groupId>
<artifactId>ktor-serialization-kotlinx-json-jvm</artifactId>
<version>${ktor.version}</version>
</dependency>
<dependency>
<groupId>io.ktor</groupId>
<artifactId>ktor-client-java-jvm</artifactId>
<version>${ktor.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-test-junit5</artifactId>
<version>${kotlin.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-coroutines-debug</artifactId>
<version>${kotlinx.coroutines.debug.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.mockk</groupId>
<artifactId>mockk-jvm</artifactId>
<version>1.14.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
<resources>
<resource>
<directory>${project.basedir}/src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<sourceDirs>
<sourceDir>${project.basedir}/src/main/kotlin</sourceDir>
<sourceDir>${project.build.directory}/generated-sources/openapi/src/main/kotlin</sourceDir>
</sourceDirs>
</configuration>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<configuration>
<compilerPlugins>
<plugin>kotlinx-serialization</plugin>
</compilerPlugins>
<jvmTarget>1.8</jvmTarget>
Copy link

Copilot AI Oct 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Kotlin compiler is targeting JVM 1.8, but the parent pom specifies Java 11 as the minimum version. For consistency and to take advantage of Java 11 features, consider updating jvmTarget to 11.

Suggested change
<jvmTarget>1.8</jvmTarget>
<jvmTarget>11</jvmTarget>

Copilot uses AI. Check for mistakes.
</configuration>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-serialization</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<!-- RELEASE_VERSION -->
<version>${openapi.generator.version}</version>
<!-- /RELEASE_VERSION -->
<executions>
<execution>
<id>default</id>
<goals>
<goal>generate</goal>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generating doesn't work for me at all - I'm getting this error:

Execution default-cli of goal org.openapitools:openapi-generator-maven-plugin:7.15.0:generate failed: Unable to load the mojo 'generate' in the plugin 'org.openapitools:openapi-generator-maven-plugin:7.15.0' due to an API incompatibility: org.codehaus.plexus.component.repository.exception.ComponentLookupException: org/openapitools/codegen/plugin/CodeGenMojo has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which indicates a problem with using java 8 - using a later version works. We need to support java 8.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting the following warnings:

Unknown type found in the schema: long. To map it, please use the schema mapping option (e.g. --schema-mappings in CLI)
Unknown type found in the schema: long. To map it, please use the schema mapping option (e.g. --schema-mappings in CLI)
Unknown type found in the schema: long. To map it, please use the schema mapping option (e.g. --schema-mappings in CLI)

Empty operationId found for path: post /v1/rest/ingestion/queued/{database}/{table}. Renamed to auto-generated operationId: v1RestIngestionQueuedDatabaseTablePost
Empty operationId found for path: get /v1/rest/ingestion/configuration. Renamed to auto-generated operationId: v1RestIngestionConfigurationGet
Empty operationId found for path: get /v1/rest/ingestion/queued/{database}/{table}/{operationId}. Renamed to auto-generated operationId: v1RestIngestionQueuedDatabaseTableOperationIdGet
Empty operationId found for path: post /v1/rest/ingest/{database}/{table}. Renamed to auto-generated operationId: v1RestIngestDatabaseTablePost


Copy link
Contributor Author

@ag-ramachandran ag-ramachandran Oct 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, this is because we are using 11.

</goals>
<configuration>
<typeMappings>integer=java.lang.Long,int=java.lang.Long</typeMappings>
<globalProperties>
<authMethods>bearer</authMethods>
</globalProperties>
<inputSpec>${project.basedir}/src/main/resources/openapi.yaml</inputSpec>
<cleanupOutput>true</cleanupOutput>
<!-- target to generate kotlin client code -->
<generatorName>kotlin</generatorName>
<!-- pass any necessary config options -->
<configOptions>
<library>jvm-ktor</library>
<packageName>com.microsoft.azure.kusto.ingest.v2</packageName>
<idea>true</idea>
<!-- Use the Java 8 date library -->
<dateLibrary>java8</dateLibrary>
<serializableModel>true</serializableModel>
<serializationLibrary>kotlinx_serialization</serializationLibrary>
<generateTests>false</generateTests>
<skipIfSpecIsUnchanged>true</skipIfSpecIsUnchanged>
</configOptions>
<library>jvm-ktor</library>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.diffplug.spotless</groupId>
<artifactId>spotless-maven-plugin</artifactId>
<version>${spotless.version}</version>
<configuration>
<kotlin>
<!-- These are the defaults, you can override if you want -->
<includes>
<include>src/main/kotlin/**/*.kt</include>
<include>src/test/kotlin/**/*.kt</include>
</includes>

<ktfmt>
<version>0.51</version> <!-- optional -->
<style>KOTLINLANG</style> <!-- optional, options are META (default), GOOGLE and KOTLINLANG -->
<maxWidth>80</maxWidth> <!-- optional -->
<blockIndent>4</blockIndent> <!-- optional -->
<continuationIndent>8</continuationIndent> <!-- optional -->
<removeUnusedImports>true</removeUnusedImports> <!-- optional -->
<manageTrailingCommas>true</manageTrailingCommas> <!-- optional -->
</ktfmt>
<ktlint>
<version>1.0.0</version> <!-- optional -->
<editorConfigOverride> <!-- optional -->
<ij_kotlin_allow_trailing_comma>true</ij_kotlin_allow_trailing_comma>
<ij_kotlin_allow_trailing_comma_on_call_site>true</ij_kotlin_allow_trailing_comma_on_call_site>
<!-- intellij_idea is the default style we preset in Spotless, you can override it referring to https://pinterest.github.io/ktlint/latest/rules/code-styles. -->
<ktlint_code_style>intellij_idea</ktlint_code_style>
</editorConfigOverride>
<customRuleSets> <!-- optional -->
<value>io.nlopez.compose.rules:ktlint:0.4.25</value>
</customRuleSets>
</ktlint>
<licenseHeader>
<content>
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
</content> <!-- or <file>${project.basedir}/license-header</file> -->
</licenseHeader>
</kotlin>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
package com.microsoft.azure.kusto.ingest.v2

import com.azure.core.credential.TokenCredential
import com.microsoft.azure.kusto.ingest.v2.apis.DefaultApi
import com.microsoft.azure.kusto.ingest.v2.common.exceptions.IngestException
import com.microsoft.azure.kusto.ingest.v2.infrastructure.HttpResponse
import com.microsoft.azure.kusto.ingest.v2.models.ConfigurationResponse
import org.slf4j.LoggerFactory

class ConfigurationApiWrapper(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a public api for the users to use? Equivalent to the builder?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If so it should have a better name

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be used internally. Thought was the following : we will have a builder entry point added that will orchestrate calls to

a) Get Config
b) Use the config and create an ingest client
c) Have a public API for upload that will be called against the ingest client

override val dmUrl: String,
override val tokenCredential: TokenCredential,
override val skipSecurityChecks: Boolean = false,
) : KustoBaseApiClient(dmUrl, tokenCredential, skipSecurityChecks) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we consistently using this naming here (Data management URL)? In the portal it's called 'Data Ingestion URI' - might be a good idea to align with that for clarity.

private val logger =
LoggerFactory.getLogger(ConfigurationApiWrapper::class.java)
private val baseUrl = "$dmUrl/v1/rest/ingestion/configuration"
private val api: DefaultApi =
DefaultApi(baseUrl = dmUrl, httpClientConfig = setupConfig)

suspend fun getConfigurationDetails(): ConfigurationResponse {
val configurationHttpResponse: HttpResponse<ConfigurationResponse> =
api.getIngestConfiguration()
if (configurationHttpResponse.success) {
logger.info(
"Successfully retrieved configuration details from $dmUrl with status: ${configurationHttpResponse.status}",
)
logger.debug(
"Configuration details: {}",
configurationHttpResponse.body(),
)
return configurationHttpResponse.body()
} else {
logger.error(
"Failed to retrieve configuration details from $baseUrl. Status: ${configurationHttpResponse.status}, " +
"Body: ${configurationHttpResponse.body()}",
)
throw IngestException(
"Failed to retrieve configuration details from $baseUrl. Status: ${configurationHttpResponse.status}, " +
"Body: ${configurationHttpResponse.body()}",
)
}
}
}
Loading
Loading