Skip to content

Commit 4fcc625

Browse files
yongkiy-googlecopybara-github
authored andcommitted
chore: add skeleton Agent Engine Deployer for ADK Java
PiperOrigin-RevId: 906820376
1 parent d37f6ee commit 4fcc625

2 files changed

Lines changed: 233 additions & 0 deletions

File tree

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
/*
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.adk.deploy;
18+
19+
import java.io.IOException;
20+
import java.nio.file.Files;
21+
import java.nio.file.Path;
22+
import java.time.Instant;
23+
import java.util.logging.Level;
24+
import java.util.logging.Logger;
25+
26+
/**
27+
* Command line application to deploy an ADK Java Agent to Vertex AI Agent Engine (Reasoning
28+
* Engine).
29+
*/
30+
class AgentEngineDeployer {
31+
private static final Logger logger = Logger.getLogger(AgentEngineDeployer.class.getName());
32+
33+
private final String region;
34+
private final String projectId;
35+
private final String agentName;
36+
private final int serverPort;
37+
private final String sourceDir;
38+
private final Path tempDir;
39+
40+
private AgentEngineDeployer(
41+
String region,
42+
String projectId,
43+
String agentName,
44+
int serverPort,
45+
String sourceDir,
46+
Path tempDir) {
47+
this.region = region;
48+
this.projectId = projectId;
49+
this.agentName = agentName;
50+
this.serverPort = serverPort;
51+
this.sourceDir = sourceDir;
52+
this.tempDir = tempDir;
53+
}
54+
55+
/** Creates a temporary Dockerfile and bundles the application for Reasoning Engine deployment. */
56+
private static Path prepareBundle(int serverPort) throws IOException {
57+
Path tempDir = Files.createTempDirectory("agentEngineDeploy");
58+
Path dockerfile = tempDir.resolve("Dockerfile");
59+
60+
String dockerfileContent =
61+
String.format(
62+
"FROM eclipse-temurin:21-jdk\n"
63+
+ "WORKDIR /app\n"
64+
+ "COPY . .\n"
65+
+ "RUN ./mvnw clean package -DskipTests\n"
66+
+ "EXPOSE %d\n"
67+
+ "CMD [\"java\", \"-jar\", \"target/app.jar\"]\n",
68+
serverPort);
69+
70+
Files.writeString(dockerfile, dockerfileContent);
71+
logger.info("Prepared Dockerfile at " + dockerfile.toAbsolutePath());
72+
return tempDir;
73+
}
74+
75+
/** Orchestrates the deployment process. */
76+
public void deploy() throws IOException {
77+
logger.info("Starting Agent Engine deployment...");
78+
logger.info(
79+
String.format(
80+
"Deploying Agent '%s' to project '%s' in region '%s'...",
81+
agentName, projectId, region));
82+
83+
// TODO: Integrate with Vertex AI CreateReasoningEngine API client.
84+
logger.info("Preparation complete. Skipping actual deployment to Vertex AI for now.");
85+
}
86+
87+
/** Builder for {@link AgentEngineDeployer}. */
88+
public static class Builder {
89+
private String region;
90+
private String projectId;
91+
private String agentName;
92+
private int serverPort;
93+
private String sourceDir;
94+
95+
public Builder region(String region) {
96+
this.region = region;
97+
return this;
98+
}
99+
100+
public Builder projectId(String projectId) {
101+
this.projectId = projectId;
102+
return this;
103+
}
104+
105+
public Builder agentName(String agentName) {
106+
this.agentName = agentName;
107+
return this;
108+
}
109+
110+
public Builder serverPort(int serverPort) {
111+
this.serverPort = serverPort;
112+
return this;
113+
}
114+
115+
public Builder sourceDir(String sourceDir) {
116+
this.sourceDir = sourceDir;
117+
return this;
118+
}
119+
120+
public AgentEngineDeployer build() throws IOException {
121+
if (projectId == null || projectId.isEmpty()) {
122+
throw new IllegalStateException("Project ID must be specified.");
123+
}
124+
if (agentName == null || agentName.isEmpty()) {
125+
agentName = "ADK Java Agent: " + Instant.now().toString();
126+
}
127+
if (sourceDir == null || sourceDir.isEmpty()) {
128+
sourceDir = System.getProperty("user.dir");
129+
}
130+
Path tempDir = AgentEngineDeployer.prepareBundle(serverPort);
131+
return new AgentEngineDeployer(region, projectId, agentName, serverPort, sourceDir, tempDir);
132+
}
133+
}
134+
135+
public static Builder builder() {
136+
return new Builder();
137+
}
138+
139+
public static void main(String[] args) {
140+
Builder builder = AgentEngineDeployer.builder().region("us-central1").serverPort(8080);
141+
142+
// Minimal argument parsing logic
143+
for (int i = 0; i < args.length; i++) {
144+
switch (args[i]) {
145+
case "--project":
146+
if (i + 1 < args.length) {
147+
builder.projectId(args[++i]);
148+
}
149+
break;
150+
case "--region":
151+
if (i + 1 < args.length) {
152+
builder.region(args[++i]);
153+
}
154+
break;
155+
case "--name":
156+
if (i + 1 < args.length) {
157+
builder.agentName(args[++i]);
158+
}
159+
break;
160+
case "--port":
161+
if (i + 1 < args.length) {
162+
builder.serverPort(Integer.parseInt(args[++i]));
163+
}
164+
break;
165+
case "--source-dir":
166+
if (i + 1 < args.length) {
167+
builder.sourceDir(args[++i]);
168+
}
169+
break;
170+
default:
171+
logger.warning("Unknown argument: " + args[i]);
172+
}
173+
}
174+
175+
try {
176+
AgentEngineDeployer deployer = builder.build();
177+
deployer.deploy();
178+
} catch (Exception e) {
179+
logger.log(Level.SEVERE, "Deployment failed", e);
180+
System.exit(1);
181+
}
182+
}
183+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.adk.deploy;
18+
19+
import static com.google.common.truth.Truth.assertThat;
20+
import static org.junit.Assert.assertThrows;
21+
22+
import java.io.IOException;
23+
import java.nio.file.Files;
24+
import java.nio.file.Path;
25+
import org.junit.Test;
26+
import org.junit.runner.RunWith;
27+
import org.junit.runners.JUnit4;
28+
29+
@RunWith(JUnit4.class)
30+
public class AgentEngineDeployerTest {
31+
32+
@Test
33+
public void build_withMissingProjectId_throwsException() {
34+
AgentEngineDeployer.Builder builder = AgentEngineDeployer.builder();
35+
// ProjectId is not set.
36+
assertThrows(IllegalStateException.class, builder::build);
37+
}
38+
39+
@Test
40+
public void deploy_createsDockerfileWithCorrectPort() throws IOException {
41+
int serverPort = 9090;
42+
43+
Path tempDir = AgentEngineDeployer.prepareBundle(serverPort);
44+
Path dockerfile = tempDir.resolve("Dockerfile");
45+
46+
assertThat(Files.exists(dockerfile)).isTrue();
47+
String content = Files.readString(dockerfile);
48+
assertThat(content).contains("EXPOSE " + serverPort);
49+
}
50+
}

0 commit comments

Comments
 (0)