public async Task <IActionResult> GetTensorBoardStatus(long id, [FromServices] IOptions <ContainerManageOptions> options) { //データの存在チェック var trainingHistory = await trainingHistoryRepository.GetByIdAsync(id); if (trainingHistory == null) { return(JsonNotFound($"Training ID {id} is not found.")); } //学習履歴IDとテナントIDが等しく、Disable状態じゃないコンテナをDBから取得する TensorBoardContainer container = tensorBoardContainerRepository.GetAvailableContainer(id); //以下、Jsonで返却するパラメータ ContainerStatus status = ContainerStatus.None; //コンテナのステータス // 対象コンテナ情報が存在する場合、その結果を返す if (container != null) { //コンテナのステータスを最新にする status = await clusterManagementLogic.SyncContainerStatusAsync(container, false); } return(JsonOK(new TensorBoardOutputModel(container, status, options.Value.WebEndPoint))); }
public TensorBoardOutputModel(TensorBoardContainer container, ContainerStatus status, string endpoint = null) { Status = status.Name; StatusType = status.StatusType; if (container != null) { Name = container.Name; if (status.Exist() && string.IsNullOrEmpty(container.Host) == false) { //ノードポート番号を返す NodePort = container.PortNo.ToString(); } // 残り生存時間を計算する if (container.ExpiresIn.HasValue && container.ExpiresIn.Value != 0) { long elapsedTicks = container.StartedAt.AddSeconds(container.ExpiresIn.Value).Ticks - DateTime.Now.Ticks; TimeSpan elapsedSpan = new TimeSpan(elapsedTicks); if (elapsedSpan.Ticks < 0) { RemainingTime = "0d 0h 0m"; } else { RemainingTime = elapsedSpan.ToString(@"%d'd '%h'h '%m'm'", CultureInfo.InvariantCulture); } } else { // 生存時間が無期限の場合はnullを返す RemainingTime = null; } } }
public async Task <IActionResult> RunTensorBoard(long id, [FromBody] TensorBoardInputModel model) { //データの存在チェック var trainingHistory = await trainingHistoryRepository.GetByIdAsync(id); if (trainingHistory == null) { return(JsonNotFound($"Training ID {id} is not found.")); } //学習履歴IDとテナントIDが等しく、Disable状態じゃないコンテナを取得する TensorBoardContainer container = tensorBoardContainerRepository.GetAvailableContainer(id); // 当該レコードが存在する場合、時間差で他の人が立てたとみなし、何もしない if (container != null) { var status = ContainerStatus.Convert(container.Status); return(JsonOK(new TensorBoardOutputModel(container, status, containerOptions.WebEndPoint))); } // コンテナ生存期間 int expiresIn = 0; // 無期限だが、DeleteTensorBoardContainerTimerの動作タイミングで削除する if (model.ExpiresIn.HasValue) { // 値が存在する場合、その期間起動させる expiresIn = model.ExpiresIn.Value; } //新規にTensorBoardコンテナを起動する。 var result = await clusterManagementLogic.RunTensorBoardContainerAsync(trainingHistory, expiresIn, model.selectedHistoryIds); if (result == null || result.Status.Succeed() == false) { //起動に失敗した場合、ステータス Failed で返す。 return(JsonError(HttpStatusCode.ServiceUnavailable, $"Failed to run tensorboard container: {result.Status}")); } container = new TensorBoardContainer() { Name = result.Name, StartedAt = DateTime.Now, Status = result.Status.Name, TenantId = CurrentUserInfo.SelectedTenant.Id, TrainingHistoryId = id, Host = result.Host, PortNo = result.Port, ExpiresIn = expiresIn, MountedTrainingHistoryIdList = model.selectedHistoryIds }; // コンテナテーブルにInsertする tensorBoardContainerRepository.Add(container); unitOfWork.Commit(); return(JsonOK(new TensorBoardOutputModel(container, result.Status, containerOptions.WebEndPoint))); }
/// <summary> /// TensorBoardコンテナを削除する。 /// </summary> /// <param name="container">対象コンテナ</param> /// <param name="force">他テナントに対する変更を許可するか</param> public async Task DeleteTensorBoardAsync(TensorBoardContainer container, bool force) { //TensorBoardコンテナを削除する。 await clusterManagementLogic.DeleteContainerAsync(ContainerType.TensorBoard, container.Name, CurrentUserInfo.SelectedTenant.Name, force); //結果に関わらず、DBからコンテナ情報を消す tensorBoardContainerRepository.Delete(container, force); unitOfWork.Commit(); }
/// <summary> /// 指定したTensorBoardコンテナのステータスをクラスタ管理サービスに問い合わせ、結果でDBを更新する。 /// </summary> /// <remark> /// TensorBoardコンテナの場合、以下の理由から、エラーが発生した場合は即DBからも削除してしまう。 /// ・履歴管理をする必要がない /// ・名前に時刻が入っているので、もしコンテナが残っていても次回起動には支障がない。 /// </remark> public async Task <ContainerStatus> SyncContainerStatusAsync(TensorBoardContainer container, bool force) { ContainerStatus result; if (string.IsNullOrEmpty(container.Host)) { //ホストが決まっていない=リソースに空きがなくて、待っている状態 var info = await GetContainerEndpointInfoAsync(container.Name, CurrentUserInfo.SelectedTenant.Name, false); result = info.Status; var endpoint = info.EndPoints?.FirstOrDefault(e => e.Key == "tensorboard"); if (endpoint != null) { //ノードが立ったので、ポート情報を更新する //どんな状態のインスタンスが引数で与えられるかわからないので、改めて取得して更新 var nextStatusContainer = await tensorBoardContainerRepository.GetByIdAsync(container.Id); nextStatusContainer.Host = endpoint.Host; nextStatusContainer.PortNo = endpoint.Port; nextStatusContainer.Status = result.Name; tensorBoardContainerRepository.Update(nextStatusContainer); unitOfWork.Commit(); return(info.Status); } //まだホストが決まっていない場合は、後段処理を実行(対象コンテナがないかもしれないから) } else { result = await GetContainerStatusAsync(container.Name, container.Tenant.Name, force); } if (result.Exist() == false) { //コンテナがすでに停止しているので、ログを出した後でDBから対象レコードを削除 LogInformation($"ステータス {result.Name} のTensorBoardコンテナ {container.Id} {container.Name} を削除します。"); tensorBoardContainerRepository.Delete(container, force); unitOfWork.Commit(); } else { bool updateResult = tensorBoardContainerRepository.UpdateStatus(container.Id, result.Name, true); if (updateResult == false) { //削除対象がすでに消えていた場合 return(ContainerStatus.None); } unitOfWork.Commit(); } return(result); }
public async Task <IActionResult> DeleteTensorBoard(long id) { //学習履歴IDとテナントIDが等しく、Disable状態じゃないコンテナを取得する TensorBoardContainer container = tensorBoardContainerRepository.GetAvailableContainer(id); // 当該レコードが存在しない場合、404エラー if (container == null) { return(JsonNotFound($"TensorBoard container for TrainingHistory ID {id} is not found.")); } await trainingLogic.DeleteTensorBoardAsync(container, false); return(JsonNoContent()); }
public TensorBoardOutputModel(TensorBoardContainer container, ContainerStatus status, string endpoint = null) { Status = status.Name; StatusType = status.StatusType; if (container != null) { Name = container.Name; if (status.Exist() && string.IsNullOrEmpty(container.Host) == false) { //リバプロなどでノードのホスト名ではなく、共通のエンドポイントを使える場合は、そっちを使う string host = string.IsNullOrEmpty(endpoint) ? container.Host : endpoint; Url = new UriBuilder("http", host, (int)container.PortNo).ToString(); } } }
public async Task <IActionResult> RunTensorBoard(long id, [FromServices] IOptions <ContainerManageOptions> options) { //データの存在チェック var trainingHistory = await trainingHistoryRepository.GetByIdAsync(id); if (trainingHistory == null) { return(JsonNotFound($"Training ID {id} is not found.")); } //学習履歴IDとテナントIDが等しく、Disable状態じゃないコンテナを取得する TensorBoardContainer container = tensorBoardContainerRepository.GetAvailableContainer(id); // 当該レコードが存在する場合、時間差で他の人が立てたとみなし、何もしない if (container != null) { var status = ContainerStatus.Convert(container.Status); return(JsonOK(new TensorBoardOutputModel(container, status, options.Value.WebEndPoint))); } //新規にTensorBoardコンテナを起動する。 var result = await clusterManagementLogic.RunTensorBoardContainerAsync(trainingHistory); if (result == null || result.Status.Succeed() == false) { //起動に失敗した場合、ステータス Failed で返す。 return(JsonError(System.Net.HttpStatusCode.ServiceUnavailable, $"Failed to run tensorboard container: {result.Status}")); } container = new TensorBoardContainer() { Name = result.Name, StartedAt = DateTime.Now, Status = result.Status.Name, TenantId = CurrentUserInfo.SelectedTenant.Id, TrainingHistoryId = id, Host = result.Host, PortNo = result.Port }; // コンテナテーブルにInsertする tensorBoardContainerRepository.Add(container); unitOfWork.Commit(); return(JsonOK(new TensorBoardOutputModel(container, result.Status, options.Value.WebEndPoint))); }
public async Task <IActionResult> Delete(long?id) { //データの入力チェック if (id == null) { return(JsonBadRequest("Invalid inputs.")); } //データの存在チェック var trainingHistory = await trainingHistoryRepository.GetByIdAsync(id.Value); if (trainingHistory == null) { return(JsonNotFound($"Training ID {id} is not found.")); } //ステータスを確認 var status = trainingHistory.GetStatus(); if (status.Exist()) { //学習がまだ進行中の場合、情報を更新する status = await clusterManagementLogic.GetContainerStatusAsync(trainingHistory.Key, CurrentUserInfo.SelectedTenant.Name, false); } //派生した学習履歴があったら消せない var child = trainingHistoryRepository.Find(t => t.ParentId == trainingHistory.Id); if (child != null) { return(JsonConflict($"There is another training which is derived from training {trainingHistory.Id}.")); } //学習結果を利用した推論ジョブがあったら消せない var inference = inferenceHistoryRepository.Find(t => t.ParentId == trainingHistory.Id); if (inference != null) { return(JsonConflict($"Training training {trainingHistory.Id} has been used by inference.")); } if (status.Exist()) { //実行中であれば、コンテナを削除 await clusterManagementLogic.DeleteContainerAsync( ContainerType.Training, trainingHistory.Key, CurrentUserInfo.SelectedTenant.Name, false); } //TensorBoardを起動中だった場合は、そっちも消す TensorBoardContainer container = tensorBoardContainerRepository.GetAvailableContainer(trainingHistory.Id); if (container != null) { await clusterManagementLogic.DeleteContainerAsync( ContainerType.TensorBoard, container.Name, CurrentUserInfo.SelectedTenant.Name, false); tensorBoardContainerRepository.Delete(container, true); } //添付ファイルがあったらまとめて消す var files = await trainingHistoryRepository.GetAllAttachedFilesAsync(trainingHistory.Id); foreach (var file in files) { trainingHistoryRepository.DeleteAttachedFile(file); await storageLogic.DeleteFileAsync(ResourceType.TrainingHistoryAttachedFiles, file.StoredPath); } trainingHistoryRepository.Delete(trainingHistory); unitOfWork.Commit(); return(JsonNoContent()); }