Skip to content

Commit 2bc60ad

Browse files
committed
feat: add support for building linux/arm64 images from code
1 parent f473490 commit 2bc60ad

File tree

9 files changed

+184
-2
lines changed

9 files changed

+184
-2
lines changed

client/scripts/update_api_spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { parseDocument } from "yaml";
2424

2525
const GH_BASE_URL = "https://raw.githubusercontent.com";
2626
const DATA_SERVICES_REPO = "SwissDataScienceCenter/renku-data-services";
27-
const DATA_SERVICES_RELEASE = "main";
27+
const DATA_SERVICES_RELEASE = "leafty/configure-arm-builds";
2828

2929
async function main() {
3030
argv.forEach((arg) => {

client/src/features/sessionsV2/api/sessionLaunchersV2.generated-api.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,12 +315,15 @@ export type EnvironmentWithImageGet = Environment & {
315315
environment_kind: EnvironmentKind;
316316
};
317317
export type Repository = string;
318+
export type BuildPlatform = string;
319+
export type BuildPlatforms = BuildPlatform[];
318320
export type BuilderVariant = string;
319321
export type FrontendVariant = string;
320322
export type RepositoryRevision = string;
321323
export type BuildContextDir = string;
322324
export type BuildParameters = {
323325
repository: Repository;
326+
platforms?: BuildPlatforms;
324327
builder_variant: BuilderVariant;
325328
frontend_variant: FrontendVariant;
326329
repository_revision?: RepositoryRevision;
@@ -385,6 +388,7 @@ export type RepositoryRevisionPatch = string;
385388
export type BuildContextDirPatch = string;
386389
export type BuildParametersPatch = {
387390
repository?: Repository;
391+
platforms?: BuildPlatforms;
388392
builder_variant?: BuilderVariant;
389393
frontend_variant?: FrontendVariant;
390394
repository_revision?: RepositoryRevisionPatch;

client/src/features/sessionsV2/api/sessionLaunchersV2.openapi.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,6 +1006,19 @@
10061006
"maxLength": 99,
10071007
"example": "My Renku Session :)"
10081008
},
1009+
"BuildPlatforms": {
1010+
"description": "The target runtime platforms of a session environment.",
1011+
"type": "array",
1012+
"items": {
1013+
"$ref": "#/components/schemas/BuildPlatform"
1014+
}
1015+
},
1016+
"BuildPlatform": {
1017+
"description": "A runtime platform, e.g. \"linux/amd64\".",
1018+
"type": "string",
1019+
"minLength": 1,
1020+
"maxLength": 99
1021+
},
10091022
"BuilderVariant": {
10101023
"description": "Type of virtual environment manager when building custom environments.",
10111024
"type": "string",
@@ -1106,6 +1119,9 @@
11061119
"repository": {
11071120
"$ref": "#/components/schemas/Repository"
11081121
},
1122+
"platforms": {
1123+
"$ref": "#/components/schemas/BuildPlatforms"
1124+
},
11091125
"builder_variant": {
11101126
"$ref": "#/components/schemas/BuilderVariant"
11111127
},
@@ -1144,6 +1160,9 @@
11441160
"repository": {
11451161
"$ref": "#/components/schemas/Repository"
11461162
},
1163+
"platforms": {
1164+
"$ref": "#/components/schemas/BuildPlatforms"
1165+
},
11471166
"builder_variant": {
11481167
"$ref": "#/components/schemas/BuilderVariant"
11491168
},
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
/*!
2+
* Copyright 2025 - Swiss Data Science Center (SDSC)
3+
* A partnership between École Polytechnique Fédérale de Lausanne (EPFL) and
4+
* Eidgenössische Technische Hochschule Zürich (ETHZ).
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
import ChevronFlippedIcon from "~/components/icons/ChevronFlippedIcon";
20+
import cx from "classnames";
21+
import { useCallback, useMemo, useState } from "react";
22+
import {
23+
Controller,
24+
type Control,
25+
type FieldValues,
26+
type UseControllerProps,
27+
} from "react-hook-form";
28+
import { Collapse, Label } from "reactstrap";
29+
30+
import { BUILDER_PLATFORMS } from "../../session.constants";
31+
import type { SessionLauncherForm } from "../../sessionsV2.types";
32+
import BuilderSelectorCommon from "./BuilderSelectorCommon";
33+
34+
interface BuilderAdvancedSettingsProps {
35+
control: Control<SessionLauncherForm>;
36+
}
37+
38+
export default function BuilderAdvancedSettings({
39+
control,
40+
}: BuilderAdvancedSettingsProps) {
41+
const [isOpen, setIsOpen] = useState(false);
42+
const toggleIsOpen = useCallback(
43+
() => setIsOpen((isAdvancedSettingOpen) => !isAdvancedSettingOpen),
44+
[]
45+
);
46+
return (
47+
<div className={cx("d-flex", "flex-column", "gap-1")}>
48+
<button
49+
className={cx(
50+
"d-flex",
51+
"align-items-center",
52+
"w-100",
53+
"bg-transparent",
54+
"border-0",
55+
"p-0",
56+
"h4"
57+
)}
58+
type="button"
59+
onClick={toggleIsOpen}
60+
>
61+
Advanced settings
62+
<ChevronFlippedIcon className="ms-1" flipped={isOpen} />
63+
</button>
64+
<Collapse isOpen={isOpen}>
65+
<div className={cx("d-flex", "flex-column", "gap-3")}>
66+
<BuilderPlatformSelector name="platform" control={control} />
67+
</div>
68+
</Collapse>
69+
</div>
70+
);
71+
}
72+
73+
interface BuilderPlatformSelectorProps<T extends FieldValues>
74+
extends UseControllerProps<T> {}
75+
76+
function BuilderPlatformSelector<T extends FieldValues>({
77+
...controllerProps
78+
}: BuilderPlatformSelectorProps<T>) {
79+
const defaultValue = useMemo(
80+
() =>
81+
controllerProps.defaultValue
82+
? controllerProps.defaultValue
83+
: BUILDER_PLATFORMS[0],
84+
[controllerProps.defaultValue]
85+
);
86+
87+
return (
88+
<div>
89+
<Label for="builder-environment-platform-select-input">Platform</Label>
90+
<Controller
91+
{...controllerProps}
92+
render={({
93+
field: { onBlur, onChange, value, disabled },
94+
fieldState: { error },
95+
}) => (
96+
<>
97+
<div
98+
className={cx(error && "is-invalid")}
99+
data-cy="environment-platform-select"
100+
>
101+
<BuilderSelectorCommon
102+
defaultValue={defaultValue}
103+
disabled={disabled}
104+
id="builder-environment-platform-select"
105+
inputId="builder-environment-platform-select-input"
106+
name={controllerProps.name}
107+
onBlur={onBlur}
108+
onChange={onChange}
109+
options={BUILDER_PLATFORMS}
110+
value={value ?? ""}
111+
/>
112+
</div>
113+
<div className="invalid-feedback">
114+
{error?.message ? (
115+
<>{error.message}</>
116+
) : (
117+
<>Please select a valid platform.</>
118+
)}
119+
</div>
120+
</>
121+
)}
122+
rules={
123+
controllerProps.rules ?? {
124+
required: "Please select a platform.",
125+
}
126+
}
127+
/>
128+
</div>
129+
);
130+
}

client/src/features/sessionsV2/components/SessionForm/BuilderEnvironmentFields.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import { DEFAULT_APP_PARAMS } from "../../../../utils/context/appParams.constant
2929
import { useProject } from "../../../ProjectPageV2/ProjectPageContainer/ProjectPageContainer";
3030
import { useGetRepositoriesProbesQuery } from "../../../repositories/repositories.api";
3131
import type { SessionLauncherForm } from "../../sessionsV2.types";
32+
import BuilderAdvancedSettings from "./BuilderAdvancedSettings";
3233
import BuilderFrontendSelector from "./BuilderFrontendSelector";
3334
import BuilderTypeSelector from "./BuilderTypeSelector";
3435
import CodeRepositoryAdvancedSettings from "./CodeRepositoryAdvancedSettings";
@@ -104,6 +105,7 @@ export default function BuilderEnvironmentFields({
104105
</div>
105106
<BuilderTypeSelector name="builder_variant" control={control} />
106107
<BuilderFrontendSelector name="frontend_variant" control={control} />
108+
<BuilderAdvancedSettings control={control} />
107109
</div>
108110
);
109111

client/src/features/sessionsV2/components/SessionModals/NewSessionLauncherModal.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ export default function NewSessionLauncherModal({
7272
default_url: DEFAULT_URL,
7373
port: DEFAULT_PORT,
7474
repository: "",
75+
platform: "",
7576
},
7677
});
7778
const {

client/src/features/sessionsV2/session.constants.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,21 @@ export const BUILDER_FRONTENDS = [
136136
},
137137
] as readonly BuilderSelectorOption[];
138138

139+
export const BUILDER_PLATFORMS = [
140+
{
141+
value: "linux/amd64",
142+
label: "linux/amd64",
143+
description:
144+
"The default runtime platform. Select this option unless you know your session will run on a different platform.",
145+
},
146+
{
147+
value: "linux/arm64",
148+
label: "linux/arm64",
149+
description:
150+
"Select this option if your session will run on ARM64 compute resources.",
151+
},
152+
] as readonly BuilderSelectorOption[];
153+
139154
export const IMAGE_BUILD_DOCS =
140155
"https://renku.notion.site/How-to-create-a-custom-environment-from-a-code-repository-1960df2efafc801b88f6da59a0aa8234";
141156

client/src/features/sessionsV2/session.utils.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ export function getFormattedEnvironmentValues(data: SessionLauncherForm): {
103103
gid,
104104
mount_directory,
105105
name,
106+
platform,
106107
port,
107108
repository_revision: repository_revision_,
108109
repository,
@@ -125,6 +126,7 @@ export function getFormattedEnvironmentValues(data: SessionLauncherForm): {
125126
builder_variant,
126127
frontend_variant,
127128
repository,
129+
platforms: [platform],
128130
...(context_dir ? { context_dir } : {}),
129131
...(repository_revision ? { repository_revision } : {}),
130132
},
@@ -203,6 +205,7 @@ export function getFormattedEnvironmentValuesForEdit(
203205
builder_variant,
204206
context_dir,
205207
frontend_variant,
208+
platform,
206209
repository_revision,
207210
repository,
208211
} = data;
@@ -218,6 +221,7 @@ export function getFormattedEnvironmentValuesForEdit(
218221
repository,
219222
repository_revision: repository_revision ?? "",
220223
context_dir: context_dir ?? "",
224+
platforms: [platform],
221225
},
222226
},
223227
};
@@ -277,6 +281,10 @@ export function getLauncherDefaultValues(
277281
launcher.environment.environment_image_source === "build"
278282
? launcher.environment.build_parameters.context_dir ?? ""
279283
: "",
284+
platform:
285+
launcher.environment.environment_image_source === "build"
286+
? launcher.environment.build_parameters.platforms?.at(0) ?? ""
287+
: "",
280288
};
281289
}
282290

client/src/features/sessionsV2/sessionsV2.types.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ export interface SessionLauncherForm
103103
// For "global" environments
104104
environmentId: EnvironmentId;
105105

106-
// For "custom" + "image" environments
106+
// For "custom + image" environments
107107
default_url: DefaultUrl;
108108
uid: EnvironmentUid;
109109
gid: EnvironmentGid;
@@ -112,6 +112,9 @@ export interface SessionLauncherForm
112112
args: string;
113113
command: string;
114114
strip_path_prefix: boolean;
115+
116+
// For "custom + build" environments
117+
platform: string;
115118
}
116119

117120
export interface SessionResources {

0 commit comments

Comments
 (0)