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