Skip to content

Commit d37bb33

Browse files
yongkiy-googlecopybara-github
authored andcommitted
feat: add skeleton Agent Engine Deployer for ADK Java
PiperOrigin-RevId: 906820376
1 parent dd46b25 commit d37bb33

2 files changed

Lines changed: 253 additions & 0 deletions

File tree

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
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+
public 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+
Path tempDir = AgentEngineDeployer.prepareBundle(serverPort);
122+
return new AgentEngineDeployer(region, projectId, agentName, serverPort, sourceDir, tempDir);
123+
}
124+
}
125+
126+
public static Builder builder() {
127+
return new Builder();
128+
}
129+
130+
public static void main(String[] args) {
131+
String region = "us-central1";
132+
String projectId = "";
133+
String agentName = "";
134+
int serverPort = 8080;
135+
String sourceDir = "";
136+
137+
// Minimal argument parsing logic
138+
for (int i = 0; i < args.length; i++) {
139+
switch (args[i]) {
140+
case "--project":
141+
if (i + 1 < args.length) {
142+
projectId = args[++i];
143+
}
144+
break;
145+
case "--region":
146+
if (i + 1 < args.length) {
147+
region = args[++i];
148+
}
149+
break;
150+
case "--name":
151+
if (i + 1 < args.length) {
152+
agentName = args[++i];
153+
}
154+
break;
155+
case "--port":
156+
if (i + 1 < args.length) {
157+
serverPort = Integer.parseInt(args[++i]);
158+
}
159+
break;
160+
case "--source-dir":
161+
if (i + 1 < args.length) {
162+
sourceDir = args[++i];
163+
}
164+
break;
165+
default:
166+
logger.warning("Unknown argument: " + args[i]);
167+
}
168+
}
169+
170+
if (projectId == null || projectId.isEmpty()) {
171+
throw new IllegalArgumentException("Project ID must be specified.");
172+
}
173+
if (agentName == null || agentName.isEmpty()) {
174+
agentName = "ADK Java Agent: " + Instant.now().toString();
175+
}
176+
if (sourceDir == null || sourceDir.isEmpty()) {
177+
sourceDir = System.getProperty("user.dir");
178+
}
179+
try {
180+
AgentEngineDeployer deployer =
181+
AgentEngineDeployer.builder()
182+
.region(region)
183+
.projectId(projectId)
184+
.agentName(agentName)
185+
.serverPort(serverPort)
186+
.sourceDir(sourceDir)
187+
.build();
188+
deployer.deploy();
189+
} catch (Exception e) {
190+
logger.log(Level.SEVERE, "Deployment failed", e);
191+
System.exit(1);
192+
}
193+
}
194+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
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 computeFlags_withMissingProject_throwsException() {
34+
AgentEngineDeployer deployer = new AgentEngineDeployer();
35+
assertThrows(IllegalArgumentException.class, deployer::computeFlags);
36+
}
37+
38+
@Test
39+
public void computeFlags_withValidProject_succeeds() {
40+
AgentEngineDeployer deployer = new AgentEngineDeployer();
41+
deployer.setProjectId("test-project");
42+
deployer.computeFlags();
43+
// No exception thrown.
44+
}
45+
46+
@Test
47+
public void prepareBundle_createsDockerfile() throws IOException {
48+
AgentEngineDeployer deployer = new AgentEngineDeployer();
49+
deployer.setProjectId("test-project");
50+
deployer.setServerPort(9090);
51+
52+
Path tempDir = deployer.prepareBundle();
53+
Path dockerfile = tempDir.resolve("Dockerfile");
54+
55+
assertThat(Files.exists(dockerfile)).isTrue();
56+
String content = Files.readString(dockerfile);
57+
assertThat(content).contains("EXPOSE 9090");
58+
}
59+
}

0 commit comments

Comments
 (0)