/// <summary> /// 引数 NotebookHistory history の属性 CreatedAt/StartedA/CompletedAt の値に従い、 /// 待機時間(WaitingTime)と実行時間(ExecutionTime)を設定する。 /// StartedAt == null 時におては、CompletedAt == null なら Pending 中、 /// CompletedAt != null なら Pending 中にキャンセルしたと判定する。 /// /// 状態 | 待機時間 | 実行時間 /// StartedAt == null and CompletedAt == null | 現時刻 - CreatedAt | null /// StartedAt == null and CompletedAt != null | CompletedAt - CreatedAt | null /// CompletedAt == null | StartedAt - CreatedAt | 現時刻 - StartedAt /// その他(両方とも値有り) | StartedAt - CreatedAt | CompletedAt - StartedAt /// /// </summary> /// <param name="history">ノートブック履歴</param> private void SetWaitingAndExecutionTimes(NotebookHistory history) { if (history.StartedAt == null) { if (history.CompletedAt == null) { // ノートブックコンテナの起動前 (すなわち Pending 中) WaitingTime = GetElapsedTime(DateTime.Now, history.CreatedAt); ExecutionTime = null; } else { // ノートブックコンテナの起動前(Pending 中)にジョブをキャンセルした場合 WaitingTime = GetElapsedTime(history.CompletedAt, history.CreatedAt); ExecutionTime = null; } } else if (history.CompletedAt == null) { // ノートブックコンテナの起動中 WaitingTime = GetElapsedTime(history.StartedAt, history.CreatedAt); ExecutionTime = GetElapsedTime(DateTime.Now, history.StartedAt); } else { // ノートブックコンテナの起動完了 WaitingTime = GetElapsedTime(history.StartedAt, history.CreatedAt); ExecutionTime = GetElapsedTime(history.CompletedAt, history.StartedAt); } }
/// <summary> /// ノートブック履歴コンテナを削除し、ステータスを変更する。 /// </summary> /// <param name="notebookHistory">対象ノートブック履歴</param> /// <param name="status">変更後のステータス</param> /// <param name="force">他テナントに対する変更を許可するか</param> public async Task ExitAsync(NotebookHistory notebookHistory, ContainerStatus status, bool force) { // コンテナの生存確認 if (notebookHistory.GetStatus().Exist()) { var info = await clusterManagementLogic.GetContainerDetailsInfoAsync(notebookHistory.Key, CurrentUserInfo.SelectedTenant.Name, force); // コンテナ削除の前に、DBの更新を先に実行 await notebookHistoryRepository.UpdateStatusAsync(notebookHistory.Id, status, DateTime.Now, force); // 実コンテナ削除の結果は確認せず、DBの更新を確定する(コンテナがいないなら、そのまま消しても問題ない想定) unitOfWork.Commit(); if (info.Status.Exist()) { // 再確認してもまだ存在していたら、コンテナ削除 await clusterManagementLogic.DeleteContainerAsync( ContainerType.Notebook, notebookHistory.Key, CurrentUserInfo.SelectedTenant.Name, force); } } else { await notebookHistoryRepository.UpdateStatusAsync(notebookHistory.Id, status, force); // DBの更新を確定する unitOfWork.Commit(); } }
public SimpleOutputModel(NotebookHistory history) : base(history) { Id = history.Id; DisplayId = history.DisplayId; Name = history.Name; Memo = history.Memo; Status = history.GetStatus().ToString(); FullName = $"{Id}:{Name}"; Favorite = history.Favorite; }
public DetailsOutputModel(NotebookHistory history) : base(history) { Key = history.Key; if (history.DataSet != null) { DataSet = new DataSetApiModels.IndexOutputModel(history.DataSet); } Options = new List<KeyValuePair<string, string>>(); GitModel = new GitCommitOutputModel() { GitId = history.ModelGitId, Repository = history.ModelRepository, Owner = history.ModelRepositoryOwner, Branch = history.ModelBranch, CommitId = history.ModelCommitId }; ContainerImage = new ContainerImageOutputModel() { Image = history.ContainerImage, Tag = history.ContainerTag }; if (history.ContainerRegistryId.HasValue) { ContainerImage.RegistryId = history.ContainerRegistryId.Value; ContainerImage.RegistryName = history.ContainerRegistry.Name; } CompletedAt = history.CompletedAt?.ToFormatedString(); StartedAt = history.StartedAt?.ToFormatedString(); Node = history.Node; Cpu = history.Cpu; Memory = history.Memory; Gpu = history.Gpu; Partition = history.Partition; ExpiresIn = history.ExpiresIn; foreach (var option in history.GetOptionDic()) { Options.Add(new KeyValuePair<string, string>(option.Key, option.Value)); } // 待機時間と実行時間の設定 SetWaitingAndExecutionTimes(history); }
/// <summary> /// ステータスを更新して、出力モデルに変換する /// </summary> /// <param name="history">ノートブック履歴</param> private async Task <IndexOutputModel> GetUpdatedIndexOutputModelAsync(NotebookHistory history) { var model = new IndexOutputModel(history); var status = history.GetStatus(); if (status.Exist()) { //ノートブックコンテナがまだ進行中の場合、情報を更新する var newStatus = await clusterManagementLogic.GetContainerStatusAsync(history.Key, CurrentUserInfo.SelectedTenant.Name, false); if (status.Key != newStatus.Key) { //更新があったので、変更処理 await notebookHistoryRepository.UpdateStatusAsync(history.Id, newStatus, false); unitOfWork.Commit(); model.Status = newStatus.Name; } } return(model); }
public async Task <IActionResult> Create([FromBody] CreateInputModel model, [FromServices] INodeRepository nodeRepository) { //データの入力チェック if (!ModelState.IsValid) { return(JsonBadRequest("Invalid inputs.")); } //データセットが指定されていれば存在チェック if (model.DataSetId.HasValue) { var dataSet = await dataSetRepository.GetByIdAsync(model.DataSetId.Value); if (dataSet == null) { return(JsonNotFound($"DataSet ID {model.DataSetId} is not found.")); } } if (string.IsNullOrEmpty(model.Partition) == false) { bool existPartition = await nodeRepository.IsEnablePartitionAsync(model.Partition, true); if (existPartition == false) { return(JsonNotFound($"There are no enable nodes with Partition {model.Partition}.")); } } // 環境変数名のチェック if (model.Options != null && model.Options.Count > 0) { foreach (var env in model.Options) { if (!string.IsNullOrEmpty(env.Key)) { // フォーマットチェック if (!Regex.IsMatch(env.Key, "^[-._a-zA-Z][-._a-zA-Z0-9]*$")) { return(JsonNotFound($"Invalid envName. Please match the format of '^[-._a-zA-Z][-._a-zA-Z0-9]*$'.")); } } } } //コンテナの実行前に、ノートブック履歴を作成する(コンテナの実行に失敗した場合、そのステータスをユーザに表示するため) var notebookHistory = new NotebookHistory() { DisplayId = -1, Name = model.Name, DataSetId = model.DataSetId, OptionDic = model.Options ?? new Dictionary <string, string>(), //オプションはnullの可能性があるので、その時は初期化 Cpu = model.Cpu.Value, Memory = model.Memory.Value, Gpu = model.Gpu.Value, Partition = model.Partition, Memo = model.Memo, Status = ContainerStatus.Running.Key, StartedAt = DateTime.Now, ExpiresIn = model.ExpiresIn }; //コンテナが指定されているかチェック if (model.ContainerImage != null) { notebookHistory.ContainerRegistryId = model.ContainerImage.RegistryId ?? CurrentUserInfo.SelectedTenant.DefaultRegistry?.Id; notebookHistory.ContainerImage = model.ContainerImage.Image; notebookHistory.ContainerTag = model.ContainerImage.Tag; //latestは運用上使用されていないハズなので、そのまま直接代入 } else { //コンテナイメージの設定がない場合デフォルトのイメージを設定 notebookHistory.ContainerRegistryId = null; notebookHistory.ContainerImage = "tensorflow/tensorflow"; notebookHistory.ContainerTag = "1.13.1-gpu-py3"; } //gitが指定されているかチェック if (model.GitModel != null) { //gitリポジトリ名が指定されていれば、ブランチ、コミットIDを設定。指定されていなければnull long? gitId = model.GitModel.GitId ?? CurrentUserInfo.SelectedTenant.DefaultGit?.Id; string branch = null; string commitId = null; if (!string.IsNullOrEmpty(model.GitModel.Repository)) { branch = model.GitModel.Branch ?? "master"; commitId = model.GitModel.CommitId; //コミットIDが指定されていなければ、ブランチのHEADからコミットIDを取得する if (string.IsNullOrEmpty(commitId)) { commitId = await gitLogic.GetCommitIdAsync(gitId.Value, model.GitModel.Repository, model.GitModel.Owner, branch); if (string.IsNullOrEmpty(commitId)) { //コミットIDが特定できなかったらエラー return(JsonNotFound($"The branch {branch} for {gitId.Value}/{model.GitModel.Owner}/{model.GitModel.Repository} is not found.")); } } } //git情報を設定 notebookHistory.ModelGitId = gitId.Value; notebookHistory.ModelRepository = model.GitModel.Repository; notebookHistory.ModelRepositoryOwner = model.GitModel.Owner; notebookHistory.ModelBranch = branch; notebookHistory.ModelCommitId = commitId; } if (notebookHistory.OptionDic.ContainsKey("")) //空文字は除外する { notebookHistory.OptionDic.Remove(""); } // 親学習が指定されていれば存在チェック if (model.ParentIds != null) { var maps = new List <NotebookHistoryParentTrainingMap>(); foreach (var parentId in model.ParentIds) { var parent = await trainingHistoryRepository.GetByIdAsync(parentId); if (parent == null) { return(JsonNotFound($"Training ID {parentId} is not found.")); } // ノートブック履歴に親学習を紐づける var map = notebookHistoryRepository.AttachParentToNotebookAsync(notebookHistory, parent); if (map != null) { maps.Add(map); } } notebookHistory.ParentTrainingMaps = maps; } notebookHistoryRepository.Add(notebookHistory); unitOfWork.Commit(); var result = await clusterManagementLogic.RunNotebookContainerAsync(notebookHistory); if (result.IsSuccess == false) { //コンテナの起動に失敗した状態。エラーを出力して、保存したノートブック履歴も削除する。 notebookHistoryRepository.Delete(notebookHistory); unitOfWork.Commit(); return(JsonError(HttpStatusCode.ServiceUnavailable, "Failed to run notebook. The message bellow may be help to resolve: " + result.Error)); } //結果に従い、ノートブック結果を更新する。 //実行には時間がかかりうるので、DBから最新の情報を取ってくる notebookHistory = await notebookHistoryRepository.GetByIdAsync(notebookHistory.Id); notebookHistory.Configuration = result.Value.Configuration; notebookHistory.Status = result.Value.Status.Key; unitOfWork.Commit(); if (result.Value.Status.Succeed()) { return(JsonCreated(new SimpleOutputModel(notebookHistory))); } else { return(JsonError(HttpStatusCode.ServiceUnavailable, $"Failed to run notebook. Status={result.Value.Status.Name}. Please contact your server administrator.")); } }
public IndexOutputModel(NotebookHistory history) : base(history) { }
/// <summary> /// コンストラクタ /// </summary> /// <param name="history">ノートブック履歴</param> public DetailsOutputModel(NotebookHistory history) : base(history) { Key = history.Key; if (history.DataSet != null) { DataSet = new DataSetApiModels.IndexOutputModel(history.DataSet); } if (history.ParentTrainingMaps != null) { Parents = new List <TrainingApiModels.IndexOutputModel>(); foreach (var parentTrainingMaps in history.ParentTrainingMaps) { var parent = new TrainingApiModels.IndexOutputModel(parentTrainingMaps.Parent); Parents.Add(parent); } Parents.Sort(delegate(TrainingApiModels.IndexOutputModel parent1, TrainingApiModels.IndexOutputModel parent2) { return(parent1.Id.CompareTo(parent2.Id)); }); } if (history.ParentInferenceMaps != null) { Inferences = new List <InferenceApiModels.InferenceIndexOutputModel>(); foreach (var parentInferenceMap in history.ParentInferenceMaps) { var parentInference = new InferenceApiModels.InferenceIndexOutputModel(parentInferenceMap.Parent); Inferences.Add(parentInference); } Inferences.Sort(delegate(InferenceApiModels.InferenceIndexOutputModel parentInference1, InferenceApiModels.InferenceIndexOutputModel parentInference2) { return(parentInference1.Id.CompareTo(parentInference2.Id)); }); } Options = new List <KeyValuePair <string, string> >(); GitModel = new GitCommitOutputModel() { GitId = history.ModelGitId, Repository = history.ModelRepository, Owner = history.ModelRepositoryOwner, Branch = history.ModelBranch, CommitId = history.ModelCommitId }; ContainerImage = new ContainerImageOutputModel() { Image = history.ContainerImage, Tag = history.ContainerTag }; if (history.ContainerRegistryId.HasValue) { ContainerImage.RegistryId = history.ContainerRegistryId.Value; ContainerImage.RegistryName = history.ContainerRegistry.Name; } CompletedAt = history.CompletedAt?.ToFormatedString(); StartedAt = history.StartedAt?.ToFormatedString(); Node = history.Node; Cpu = history.Cpu; Memory = history.Memory; Gpu = history.Gpu; Partition = history.Partition; JupyterLabVersion = history.JupyterLabVersion; ExpiresIn = history.ExpiresIn; LocalDataSet = history.LocalDataSet; foreach (var option in history.GetOptionDic()) { Options.Add(new KeyValuePair <string, string>(option.Key, option.Value)); } // 待機時間と実行時間の設定 SetWaitingAndExecutionTimes(history); EntryPoint = history.EntryPoint; }