Skip to content

Commit 6236df4

Browse files
author
ggao
committed
Add job principal field for job cluster submit
1 parent dfb4ed1 commit 6236df4

File tree

12 files changed

+435
-62
lines changed

12 files changed

+435
-62
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright 2019 Netflix, Inc.
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 io.mantisrx.runtime;
18+
19+
import io.mantisrx.shaded.com.fasterxml.jackson.annotation.JsonCreator;
20+
import io.mantisrx.shaded.com.fasterxml.jackson.annotation.JsonIgnoreProperties;
21+
import io.mantisrx.shaded.com.fasterxml.jackson.annotation.JsonProperty;
22+
23+
24+
public class JobPrincipal {
25+
26+
private final String email;
27+
private final PrincipalType type;
28+
29+
@JsonCreator
30+
@JsonIgnoreProperties(ignoreUnknown = true)
31+
public JobPrincipal(@JsonProperty("email") String email,
32+
@JsonProperty("type") PrincipalType type) {
33+
this.email = email;
34+
this.type = type != null ? type : PrincipalType.USER;
35+
}
36+
37+
public String getEmail() {
38+
return email;
39+
}
40+
41+
public PrincipalType getType() {
42+
return type;
43+
}
44+
45+
@Override
46+
public String toString() {
47+
return "JobPrincipal{" +
48+
"email='" + email + '\'' +
49+
", type=" + type +
50+
'}';
51+
}
52+
53+
public enum PrincipalType {
54+
USER,
55+
GROUP
56+
}
57+
}

mantis-common/src/main/java/io/mantisrx/runtime/NamedJobDefinition.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,25 @@
1818

1919
import io.mantisrx.shaded.com.fasterxml.jackson.annotation.JsonCreator;
2020
import io.mantisrx.shaded.com.fasterxml.jackson.annotation.JsonIgnoreProperties;
21+
import io.mantisrx.shaded.com.fasterxml.jackson.annotation.JsonInclude;
2122
import io.mantisrx.shaded.com.fasterxml.jackson.annotation.JsonProperty;
2223

2324

2425
public class NamedJobDefinition {
2526

2627
private final MantisJobDefinition jobDefinition;
2728
private final JobOwner owner;
29+
@JsonInclude(JsonInclude.Include.NON_NULL)
30+
private final JobPrincipal jobPrincipal;
2831

2932
@JsonCreator
3033
@JsonIgnoreProperties(ignoreUnknown = true)
3134
public NamedJobDefinition(@JsonProperty("jobDefinition") MantisJobDefinition jobDefinition,
32-
@JsonProperty("owner") JobOwner owner) {
35+
@JsonProperty("owner") JobOwner owner,
36+
@JsonProperty("jobPrincipal") JobPrincipal jobPrincipal) {
3337
this.jobDefinition = jobDefinition;
3438
this.owner = owner;
39+
this.jobPrincipal = jobPrincipal;
3540
}
3641

3742
public MantisJobDefinition getJobDefinition() {
@@ -42,11 +47,16 @@ public JobOwner getOwner() {
4247
return owner;
4348
}
4449

50+
public JobPrincipal getJobPrincipal() {
51+
return jobPrincipal;
52+
}
53+
4554
@Override
4655
public String toString() {
4756
return "NamedJobDefinition{" +
4857
"jobDefinition=" + jobDefinition +
4958
", owner=" + owner +
59+
", jobPrincipal=" + jobPrincipal +
5060
'}';
5161
}
5262

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
/*
2+
* Copyright 2019 Netflix, Inc.
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 io.mantisrx.runtime;
18+
19+
import static org.junit.Assert.assertEquals;
20+
import static org.junit.Assert.assertNotNull;
21+
22+
import io.mantisrx.shaded.com.fasterxml.jackson.databind.DeserializationFeature;
23+
import io.mantisrx.shaded.com.fasterxml.jackson.databind.ObjectMapper;
24+
import io.mantisrx.shaded.com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
25+
import org.junit.Test;
26+
27+
public class NamedJobDefinitionDeserializationTest {
28+
29+
private static final ObjectMapper objectMapper = new ObjectMapper()
30+
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
31+
.registerModule(new Jdk8Module());
32+
33+
@Test
34+
public void testDeserializeNamedJobDefinitionWithJobPrincipal() throws Exception {
35+
String json = "{\n" +
36+
" \"jobDefinition\": {\n" +
37+
" \"name\": \"TestGigi2\",\n" +
38+
" \"user\": \"ggao\",\n" +
39+
" \"jobJarFileLocation\": \"https://mantis.staging.us-east-1.prod.netflix.net/mantis-artifacts/titus-migration-thin-1.2.3-snapshot.202511202319+aa2e763.zip\",\n" +
40+
" \"version\": \"1.2.3-snapshot.202511202319+aa2e763\",\n" +
41+
" \"schedulingInfo\": {\n" +
42+
" \"stages\": {\n" +
43+
" \"1\": {\n" +
44+
" \"numberOfInstances\": \"1\",\n" +
45+
" \"machineDefinition\": {\n" +
46+
" \"cpuCores\": 2,\n" +
47+
" \"memoryMB\": 8192,\n" +
48+
" \"diskMB\": 8192,\n" +
49+
" \"networkMbps\": 700,\n" +
50+
" \"numPorts\": \"1\"\n" +
51+
" },\n" +
52+
" \"scalable\": false,\n" +
53+
" \"softConstraints\": [],\n" +
54+
" \"hardConstraints\": [],\n" +
55+
" \"containerAttributes\": {\n" +
56+
" \"containerSkuID\": \"small\"\n" +
57+
" }\n" +
58+
" }\n" +
59+
" }\n" +
60+
" },\n" +
61+
" \"parameters\": [],\n" +
62+
" \"labels\": [\n" +
63+
" {\n" +
64+
" \"name\": \"_mantis.user\",\n" +
65+
" \"value\": \"ggao\"\n" +
66+
" },\n" +
67+
" {\n" +
68+
" \"name\": \"_mantis.ownerEmail\",\n" +
69+
" \"value\": \"ggao@netflix.com\"\n" +
70+
" },\n" +
71+
" {\n" +
72+
" \"name\": \"_mantis.artifact\",\n" +
73+
" \"value\": \"titus-migration-thin-1.2.3\"\n" +
74+
" },\n" +
75+
" {\n" +
76+
" \"name\": \"_mantis.artifact.version\",\n" +
77+
" \"value\": \"snapshot\"\n" +
78+
" }\n" +
79+
" ],\n" +
80+
" \"migrationConfig\": {\n" +
81+
" \"strategy\": \"PERCENTAGE\",\n" +
82+
" \"configString\": \"{\\\"percentToMove\\\":25,\\\"intervalMs\\\":60000}\"\n" +
83+
" },\n" +
84+
" \"slaMin\": \"0\",\n" +
85+
" \"slaMax\": \"0\",\n" +
86+
" \"deploymentStrategy\": {\n" +
87+
" \"resourceClusterId\": \"mantisResourceClusterStagingDefault3\"\n" +
88+
" },\n" +
89+
" \"cronSpec\": null,\n" +
90+
" \"cronPolicy\": \"KEEP_EXISTING\"\n" +
91+
" },\n" +
92+
" \"owner\": {\n" +
93+
" \"contactEmail\": \"ggao@netflix.com\",\n" +
94+
" \"description\": \"\",\n" +
95+
" \"name\": \"Gigi Gao\",\n" +
96+
" \"repo\": \"\",\n" +
97+
" \"teamName\": \"\"\n" +
98+
" },\n" +
99+
" \"jobPrincipal\": {\n" +
100+
" \"email\": \"ggao@netflix.com\"\n" +
101+
" }\n" +
102+
"}";
103+
104+
NamedJobDefinition njd = objectMapper.readValue(json, NamedJobDefinition.class);
105+
106+
// Verify the object was deserialized
107+
assertNotNull("NamedJobDefinition should not be null", njd);
108+
assertNotNull("JobDefinition should not be null", njd.getJobDefinition());
109+
assertNotNull("Owner should not be null", njd.getOwner());
110+
111+
// Verify jobPrincipal was deserialized correctly
112+
assertNotNull("JobPrincipal should not be null", njd.getJobPrincipal());
113+
assertEquals("JobPrincipal email should match", "ggao@netflix.com", njd.getJobPrincipal().getEmail());
114+
assertEquals("JobPrincipal type should default to USER", JobPrincipal.PrincipalType.USER, njd.getJobPrincipal().getType());
115+
116+
// Verify job definition fields
117+
assertEquals("Job name should match", "TestGigi2", njd.getJobDefinition().getName());
118+
assertEquals("User should match", "ggao", njd.getJobDefinition().getUser());
119+
120+
// Verify owner fields
121+
assertEquals("Owner email should match", "ggao@netflix.com", njd.getOwner().getContactEmail());
122+
assertEquals("Owner name should match", "Gigi Gao", njd.getOwner().getName());
123+
}
124+
125+
@Test
126+
public void testDeserializeNamedJobDefinitionWithoutJobPrincipal() throws Exception {
127+
// Test that jobPrincipal can be null for backward compatibility
128+
String json = "{\n" +
129+
" \"jobDefinition\": {\n" +
130+
" \"name\": \"TestJob\",\n" +
131+
" \"user\": \"testuser\",\n" +
132+
" \"jobJarFileLocation\": \"https://example.com/test.zip\",\n" +
133+
" \"version\": \"1.0.0\",\n" +
134+
" \"schedulingInfo\": {\n" +
135+
" \"stages\": {\n" +
136+
" \"1\": {\n" +
137+
" \"numberOfInstances\": \"1\",\n" +
138+
" \"machineDefinition\": {\n" +
139+
" \"cpuCores\": 1,\n" +
140+
" \"memoryMB\": 1024,\n" +
141+
" \"diskMB\": 1024,\n" +
142+
" \"networkMbps\": 128,\n" +
143+
" \"numPorts\": \"1\"\n" +
144+
" },\n" +
145+
" \"scalable\": false\n" +
146+
" }\n" +
147+
" }\n" +
148+
" },\n" +
149+
" \"parameters\": [],\n" +
150+
" \"labels\": []\n" +
151+
" },\n" +
152+
" \"owner\": {\n" +
153+
" \"contactEmail\": \"test@example.com\",\n" +
154+
" \"description\": \"\",\n" +
155+
" \"name\": \"Test User\",\n" +
156+
" \"repo\": \"\",\n" +
157+
" \"teamName\": \"\"\n" +
158+
" }\n" +
159+
"}";
160+
161+
NamedJobDefinition njd = objectMapper.readValue(json, NamedJobDefinition.class);
162+
163+
// Verify the object was deserialized
164+
assertNotNull("NamedJobDefinition should not be null", njd);
165+
assertNotNull("JobDefinition should not be null", njd.getJobDefinition());
166+
assertNotNull("Owner should not be null", njd.getOwner());
167+
168+
// JobPrincipal can be null for backward compatibility
169+
// This ensures old payloads without jobPrincipal still work
170+
}
171+
172+
}

mantis-control-plane/mantis-control-plane-server/src/main/java/io/mantisrx/master/api/akka/route/proto/JobClusterProtoAdapter.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ public static final CreateJobClusterRequest toCreateJobClusterRequest(final Name
7979
jd.getMigrationConfig(),
8080
jd.getIsReadyForJobMaster(),
8181
jd.getParameters(),
82-
processLabels(jd)
82+
processLabels(jd),
83+
njd.getJobPrincipal()
8384
)
8485

8586
, "user"
@@ -200,7 +201,8 @@ public static final UpdateJobClusterRequest toUpdateJobClusterRequest(final Name
200201
jd.getMigrationConfig(),
201202
jd.getIsReadyForJobMaster(),
202203
jd.getParameters(),
203-
processLabels(jd)
204+
processLabels(jd),
205+
njd.getJobPrincipal()
204206
),
205207

206208
"user");

mantis-control-plane/mantis-control-plane-server/src/main/java/io/mantisrx/master/jobcluster/JobClusterActor.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1368,6 +1368,7 @@ private MantisJobClusterMetadataView generateJobClusterMetadataView(IJobClusterM
13681368
.withIsReadyForJobMaster(jobClusterMetadata.getJobClusterDefinition().getIsReadyForJobMaster())
13691369
.withJars(jobClusterMetadata.getJobClusterDefinition().getJobClusterConfigs())
13701370
.withJobOwner(jobClusterMetadata.getJobClusterDefinition().getOwner())
1371+
.withJobPrincipal(jobClusterMetadata.getJobClusterDefinition().getJobPrincipal())
13711372
.withLabels(jobClusterMetadata.getJobClusterDefinition().getLabels())
13721373
.withLastJobCount(jobClusterMetadata.getLastJobCount())
13731374
.withSla(jobClusterMetadata.getJobClusterDefinition().getSLA())

0 commit comments

Comments
 (0)