コード例 #1
0
        /// <summary>
        /// Calls the 'scalar maintenance' verb
        /// </summary>
        /// <param name="task">Maintenance task to run</param>
        /// <param name="repoRoot">Repo to maintain</param>
        /// <param name="sessionId">Ignored</param>
        /// <returns>
        /// true if the maintenance verb succeeded, and false otherwise
        /// </returns>
        /// <remarks>
        /// 'CallMaintenance' should only be called for repos that are owned by
        /// the owner of the current process.
        ///
        /// 'launchctl asuser' *could* be used to launch has an arbitrary user,
        /// however, it is not used because it does not pass back the output/errors
        /// of the maintenance verb correctly.
        ///
        /// On Mac this method:
        ///
        ///   - Is only called by Scalar.Service
        ///   - Is only called for repos owned by the same user that's running Scalar.Service
        ///
        /// And so there is no need to use 'launchctl'.
        /// </remarks>
        public bool CallMaintenance(MaintenanceTasks.Task task, string repoRoot, int sessionId)
        {
            string taskVerbName = MaintenanceTasks.GetVerbTaskName(task);
            string arguments    =
                $"run {taskVerbName} \"{repoRoot}\" --{ScalarConstants.VerbParameters.InternalUseOnly} {this.internalVerbJson}";

            ProcessResult result = this.processLauncher.LaunchProcess(this.scalarBinPath, arguments, repoRoot);

            if (result.ExitCode != 0)
            {
                EventMetadata metadata = new EventMetadata();
                metadata.Add("Area", "ScalarVerbRunner");
                metadata.Add(nameof(this.scalarBinPath), this.scalarBinPath);
                metadata.Add(nameof(arguments), arguments);
                metadata.Add(nameof(repoRoot), repoRoot);
                metadata.Add(nameof(result.ExitCode), result.ExitCode);
                metadata.Add(nameof(result.Output), result.Output);
                metadata.Add(nameof(result.Errors), result.Errors);

                this.tracer.RelatedError(metadata, $"{nameof(this.CallMaintenance)}: Maintenance verb failed");
                return(false);
            }

            return(true);
        }
コード例 #2
0
        private bool CallScalarMaintenance(MaintenanceTasks.Task task, string repoRoot, CurrentUser currentUser)
        {
            string taskVerbName = MaintenanceTasks.GetVerbTaskName(task);

            return(currentUser.RunAs(
                       Configuration.Instance.ScalarLocation,
                       $"run {taskVerbName} \"{repoRoot}\" --{ScalarConstants.VerbParameters.InternalUseOnly} {this.internalVerbJson}"));
        }
コード例 #3
0
        public void CallMaintenance_LaunchesVerbUsingCorrectArgs()
        {
            MaintenanceTasks.Task task = MaintenanceTasks.Task.FetchCommitsAndTrees;
            string taskVerbName        = MaintenanceTasks.GetVerbTaskName(task);
            string scalarBinPath       = Path.Combine(this.scalarPlatform.Constants.ScalarBinDirectoryPath, this.scalarPlatform.Constants.ScalarExecutableName);
            string expectedArgs        =
                $"run {taskVerbName} \"{ExpectedActiveRepoPath}\" --{ScalarConstants.VerbParameters.InternalUseOnly} {new InternalVerbParameters(startedByService: true).ToJson()}";

            Mock <MacScalarVerbRunner.ScalarProcessLauncher> procLauncherMock = new Mock <MacScalarVerbRunner.ScalarProcessLauncher>(MockBehavior.Strict, this.tracer);

            procLauncherMock.Setup(mp => mp.LaunchProcess(
                                       scalarBinPath,
                                       expectedArgs,
                                       ExpectedActiveRepoPath))
            .Returns(new ProcessResult(output: string.Empty, errors: string.Empty, exitCode: 0));

            MacScalarVerbRunner verbProcess = new MacScalarVerbRunner(this.tracer, procLauncherMock.Object);

            verbProcess.CallMaintenance(task, ExpectedActiveRepoPath, ExpectedActiveUserId);

            procLauncherMock.VerifyAll();
        }
コード例 #4
0
            private void RunMaintenanceTaskForRepos(UserAndSession registeredUser)
            {
                EventMetadata metadata = new EventMetadata();

                metadata.Add(nameof(this.task), MaintenanceTasks.GetVerbTaskName(this.task));
                metadata.Add(nameof(registeredUser.UserId), registeredUser.UserId);
                metadata.Add(nameof(registeredUser.SessionId), registeredUser.SessionId);

                int  reposSkipped             = 0;
                int  reposSuccessfullyRemoved = 0;
                int  repoRemovalFailures      = 0;
                int  reposMaintained          = 0;
                int  reposInRegistryForUser   = 0;
                bool maintenancePaused        = false;

                string rootPath;
                string errorMessage;
                string traceMessage = null;

                IEnumerable <ScalarRepoRegistration> reposForUser = this.repoRegistry.GetRegisteredRepos().Where(
                    x => x.UserId.Equals(registeredUser.UserId, StringComparison.InvariantCultureIgnoreCase));

                foreach (ScalarRepoRegistration repoRegistration in reposForUser)
                {
                    ++reposInRegistryForUser;

                    if (maintenancePaused || this.IsMaintenancePaused(out traceMessage))
                    {
                        metadata[nameof(traceMessage)] = traceMessage;
                        maintenancePaused = true;
                        ++reposSkipped;
                        continue;
                    }

                    rootPath = Path.GetPathRoot(repoRegistration.NormalizedRepoRoot);

                    metadata[nameof(repoRegistration.NormalizedRepoRoot)] = repoRegistration.NormalizedRepoRoot;
                    metadata[nameof(rootPath)] = rootPath;
                    metadata.Remove(nameof(errorMessage));

                    if (!string.IsNullOrWhiteSpace(rootPath) && !this.fileSystem.DirectoryExists(rootPath))
                    {
                        ++reposSkipped;

                        // If the volume does not exist we'll assume the drive was removed or is encrypted,
                        // and we'll leave the repo in the registry (but we won't run maintenance on it).
                        this.tracer.RelatedEvent(
                            EventLevel.Informational,
                            $"{nameof(this.RunMaintenanceTaskForRepos)}_SkippedRepoWithMissingVolume",
                            metadata);

                        continue;
                    }

                    if (!this.fileSystem.DirectoryExists(repoRegistration.NormalizedRepoRoot))
                    {
                        // The repo is no longer on disk (but its volume is present)
                        // Unregister the repo
                        if (this.repoRegistry.TryUnregisterRepo(repoRegistration.NormalizedRepoRoot, out errorMessage))
                        {
                            ++reposSuccessfullyRemoved;
                            this.tracer.RelatedEvent(
                                EventLevel.Informational,
                                $"{nameof(this.RunMaintenanceTaskForRepos)}_RemovedMissingRepo",
                                metadata);
                        }
                        else
                        {
                            ++repoRemovalFailures;
                            metadata[nameof(errorMessage)] = errorMessage;
                            this.tracer.RelatedEvent(
                                EventLevel.Warning,
                                $"{nameof(this.RunMaintenanceTaskForRepos)}_FailedToRemoveRepo",
                                metadata);
                        }

                        continue;
                    }

                    ++reposMaintained;
                    this.tracer.RelatedEvent(
                        EventLevel.Informational,
                        $"{nameof(this.RunMaintenanceTaskForRepos)}_CallingMaintenance",
                        metadata);

                    this.scalarVerb.CallMaintenance(this.task, repoRegistration.NormalizedRepoRoot, registeredUser.SessionId);
                }

                metadata.Add(nameof(reposInRegistryForUser), reposInRegistryForUser);
                metadata.Add(nameof(reposSkipped), reposSkipped);
                metadata.Add(nameof(reposSuccessfullyRemoved), reposSuccessfullyRemoved);
                metadata.Add(nameof(repoRemovalFailures), repoRemovalFailures);
                metadata.Add(nameof(reposMaintained), reposMaintained);
                metadata.Add(nameof(maintenancePaused), maintenancePaused);
                this.tracer.RelatedEvent(
                    EventLevel.Informational,
                    $"{nameof(this.RunMaintenanceTaskForRepos)}_MaintenanceSummary",
                    metadata);
            }