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;
                }
            }
        }
Beispiel #3
0
        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)));
        }
Beispiel #4
0
        /// <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());
        }
Beispiel #7
0
        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());
        }