/
PersistenceService.java
1267 lines (1158 loc) · 55.4 KB
/
PersistenceService.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
*
* Copyright 2020 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.netflix.genie.web.data.services;
import com.netflix.genie.common.dto.Job;
import com.netflix.genie.common.dto.JobExecution;
import com.netflix.genie.common.dto.JobMetadata;
import com.netflix.genie.common.dto.UserResourcesSummary;
import com.netflix.genie.common.dto.search.JobSearchResult;
import com.netflix.genie.common.exceptions.GenieException;
import com.netflix.genie.common.external.dtos.v4.AgentClientMetadata;
import com.netflix.genie.common.external.dtos.v4.Application;
import com.netflix.genie.common.external.dtos.v4.ApplicationRequest;
import com.netflix.genie.common.external.dtos.v4.ApplicationStatus;
import com.netflix.genie.common.external.dtos.v4.ArchiveStatus;
import com.netflix.genie.common.external.dtos.v4.Cluster;
import com.netflix.genie.common.external.dtos.v4.ClusterRequest;
import com.netflix.genie.common.external.dtos.v4.ClusterStatus;
import com.netflix.genie.common.external.dtos.v4.Command;
import com.netflix.genie.common.external.dtos.v4.CommandRequest;
import com.netflix.genie.common.external.dtos.v4.CommandStatus;
import com.netflix.genie.common.external.dtos.v4.CommonResource;
import com.netflix.genie.common.external.dtos.v4.Criterion;
import com.netflix.genie.common.external.dtos.v4.JobRequest;
import com.netflix.genie.common.external.dtos.v4.JobSpecification;
import com.netflix.genie.common.external.dtos.v4.JobStatus;
import com.netflix.genie.common.internal.dtos.v4.FinishedJob;
import com.netflix.genie.common.internal.exceptions.unchecked.GenieInvalidStatusException;
import com.netflix.genie.common.internal.exceptions.unchecked.GenieJobAlreadyClaimedException;
import com.netflix.genie.web.data.services.impl.jpa.queries.aggregates.JobInfoAggregate;
import com.netflix.genie.web.dtos.JobSubmission;
import com.netflix.genie.web.dtos.ResolvedJob;
import com.netflix.genie.web.exceptions.checked.IdAlreadyExistsException;
import com.netflix.genie.web.exceptions.checked.NotFoundException;
import com.netflix.genie.web.exceptions.checked.PreconditionFailedException;
import com.netflix.genie.web.services.LegacyAttachmentService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.validation.Valid;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
/**
* Service API for all Genie persistence related operations.
*
* @author tgianos
* @since 4.0.0
*/
@Validated
public interface PersistenceService {
//region Application APIs
/**
* Save a new application.
*
* @param applicationRequest The {@link ApplicationRequest} containing the metadata of the application to create
* @return The unique id of the application that was created
* @throws IdAlreadyExistsException If the ID is already used by another application
*/
String saveApplication(@Valid ApplicationRequest applicationRequest) throws IdAlreadyExistsException;
/**
* Get the application metadata for given id.
*
* @param id unique id for application configuration to get. Not null/empty.
* @return The {@link Application}
* @throws NotFoundException if no application with {@literal id} exists
*/
Application getApplication(@NotBlank String id) throws NotFoundException;
/**
* Find applications which match the given filter criteria.
*
* @param name Name of the application. Can be null or empty.
* @param user The user who created the application. Can be null/empty
* @param statuses The statuses of the applications to find. Can be null.
* @param tags Tags allocated to this application
* @param type The type of the application to find
* @param page The page requested for the search results
* @return The page of found applications
*/
Page<Application> findApplications(
@Nullable String name,
@Nullable String user,
@Nullable Set<ApplicationStatus> statuses,
@Nullable Set<String> tags,
@Nullable String type,
Pageable page
);
/**
* Update an {@link Application}.
*
* @param id The id of the application to update
* @param updateApp Information to update for the application configuration with
* @throws NotFoundException If no {@link Application} with {@literal id} exists
* @throws PreconditionFailedException If {@literal id} and {@literal updateApp} id don't match
*/
void updateApplication(
@NotBlank String id,
@Valid Application updateApp
) throws NotFoundException, PreconditionFailedException;
/**
* Delete all applications from the system.
*
* @throws PreconditionFailedException When any {@link Application} is still associated with a command
*/
void deleteAllApplications() throws PreconditionFailedException;
/**
* Delete an {@link Application} from the system.
*
* @param id unique id of the application to delete
* @throws PreconditionFailedException When the {@link Application} is still used by any command
*/
void deleteApplication(@NotBlank String id) throws PreconditionFailedException;
/**
* Get all the commands the application with given id is associated with.
*
* @param id The id of the application to get the commands for.
* @param statuses The desired status(es) to filter the associated commands for
* @return The commands the application is used by
* @throws NotFoundException If no {@link Application} with {@literal id} exists
*/
Set<Command> getCommandsForApplication(
@NotBlank String id,
@Nullable Set<CommandStatus> statuses
) throws NotFoundException;
/**
* Delete any unused applications that were created before the given time.
* Unused means they aren't linked to any other resources in the Genie system like jobs or commands and therefore
* referential integrity is maintained.
*
* @param createdThreshold The instant in time that any application had to be created before (exclusive) to be
* considered for deletion. Presents ability to filter out newly created applications if
* desired.
* @return The number of successfully deleted applications
*/
long deleteUnusedApplications(Instant createdThreshold);
//endregion
//region Cluster APIs
/**
* Save a {@link Cluster}.
*
* @param clusterRequest The cluster information to save
* @return The id of the saved cluster
* @throws IdAlreadyExistsException If a {@link Cluster} with the given {@literal id} already exists
*/
String saveCluster(@Valid ClusterRequest clusterRequest) throws IdAlreadyExistsException;
/**
* Get the {@link Cluster} identified by the given {@literal id}.
*
* @param id unique id of the {@link Cluster} to get
* @return The {@link Cluster}
* @throws NotFoundException If no {@link Cluster} with {@literal id} exists
*/
Cluster getCluster(@NotBlank String id) throws NotFoundException;
/**
* Find and {@link Cluster}s that match the given parameters. Null or empty parameters are ignored.
*
* @param name cluster name
* @param statuses {@link ClusterStatus} that clusters must be in to be matched
* @param tags tags attached to this cluster
* @param minUpdateTime min time when cluster was updated
* @param maxUpdateTime max time when cluster was updated
* @param page The page to get
* @return All the clusters matching the criteria
*/
Page<Cluster> findClusters(
@Nullable String name,
@Nullable Set<ClusterStatus> statuses,
@Nullable Set<String> tags,
@Nullable Instant minUpdateTime,
@Nullable Instant maxUpdateTime,
Pageable page
);
/**
* Update a {@link Cluster} with the given information.
*
* @param id The id of the cluster to update
* @param updateCluster The information to update the cluster with
* @throws NotFoundException If no {@link Cluster} with {@literal id} exists
* @throws PreconditionFailedException If the {@literal id} doesn't match the {@literal updateCluster} id
*/
void updateCluster(
@NotBlank String id,
@Valid Cluster updateCluster
) throws NotFoundException, PreconditionFailedException;
/**
* Delete all clusters from database.
*
* @throws PreconditionFailedException If the cluster is still associated with any job
*/
void deleteAllClusters() throws PreconditionFailedException;
/**
* Delete a {@link Cluster} by id.
*
* @param id unique id of the cluster to delete
* @throws PreconditionFailedException If the cluster is still associated with any job
*/
void deleteCluster(@NotBlank String id) throws PreconditionFailedException;
/**
* Delete all clusters that are in one of the given states, aren't attached to any jobs and were created before
* the given time.
*
* @param deleteStatuses The set of {@link ClusterStatus} a cluster must be in to be considered for
* deletion.
* @param clusterCreatedThreshold The instant in time before which a cluster must have been created to be
* considered for deletion. Exclusive.
* @return The number of clusters deleted
*/
long deleteUnusedClusters(Set<ClusterStatus> deleteStatuses, Instant clusterCreatedThreshold);
/**
* Find all the {@link Cluster}'s that match the given {@link Criterion}.
*
* @param criterion The {@link Criterion} supplied that each cluster needs to completely match to be returned
* @param addDefaultStatus {@literal true} if the a default status should be added to the supplied
* {@link Criterion} if the supplied criterion doesn't already have a status
* @return All the {@link Cluster}'s which matched the {@link Criterion}
*/
Set<Cluster> findClustersMatchingCriterion(@Valid Criterion criterion, boolean addDefaultStatus);
/**
* Find all the {@link Cluster}'s that match any of the given {@link Criterion}.
*
* @param criteria The set of {@link Criterion} supplied that a cluster needs to completely match at least
* one of to be returned
* @param addDefaultStatus {@literal true} if the a default status should be added to the supplied
* {@link Criterion} if the supplied criterion doesn't already have a status
* @return All the {@link Cluster}'s which matched the {@link Criterion}
*/
Set<Cluster> findClustersMatchingAnyCriterion(@NotEmpty Set<@Valid Criterion> criteria, boolean addDefaultStatus);
//endregion
//region Command APIs
/**
* Save a {@link Command} in the system based on the given {@link CommandRequest}.
*
* @param commandRequest encapsulates the command configuration information to create
* @return The id of the command that was saved
* @throws IdAlreadyExistsException If there was a conflict on the unique id for the command
*/
String saveCommand(@Valid CommandRequest commandRequest) throws IdAlreadyExistsException;
/**
* Get the metadata for the {@link Command} identified by the id.
*
* @param id unique id for command to get. Not null/empty.
* @return The command
* @throws NotFoundException If no {@link Command} exists with the given {@literal id}
*/
Command getCommand(@NotBlank String id) throws NotFoundException;
/**
* Find commands matching the given filter criteria.
*
* @param name Name of command config
* @param user The name of the user who created the configuration
* @param statuses The status of the commands to get. Can be null.
* @param tags tags allocated to this command
* @param page The page of results to get
* @return All the commands matching the specified criteria
*/
Page<Command> findCommands(
@Nullable String name,
@Nullable String user,
@Nullable Set<CommandStatus> statuses,
@Nullable Set<String> tags,
Pageable page
);
/**
* Update a {@link Command}.
*
* @param id The id of the command configuration to update. Not null or empty.
* @param updateCommand contains the information to update the command with
* @throws NotFoundException If no {@link Command} exists with the given {@literal id}
* @throws PreconditionFailedException When the {@literal id} doesn't match the id of {@literal updateCommand}
*/
void updateCommand(
@NotBlank String id,
@Valid Command updateCommand
) throws NotFoundException, PreconditionFailedException;
/**
* Delete all commands from the system.
*
* @throws PreconditionFailedException If any constraint is violated trying to delete a command
*/
void deleteAllCommands() throws PreconditionFailedException;
/**
* Delete a {@link Command} from system.
*
* @param id unique if of the command to delete
* @throws NotFoundException If no {@link Command} exists with the given {@literal id}
*/
void deleteCommand(@NotBlank String id) throws NotFoundException;
/**
* Add applications for the command.
*
* @param id The id of the command to add the application file to. Not null/empty/blank.
* @param applicationIds The ids of the applications to add. Not null.
* @throws NotFoundException If no {@link Command} exists with the given {@literal id} or one of the
* applications doesn't exist
* @throws PreconditionFailedException If an application with one of the ids is already associated with the command
*/
void addApplicationsForCommand(
@NotBlank String id,
@NotEmpty List<@NotBlank String> applicationIds
) throws NotFoundException, PreconditionFailedException;
/**
* Set the applications for the command.
*
* @param id The id of the command to add the application file to. Not null/empty/blank.
* @param applicationIds The ids of the applications to set. Not null.
* @throws NotFoundException If no {@link Command} exists with the given {@literal id} or one of the
* applications doesn't exist
* @throws PreconditionFailedException If there are duplicate application ids in the list
*/
void setApplicationsForCommand(
@NotBlank String id,
@NotNull List<@NotBlank String> applicationIds
) throws NotFoundException, PreconditionFailedException;
/**
* Get the applications for a given command.
*
* @param id The id of the command to get the application for. Not null/empty/blank.
* @return The applications or exception if none exist.
* @throws NotFoundException If no {@link Command} exists with the given {@literal id}
*/
List<Application> getApplicationsForCommand(String id) throws NotFoundException;
/**
* Remove all the applications from the command.
*
* @param id The id of the command to remove the application from. Not null/empty/blank.
* @throws NotFoundException If no {@link Command} exists with the given {@literal id}
* @throws PreconditionFailedException If applications are unable to be removed
*/
void removeApplicationsForCommand(@NotBlank String id) throws NotFoundException, PreconditionFailedException;
/**
* Remove the application from the command.
*
* @param id The id of the command to remove the application from. Not null/empty/blank.
* @param appId The id of the application to remove. Not null/empty/blank
* @throws NotFoundException If no {@link Command} exists with the given {@literal id}
*/
void removeApplicationForCommand(@NotBlank String id, @NotBlank String appId) throws NotFoundException;
/**
* Get all the clusters the command with given id is associated with.
*
* @param id The id of the command to get the clusters for.
* @param statuses The status of the clusters returned
* @return The clusters the command is available on.
* @throws NotFoundException If no {@link Command} exists with the given {@literal id}
*/
Set<Cluster> getClustersForCommand(
@NotBlank String id,
@Nullable Set<ClusterStatus> statuses
) throws NotFoundException;
/**
* For the given command {@literal id} return the Cluster {@link Criterion} in priority order that is currently
* associated with this command if any.
*
* @param id The id of the command to get the criteria for
* @return The cluster criteria in priority order
* @throws NotFoundException If no command with {@literal id} exists
*/
List<Criterion> getClusterCriteriaForCommand(String id) throws NotFoundException;
/**
* Add a new {@link Criterion} to the existing list of cluster criteria for the command identified by {@literal id}.
* This new criterion will be the lowest priority criterion.
*
* @param id The id of the command to add to
* @param criterion The new {@link Criterion} to add
* @throws NotFoundException If no command with {@literal id} exists
*/
void addClusterCriterionForCommand(String id, @Valid Criterion criterion) throws NotFoundException;
/**
* Add a new {@link Criterion} to the existing list of cluster criteria for the command identified by {@literal id}.
* The {@literal priority} is the place in the list this new criterion should be placed. A value of {@literal 0}
* indicates it should be placed at the front of the list with the highest possible priority. {@literal 1} would be
* second in the list etc. If {@literal priority} is {@literal >} the current size of the cluster criteria list
* this new criterion will be placed at the end as the lowest priority item.
*
* @param id The id of the command to add to
* @param criterion The new {@link Criterion} to add
* @param priority The place in the existing cluster criteria list this new criterion should be placed. Min 0.
* @throws NotFoundException If no command with {@literal id} exists
*/
void addClusterCriterionForCommand(
String id,
@Valid Criterion criterion,
@Min(0) int priority
) throws NotFoundException;
/**
* For the command identified by {@literal id} reset the entire list of cluster criteria to match the contents of
* {@literal clusterCriteria}.
*
* @param id The id of the command to set the cluster criteria for
* @param clusterCriteria The priority list of {@link Criterion} to set
* @throws NotFoundException If no command with {@literal id} exists
*/
void setClusterCriteriaForCommand(String id, List<@Valid Criterion> clusterCriteria) throws NotFoundException;
/**
* Remove the {@link Criterion} with the given {@literal priority} from the current list of cluster criteria
* associated with the command identified by {@literal id}. A value of {@literal 0} for {@literal priority}
* will result in the first element in the list being removed, {@literal 1} the second element and so on.
*
* @param id The id of the command to remove the criterion from
* @param priority The priority of the criterion to remove
* @throws NotFoundException If no command with {@literal id} exists
*/
void removeClusterCriterionForCommand(String id, @Min(0) int priority) throws NotFoundException;
/**
* Remove all the {@link Criterion} currently associated with the command identified by {@literal id}.
*
* @param id The id of the command to remove the criteria from
* @throws NotFoundException If no command with {@literal id} exists
*/
void removeAllClusterCriteriaForCommand(String id) throws NotFoundException;
/**
* Find all the {@link Command}'s that match the given {@link Criterion}.
*
* @param criterion The {@link Criterion} supplied that each command needs to completely match to be returned
* @param addDefaultStatus {@literal true} if a default status should be added to the supplied criterion if a
* status isn't already present
* @return All the {@link Command}'s which matched the {@link Criterion}
*/
Set<Command> findCommandsMatchingCriterion(@Valid Criterion criterion, boolean addDefaultStatus);
/**
* Update the status of a command to the {@literal desiredStatus} if its status is in {@literal currentStatuses},
* it was created before {@literal commandCreatedThreshold} and it hasn't been used in any job that was created
* in the Genie system after {@literal jobCreatedThreshold}.
*
* @param desiredStatus The new status the matching commands should have
* @param commandCreatedThreshold The instant in time which a command must have been created before to be
* considered for update. Exclusive
* @param currentStatuses The set of current statuses a command must have to be considered for update
* @param jobCreatedThreshold The instant in time after which a command must not have been used in a Genie job
* for it to be considered for update. Inclusive.
* @return The number of commands whose statuses were updated to {@literal desiredStatus}
*/
int updateStatusForUnusedCommands(
CommandStatus desiredStatus,
Instant commandCreatedThreshold,
Set<CommandStatus> currentStatuses,
Instant jobCreatedThreshold
);
/**
* Bulk delete commands from the database where their status is in {@literal deleteStatuses} they were created
* before {@literal commandCreatedThreshold} and they aren't attached to any jobs still in the database.
*
* @param deleteStatuses The set of statuses a command must be in in order to be considered for deletion
* @param commandCreatedThreshold The instant in time a command must have been created before to be considered for
* deletion. Exclusive.
* @return The number of commands that were deleted
*/
long deleteUnusedCommands(Set<CommandStatus> deleteStatuses, Instant commandCreatedThreshold);
//endregion
//region Job APIs
//region V3 Job APIs
/**
* Save all the initial job fields in the data store.
*
* @param jobRequest the Job request object to save. Not null
* @param jobMetadata metadata about the job request. Not null
* @param job The Job object to create
* @param jobExecution The job execution object to create
* @throws GenieException if there is an error
* @deprecated To be removed at completion of agent migration
*/
@Deprecated
void createJob(
@NotNull com.netflix.genie.common.dto.JobRequest jobRequest,
@NotNull com.netflix.genie.common.dto.JobMetadata jobMetadata,
@NotNull Job job,
@NotNull JobExecution jobExecution
) throws GenieException;
/**
* Update the job with the various resources used to run the job including the cluster, command and applications.
*
* @param jobId The id of the job to update
* @param clusterId The id of the cluster the job runs on
* @param commandId The id of the command the job runs with
* @param applicationIds The ids of the applications used to run the job
* @param memory The amount of memory (in MB) to run the job with
* @throws GenieException For any problems while updating
* @deprecated To be removed at completion of agent migration
*/
@Deprecated
void updateJobWithRuntimeEnvironment(
@NotBlank String jobId,
@NotBlank String clusterId,
@NotBlank String commandId,
@NotNull List<String> applicationIds,
@Min(1) int memory
) throws GenieException;
/**
* Update the status and status message of the job.
*
* @param id The id of the job to update the status for.
* @param jobStatus The updated status of the job.
* @param statusMsg The updated status message of the job.
* @throws GenieException if there is an error
* @deprecated To be removed at completion of agent migration
*/
@Deprecated
void updateJobStatus(
@NotBlank(message = "No job id entered. Unable to update.") String id,
@NotNull(message = "Status cannot be null.") com.netflix.genie.common.dto.JobStatus jobStatus,
@NotBlank(message = "Status message cannot be empty.") String statusMsg
) throws GenieException;
/**
* Update the job with information for the running job process.
*
* @param id the id of the job to update the process id for
* @param processId The id of the process on the box for this job
* @param checkDelay The delay to check the process with
* @param timeout The date at which this job should timeout
* @throws GenieException if there is an error
* @deprecated To be removed at completion of agent migration
*/
@Deprecated
void setJobRunningInformation(
@NotBlank String id,
@Min(value = 0, message = "Must be no lower than zero") int processId,
@Min(value = 1, message = "Must be at least 1 millisecond, preferably much more") long checkDelay,
@NotNull Instant timeout
) throws GenieException;
/**
* Method to set all job completion information for a job execution.
*
* @param id the id of the job to update the exit code
* @param exitCode The exit code of the process
* @param status The job status for the job
* @param statusMessage The job status message
* @param stdOutSize The size (in bytes) of the standard out file or null if there isn't one
* @param stdErrSize The size (in bytes) of the standard error file or null if there isn't one
* @throws GenieException if there is an error
* @deprecated To be removed at completion of agent migration
*/
@Deprecated
void setJobCompletionInformation(
@NotBlank(message = "No job id entered. Unable to update.") String id,
int exitCode,
@NotNull(message = "No job status entered.") com.netflix.genie.common.dto.JobStatus status,
@NotBlank(message = "Status message can't be blank. Unable to update") String statusMessage,
@Nullable Long stdOutSize,
@Nullable Long stdErrSize
) throws GenieException;
/**
* Get job request for given job id.
*
* @param id id of job request to look up
* @return the job
* @throws GenieException if there is an error
*/
@Deprecated
com.netflix.genie.common.dto.JobRequest getV3JobRequest(@NotBlank String id) throws GenieException;
/**
* Get job information for given job id.
*
* @param id id of job to look up
* @return the job
* @throws GenieException if there is an error
*/
Job getJob(@NotBlank String id) throws GenieException;
/**
* Get job execution for given job id.
*
* @param id id of job execution to look up
* @return the job
* @throws GenieException if there is an error
*/
JobExecution getJobExecution(@NotBlank String id) throws GenieException;
/**
* Get the metadata about a job.
*
* @param id The id of the job to get metadata for
* @return The metadata for a job
* @throws GenieException If any error occurs
*/
JobMetadata getJobMetadata(@NotBlank String id) throws GenieException;
/**
* Find jobs which match the given filter criteria.
*
* @param id id for job
* @param name name of job
* @param user user who submitted job
* @param statuses statuses of job
* @param tags tags for the job
* @param clusterName name of cluster for job
* @param clusterId id of cluster for job
* @param commandName name of the command run in the job
* @param commandId id of the command run in the job
* @param minStarted The time which the job had to start after in order to be return (inclusive)
* @param maxStarted The time which the job had to start before in order to be returned (exclusive)
* @param minFinished The time which the job had to finish after in order to be return (inclusive)
* @param maxFinished The time which the job had to finish before in order to be returned (exclusive)
* @param grouping The job grouping to search for
* @param groupingInstance The job grouping instance to search for
* @param page Page information of job to get
* @return Metadata information on jobs which match the criteria
*/
@SuppressWarnings("checkstyle:parameternumber")
Page<JobSearchResult> findJobs(
@Nullable String id,
@Nullable String name,
@Nullable String user,
@Nullable Set<com.netflix.genie.common.dto.JobStatus> statuses,
@Nullable Set<String> tags,
@Nullable String clusterName,
@Nullable String clusterId,
@Nullable String commandName,
@Nullable String commandId,
@Nullable Instant minStarted,
@Nullable Instant maxStarted,
@Nullable Instant minFinished,
@Nullable Instant maxFinished,
@Nullable String grouping,
@Nullable String groupingInstance,
@NotNull Pageable page
);
//endregion
//region V4 Job APIs
/**
* This method will delete a chunk of jobs whose creation time is earlier than the given date.
*
* @param creationThreshold The instant in time before which all jobs should be deleted
* @param excludeStatuses The set of statuses that should be excluded from deletion if a job is in one of these
* statuses
* @param batchSize The maximum number of jobs that should be deleted per query
* @return the number of deleted jobs
*/
long deleteJobsCreatedBefore(
@NotNull Instant creationThreshold,
@NotNull Set<JobStatus> excludeStatuses,
@Min(1) int batchSize
);
/**
* Save the given job submission information in the underlying data store.
* <p>
* The job record will be created with initial state of {@link JobStatus#RESERVED} meaning that the unique id
* returned by this API has been reserved within Genie and no other job can use it. If
* {@link JobSubmission} contains some attachments these attachments will be persisted to a
* configured storage system (i.e. local disk, S3, etc) and added to the set of dependencies for the job.
* The underlying attachment storage system must be accessible by the agent process configured by the system. For
* example if the server is set up to write attachments to local disk but the agent is not running locally but
* instead on the remote system it will not be able to access those attachments (as dependencies) and fail.
* See {@link LegacyAttachmentService} for more information.
*
* @param jobSubmission All the information the system has gathered regarding the job submission from the user
* either via the API or via the agent CLI
* @return The unique id of the job within the Genie ecosystem
* @throws IdAlreadyExistsException If the id the user requested already exists in the system for another job
*/
@Nonnull
String saveJobSubmission(@Valid JobSubmission jobSubmission) throws IdAlreadyExistsException;
/**
* Get the original request for a job.
*
* @param id The unique id of the job to get
* @return The job request if one was found
* @throws NotFoundException If no job with {@code id} exists
*/
JobRequest getJobRequest(@NotBlank String id) throws NotFoundException;
/**
* Save the given resolved details for a job. Sets the job status to {@link JobStatus#RESOLVED}.
*
* @param id The id of the job
* @param resolvedJob The resolved information for the job
* @throws NotFoundException When the job identified by {@code id} can't be found and the
* specification can't be saved or one of the resolved cluster, command
* or applications not longer exist in the system.
*/
void saveResolvedJob(@NotBlank String id, @Valid ResolvedJob resolvedJob) throws NotFoundException;
/**
* Get the saved job specification for the given job. If the job hasn't had a job specification resolved an empty
* {@link Optional} will be returned.
*
* @param id The id of the job
* @return The {@link JobSpecification} if one is present else an empty {@link Optional}
* @throws NotFoundException If no job with {@code id} exists
*/
Optional<JobSpecification> getJobSpecification(@NotBlank String id) throws NotFoundException;
/**
* Set a job identified by {@code id} to be owned by the agent identified by {@code agentClientMetadata}. The
* job status in the system will be set to {@link JobStatus#CLAIMED}
*
* @param id The id of the job to claim. Must exist in the system.
* @param agentClientMetadata The metadata about the client claiming the job
* @throws NotFoundException if no job with the given {@code id} exists
* @throws GenieJobAlreadyClaimedException if the job with the given {@code id} already has been claimed
* @throws GenieInvalidStatusException if the current job status is not {@link JobStatus#RESOLVED}
*/
void claimJob(
@NotBlank String id,
@Valid AgentClientMetadata agentClientMetadata
) throws NotFoundException, GenieJobAlreadyClaimedException, GenieInvalidStatusException;
/**
* Update the status of the job identified with {@code id} to be {@code newStatus} provided that the current status
* of the job matches {@code newStatus}. Optionally a status message can be provided to provide more details to
* users. If the {@code newStatus} is {@link JobStatus#RUNNING} the start time will be set. If the {@code newStatus}
* is a member of {@link JobStatus#getFinishedStatuses()} and the job had a started time set the finished time of
* the job will be set.
*
* @param id The id of the job to update status for. Must exist in the system.
* @param currentStatus The status the caller to this API thinks the job currently has
* @param newStatus The new status the caller would like to update the status to
* @param newStatusMessage An optional status message to associate with this change
* @throws NotFoundException if no job with the given {@code id} exists
* @throws GenieInvalidStatusException if the current status of the job identified by {@code id} in the system
* doesn't match the supplied {@code currentStatus}.
* Also if the {@code currentStatus} equals the {@code newStatus}.
*/
void updateJobStatus(
@NotBlank String id,
@NotNull JobStatus currentStatus,
@NotNull JobStatus newStatus,
@Nullable String newStatusMessage
) throws NotFoundException, GenieInvalidStatusException;
/**
* Update the status and status message of the job.
*
* @param id The id of the job to update the status for.
* @param archiveStatus The updated archive status for the job.
* @throws NotFoundException If no job with the given {@code id} exists
*/
void updateJobArchiveStatus(
@NotBlank(message = "No job id entered. Unable to update.") String id,
@NotNull(message = "Status cannot be null.") ArchiveStatus archiveStatus
) throws NotFoundException;
/**
* Get whether the job is a V4 job (Run with agent).
*
* @param id The id of the job
* @return true if its a v4 job
* @throws NotFoundException If no job with the given {@code id} exists
*/
boolean isV4(@NotBlank String id) throws NotFoundException;
/**
* Get the status for a job with the given {@code id}.
*
* @param id The id of the job to get status for
* @return The job status
* @throws NotFoundException If no job with the given {@code id} exists
*/
JobStatus getJobStatus(@NotBlank String id) throws NotFoundException;
/**
* Get the archive status for a job with the given {@code id}.
*
* @param id The id of the job to get status for
* @return The job archive status
* @throws NotFoundException If no job with the given {@code id} exists
*/
ArchiveStatus getJobArchiveStatus(@NotBlank String id) throws NotFoundException;
/**
* Get the location a job directory was archived to if at all.
*
* @param id The id of the job to get the location for
* @return The archive location or {@link Optional#empty()}
* @throws NotFoundException When there is no job with id {@code id}
*/
Optional<String> getJobArchiveLocation(@NotBlank String id) throws NotFoundException;
/**
* Get a DTO representing a finished job.
*
* @param id The id of the job to retrieve
* @return the finished job
* @throws NotFoundException if no job with the given {@code id} exists
* @throws GenieInvalidStatusException if the current status of the job is not final
*/
FinishedJob getFinishedJob(@NotBlank String id) throws NotFoundException, GenieInvalidStatusException;
/**
* Get whether the job with the given ID was submitted via the REST API or other mechanism.
*
* @param id The id of the job. Not blank.
* @return {@literal true} if the job was submitted via the API. {@literal false} otherwise
* @throws NotFoundException If no job with {@literal id} exists
*/
boolean isApiJob(@NotBlank String id) throws NotFoundException;
/**
* Given a hostname return a set of all the jobs currently active on that host.
*
* @param hostname The host name to search for. Not null or empty.
* @return All the jobs active on the host as a set of Job objects
*/
Set<Job> getAllActiveJobsOnHost(@NotBlank String hostname);
/**
* Get a set of host names which are currently have active jobs in the Genie cluster.
*
* @return The set of hosts with jobs currently in an active state
*/
Set<String> getAllHostsWithActiveJobs();
/**
* Get the cluster the job used or is using.
*
* @param id The id of the job to get the cluster for
* @return The {@link Cluster}
* @throws NotFoundException If either the job or the cluster is not found
*/
Cluster getJobCluster(@NotBlank String id) throws NotFoundException;
/**
* Get the command the job used or is using.
*
* @param id The id of the job to get the command for
* @return The {@link Command}
* @throws NotFoundException If either the job or the command is not found
*/
Command getJobCommand(@NotBlank String id) throws NotFoundException;
/**
* Get the applications the job used or is currently using.
*
* @param id The id of the job to get the applications for
* @return The {@link Application}s
* @throws NotFoundException If either the job or the applications were not found
*/
List<Application> getJobApplications(@NotBlank String id) throws NotFoundException;
/**
* Get the hostname a job is running on.
*
* @param id The id of the job to get the hostname for
* @return The hostname
* @throws NotFoundException If the job host cannot be found
*/
String getJobHost(@NotBlank String id) throws NotFoundException;
/**
* Get the count of 'active' jobs for a given user across all instances.
*
* @param user The user name
* @return the number of active jobs for a given user
*/
long getActiveJobCountForUser(@NotBlank String user);
/**
* Get a map of summaries of resources usage for each user with at least one active job.
*
* @param statuses The set of {@link JobStatus} a job must be in to be considered in this request
* @param api Whether the job was submitted via the api ({@literal true}) or the agent cli ({@literal false})
* @return a map of user resources summaries, keyed on user name
*/
Map<String, UserResourcesSummary> getUserResourcesSummaries(Set<JobStatus> statuses, boolean api);
/**
* Get the amount of memory currently used on the given host by Genie jobs in any of the following states.
* <p>
* {@link JobStatus#CLAIMED}
* {@link JobStatus#INIT}
* {@link JobStatus#RUNNING}
*
* @param hostname The hostname to get the memory for
* @return The amount of memory being used in MB by all jobs
*/
long getUsedMemoryOnHost(@NotBlank String hostname);
/**
* Get the set of active agent jobs.
*
* @return The list of job ids
*/
Set<String> getActiveAgentJobs();
/**
* Get the set of agent jobs in that have not reached CLAIMED state.
*
* @return The list of job ids
*/
Set<String> getUnclaimedAgentJobs();
/**
* Get all the aggregate metadata information about jobs running on a given hostname.
*
* @param hostname The hostname the agent is running the job on
* @return A {@link JobInfoAggregate} containing the metadata information
*/
JobInfoAggregate getHostJobInformation(@NotBlank String hostname);
/**
* Get the set of jobs (agent only) whose state is in {@code statuses} and archive status is in
* {@code archiveStatuses} and last updated before {@code updated}.
*
* @param statuses the set of job statuses
* @param archiveStatuses the set of job archive statuses
* @param updated the threshold of last update
* @return a set of job ids
*/
Set<String> getJobsWithStatusAndArchiveStatusUpdatedBefore(
@NotEmpty Set<JobStatus> statuses,
@NotEmpty Set<ArchiveStatus> archiveStatuses,
@NotNull Instant updated
);
//endregion
//endregion
//region General CommonResource APIs
/**
* Add configuration files to the existing set for a resource.
*
* @param <R> The resource type that the configs should be associated with
* @param id The id of the resource to add the configuration file to. Not null/empty/blank.
* @param configs The configuration files to add. Max file length is 1024 characters.
* @param resourceClass The class of the resource
* @throws NotFoundException If no resource of type {@link R} with {@literal id} exists
*/
<R extends CommonResource> void addConfigsToResource(
@NotBlank String id,
Set<@Size(max = 1024) String> configs,
Class<R> resourceClass