Skip to content

Commit 0b38d51

Browse files
honnixclaude
andauthored
chore: migrate to flyte-sandbox-bundled and fix CI (#324)
Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
1 parent 71d676e commit 0b38d51

File tree

12 files changed

+126
-40
lines changed

12 files changed

+126
-40
lines changed

flytekit-java/src/main/java/org/flyte/flytekit/SdkConfig.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@
2727
abstract class SdkConfig {
2828

2929
// VisibleForTesting
30-
static final String DOMAIN_ENV_VAR = "FLYTE_INTERNAL_DOMAIN";
31-
static final String PROJECT_ENV_VAR = "FLYTE_INTERNAL_PROJECT";
32-
static final String VERSION_ENV_VAR = "FLYTE_INTERNAL_VERSION";
30+
static final String DOMAIN_ENV_VAR = "FLYTE_INTERNAL_TASK_DOMAIN";
31+
static final String PROJECT_ENV_VAR = "FLYTE_INTERNAL_TASK_PROJECT";
32+
static final String VERSION_ENV_VAR = "FLYTE_INTERNAL_TASK_VERSION";
3333

3434
public abstract String project();
3535

flytekit-local-engine/src/test/java/org/flyte/localengine/LocalEngineTest.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -501,9 +501,9 @@ public static Stream<Arguments> testBranchNodesProvider() {
501501
private static Map<String, WorkflowTemplate> loadWorkflows() {
502502
Map<String, String> env =
503503
ImmutableMap.of(
504-
"FLYTE_INTERNAL_DOMAIN", "development",
505-
"FLYTE_INTERNAL_VERSION", "test",
506-
"FLYTE_INTERNAL_PROJECT", "flytetester");
504+
"FLYTE_INTERNAL_TASK_DOMAIN", "development",
505+
"FLYTE_INTERNAL_TASK_VERSION", "test",
506+
"FLYTE_INTERNAL_TASK_PROJECT", "flytetester");
507507

508508
Map<WorkflowIdentifier, WorkflowTemplate> registrarWorkflows =
509509
loadAll(WorkflowTemplateRegistrar.class, env);
@@ -515,9 +515,9 @@ private static Map<String, WorkflowTemplate> loadWorkflows() {
515515
private static Map<String, RunnableTask> loadTasks() {
516516
Map<String, String> env =
517517
ImmutableMap.of(
518-
"FLYTE_INTERNAL_DOMAIN", "development",
519-
"FLYTE_INTERNAL_VERSION", "test",
520-
"FLYTE_INTERNAL_PROJECT", "flytetester");
518+
"FLYTE_INTERNAL_TASK_DOMAIN", "development",
519+
"FLYTE_INTERNAL_TASK_VERSION", "test",
520+
"FLYTE_INTERNAL_TASK_PROJECT", "flytetester");
521521

522522
Map<TaskIdentifier, RunnableTask> registrarRunnableTasks =
523523
loadAll(RunnableTaskRegistrar.class, env);

integration-tests/src/test/java/org/flyte/SerializeJavaIT.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,15 @@ class SerializeJavaIT extends Fixtures {
3636
@Test
3737
void testSerializeWorkflows() {
3838
try {
39-
File current = new File("target/protos");
40-
File tempDir = managed.resolve(current.getAbsolutePath()).toFile();
41-
boolean created = tempDir.mkdir();
42-
if (!created) {
39+
// Path must be relative to project root since jflyte runs in a container
40+
// with the project root as working directory
41+
String serializePath = "integration-tests/target/protos";
42+
File tempDir = new File("../" + serializePath);
43+
if (!tempDir.mkdirs() && !tempDir.exists()) {
4344
throw new IOException("Unable to create path");
4445
}
4546

46-
CLIENT.serializeWorkflows(CLASSPATH, tempDir.getPath());
47+
CLIENT.serializeWorkflows(CLASSPATH, serializePath);
4748

4849
boolean hasFibonacciWorkflow =
4950
Stream.of(tempDir.list())

integration-tests/src/test/java/org/flyte/utils/FlyteSandboxClient.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public static FlyteSandboxClient create() {
4747
String version = String.valueOf(System.currentTimeMillis());
4848

4949
String address = FlyteSandboxContainer.INSTANCE.getHost();
50-
int port = FlyteSandboxContainer.INSTANCE.getMappedPort(30081);
50+
int port = FlyteSandboxContainer.INSTANCE.getMappedPort(30080);
5151

5252
ManagedChannel channel =
5353
ManagedChannelBuilder.forTarget(address + ":" + port).usePlaintext().enableRetry().build();

integration-tests/src/test/java/org/flyte/utils/FlyteSandboxContainer.java

Lines changed: 90 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.nio.file.Files;
2626
import java.nio.file.Paths;
2727
import java.time.Duration;
28+
import java.util.Map;
2829
import org.apache.commons.compress.utils.IOUtils;
2930
import org.testcontainers.DockerClientFactory;
3031
import org.testcontainers.containers.BindMode;
@@ -33,7 +34,8 @@
3334

3435
public class FlyteSandboxContainer extends GenericContainer<FlyteSandboxContainer> {
3536

36-
public static final String IMAGE_NAME = "ghcr.io/flyteorg/flyte-sandbox:v1.9.1";
37+
public static final String IMAGE_NAME =
38+
"ghcr.io/flyteorg/flyte-sandbox-bundled:sha-f3ab1b7480bad4072f7ecb695660fdf47032a6c4";
3739

3840
public static final FlyteSandboxContainer INSTANCE =
3941
new FlyteSandboxContainer()
@@ -48,13 +50,14 @@ public class FlyteSandboxContainer extends GenericContainer<FlyteSandboxContaine
4850
private static void startContainer() {
4951
INSTANCE.start();
5052

51-
// Flyte sandbox uses Docker in Docker, we have to copy jflyte container into inner Docker
53+
// Flyte sandbox-bundled uses k3s with containerd (not Docker-in-Docker),
54+
// so we use ctr to import the jflyte image into the inner containerd
5255
// otherwise, flytepropeller can't use the right version for pod execution
5356

5457
DockerClient client = DockerClientFactory.instance().client();
5558
try (InputStream imageInputStream = client.saveImageCmd(JFlyteContainer.IMAGE_NAME).exec()) {
5659

57-
try (OutputStream outputStream = Files.newOutputStream(Paths.get("target/jflyte.tar.gz"))) {
60+
try (OutputStream outputStream = Files.newOutputStream(Paths.get("target/jflyte.tar"))) {
5861
IOUtils.copy(imageInputStream, outputStream);
5962
}
6063

@@ -64,7 +67,14 @@ private static void startContainer() {
6467

6568
ExecResult execResult =
6669
INSTANCE.execInContainer(
67-
"docker", "load", "-i", "integration-tests/target/jflyte.tar.gz");
70+
"ctr",
71+
"--address",
72+
"/run/k3s/containerd/containerd.sock",
73+
"--namespace",
74+
"k8s.io",
75+
"images",
76+
"import",
77+
"integration-tests/target/jflyte.tar");
6878

6979
if (execResult.getExitCode() != 0) {
7080
throw new RuntimeException(execResult.getStderr() + " " + execResult.getStdout());
@@ -75,6 +85,68 @@ private static void startContainer() {
7585
Thread.currentThread().interrupt();
7686
throw new RuntimeException("failed to load jflyte image", e);
7787
}
88+
89+
// The sandbox manifest has FLYTE_PLATFORM_INSECURE as a YAML boolean (true)
90+
// which may not be injected correctly as a string env var. Patch the configmap
91+
// to use a quoted string value and restart the flyte-sandbox pod.
92+
patchInsecureEnvVar();
93+
}
94+
95+
private static void patchInsecureEnvVar() {
96+
try {
97+
ExecResult patchResult =
98+
INSTANCE.execInContainer(
99+
"kubectl",
100+
"get",
101+
"configmap",
102+
"-n",
103+
"flyte",
104+
"flyte-sandbox-config",
105+
"-o",
106+
"jsonpath={.data.100-inline-config\\.yaml}");
107+
108+
if (patchResult.getExitCode() != 0) {
109+
throw new RuntimeException("Failed to read configmap: " + patchResult.getStderr());
110+
}
111+
112+
String config = patchResult.getStdout();
113+
if (config.contains("FLYTE_PLATFORM_INSECURE: true")) {
114+
String patched =
115+
config.replace("FLYTE_PLATFORM_INSECURE: true", "FLYTE_PLATFORM_INSECURE: 'true'");
116+
117+
ExecResult applyResult =
118+
INSTANCE.execInContainer(
119+
"sh",
120+
"-c",
121+
"kubectl create configmap flyte-sandbox-config -n flyte"
122+
+ " --from-literal='100-inline-config.yaml="
123+
+ patched.replace("'", "'\"'\"'")
124+
+ "' --dry-run=client -o yaml | kubectl apply -f -");
125+
126+
if (applyResult.getExitCode() != 0) {
127+
throw new RuntimeException("Failed to patch configmap: " + applyResult.getStderr());
128+
}
129+
130+
// Restart flyte-sandbox pod to pick up the new config
131+
INSTANCE.execInContainer(
132+
"kubectl", "rollout", "restart", "deployment/flyte-sandbox", "-n", "flyte");
133+
134+
// Wait for the rollout to complete
135+
INSTANCE.execInContainer(
136+
"kubectl",
137+
"rollout",
138+
"status",
139+
"deployment/flyte-sandbox",
140+
"-n",
141+
"flyte",
142+
"--timeout=120s");
143+
}
144+
} catch (IOException e) {
145+
throw new UncheckedIOException("failed to patch insecure env var", e);
146+
} catch (InterruptedException e) {
147+
Thread.currentThread().interrupt();
148+
throw new RuntimeException("failed to patch insecure env var", e);
149+
}
78150
}
79151

80152
FlyteSandboxContainer() {
@@ -84,23 +156,31 @@ private static void startContainer() {
84156

85157
withPrivilegedMode(true);
86158

159+
// k3s requires tmpfs mounts and cgroupns=host on Linux (CI)
160+
withTmpFs(Map.of("/run", "", "/var/run", ""));
161+
withCreateContainerCmdModifier(
162+
cmd ->
163+
cmd.getHostConfig()
164+
.withCgroupnsMode("host")
165+
// host.docker.internal is needed by the bootstrap to template manifests;
166+
// Docker Desktop adds it automatically, but Linux Docker does not
167+
.withExtraHosts("host.docker.internal:host-gateway"));
168+
87169
withNetworkAliases("flyte");
88170

89171
withWorkingDirectory(workingDir);
90172
withFileSystemBind(workingDir, workingDir, BindMode.READ_ONLY);
91173

92174
withExposedPorts(
93-
30081, // flyteadmin
94-
30082, // k8s dashboard
95-
30084, // minio
96-
30086 // k8s api
175+
30080, // envoy proxy (flyteadmin http + grpc)
176+
30002 // minio
97177
);
98178

99179
withReuse(true);
100180

101181
withNetwork(FlyteSandboxNetwork.INSTANCE);
102182

103-
waitingFor(Wait.forLogMessage(".*Flyte is ready!.*", 1));
183+
waitingFor(Wait.forHttp("/healthcheck").forPort(30080));
104184
withStartupTimeout(Duration.ofMinutes(5));
105185
}
106186

@@ -110,10 +190,8 @@ public void start() {
110190

111191
logger().info("Flyte is ready!");
112192

113-
String consoleUri = String.format("http://%s:%d/console", getHost(), getMappedPort(30081));
114-
String k8sUri = String.format("http://%s:%d", getHost(), getMappedPort(30082));
193+
String consoleUri = String.format("http://%s:%d/console", getHost(), getMappedPort(30080));
115194

116195
logger().info("Flyte UI is available at " + consoleUri);
117-
logger().info("K8s dashboard is available at " + k8sUri);
118196
}
119197
}

integration-tests/src/test/java/org/flyte/utils/JFlyteContainer.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ class JFlyteContainer extends GenericContainer<JFlyteContainer> {
3030
static final String IMAGE_NAME;
3131
static final Map<String, String> envVars =
3232
ImmutableMap.<String, String>builder()
33-
.put("FLYTE_PLATFORM_URL", "flyte:30081")
33+
.put("FLYTE_PLATFORM_URL", "flyte:30080")
3434
.put("FLYTE_PLATFORM_INSECURE", "True")
35-
.put("FLYTE_AWS_ENDPOINT", "http://flyte:30084")
35+
.put("FLYTE_AWS_ENDPOINT", "http://flyte:30002")
3636
.put("FLYTE_AWS_ACCESS_KEY_ID", "minio")
3737
.put("FLYTE_AWS_SECRET_ACCESS_KEY", "miniostorage")
3838
.put("FLYTE_STAGING_LOCATION", "s3://my-s3-bucket")
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
api.version=1.44

jflyte-utils/src/main/java/org/flyte/jflyte/utils/ExecutionConfig.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ public abstract class ExecutionConfig {
3333

3434
public static ExecutionConfig load() {
3535
return ExecutionConfig.builder()
36-
.project(getenv("FLYTE_INTERNAL_PROJECT"))
37-
.domain(getenv("FLYTE_INTERNAL_DOMAIN"))
38-
.version(getenv("FLYTE_INTERNAL_VERSION"))
36+
.project(getenv("FLYTE_INTERNAL_TASK_PROJECT"))
37+
.domain(getenv("FLYTE_INTERNAL_TASK_DOMAIN"))
38+
.version(getenv("FLYTE_INTERNAL_TASK_VERSION"))
3939
.image(getenv("FLYTE_INTERNAL_IMAGE"))
4040
.build();
4141
}

jflyte-utils/src/main/java/org/flyte/jflyte/utils/ProjectClosure.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -212,9 +212,9 @@ static ProjectClosure load(
212212
.put("JFLYTE_DOMAIN", config.domain())
213213
.put("JFLYTE_PROJECT", config.project())
214214
.put("JFLYTE_VERSION", config.version())
215-
.put("FLYTE_INTERNAL_DOMAIN", config.domain())
216-
.put("FLYTE_INTERNAL_PROJECT", config.project())
217-
.put("FLYTE_INTERNAL_VERSION", config.version())
215+
.put("FLYTE_INTERNAL_TASK_DOMAIN", config.domain())
216+
.put("FLYTE_INTERNAL_TASK_PROJECT", config.project())
217+
.put("FLYTE_INTERNAL_TASK_VERSION", config.version())
218218
.build();
219219

220220
// 1. load classes, and create templates

jflyte/src/main/java/org/flyte/jflyte/ExecuteLocal.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@ public Integer call() {
6464

6565
Map<String, String> env =
6666
ImmutableMap.of(
67-
"FLYTE_INTERNAL_DOMAIN", "development",
68-
"FLYTE_INTERNAL_VERSION", "test",
69-
"FLYTE_INTERNAL_PROJECT", "flytetester");
67+
"FLYTE_INTERNAL_TASK_DOMAIN", "development",
68+
"FLYTE_INTERNAL_TASK_VERSION", "test",
69+
"FLYTE_INTERNAL_TASK_PROJECT", "flytetester");
7070

7171
Map<String, RunnableTask> runnableTasks = ExecuteLocalLoader.loadTasks(modules, env);
7272
Map<String, DynamicWorkflowTask> dynamicWorkflowTasks =

0 commit comments

Comments
 (0)