private void PromoteToInstalledOrRemove(
            string installingPath,
            string installedPath,
            DependencySnapshotInstallationMode installationMode,
            ILogger logger)
        {
            var latestSnapshot = _storage.GetLatestInstalledSnapshot();

            if (latestSnapshot != null && _snapshotComparer.AreEquivalent(installingPath, latestSnapshot, logger))
            {
                logger.Log(
                    isUserOnlyLog: false,
                    LogLevel.Trace,
                    string.Format(PowerShellWorkerStrings.RemovingEquivalentDependencySnapshot, installingPath, latestSnapshot));

                // The new snapshot is not better than the latest installed snapshot,
                // so remove the new snapshot and update the timestamp of the latest snapshot
                // in order to avoid unnecessary worker restarts.
                _storage.RemoveSnapshot(installingPath);
                _storage.SetSnapshotCreationTimeToUtcNow(latestSnapshot);
            }
            else
            {
                PromoteToInstalled(installingPath, installedPath, installationMode, logger);
            }
        }
コード例 #2
0
        public void DoesNotPromoteSnapshotIfSaveModuleKeepsThrowing(DependencySnapshotInstallationMode installationMode)
        {
            var manifestEntries =
                new[] { new DependencyManifestEntry("Module", VersionSpecificationType.ExactVersion, "Version") };

            var dummyPowerShell = PowerShell.Create();

            var injectedException = new Exception("Couldn't save module");

            _mockModuleProvider.Setup(
                _ => _.SaveModule(It.IsAny <PowerShell>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>()))
            .Throws(injectedException);

            _mockStorage.Setup(_ => _.RemoveSnapshot(_targetPathInstalling));

            var installer       = CreateDependenciesSnapshotInstallerWithMocks();
            var thrownException = Assert.Throws <DependencyInstallationException>(
                () => installer.InstallSnapshot(manifestEntries, _targetPathInstalled, dummyPowerShell, installationMode, _mockLogger.Object));

            Assert.Contains(injectedException.Message, thrownException.Message);

            _mockStorage.Verify(_ => _.PromoteInstallingSnapshotToInstalledAtomically(It.IsAny <string>()), Times.Never);
            _mockStorage.Verify(_ => _.RemoveSnapshot(_targetPathInstalling), Times.Once);
            _mockModuleProvider.Verify(_ => _.Cleanup(dummyPowerShell), Times.Once);
        }
コード例 #3
0
        public void PromotesInstallingSnapshotToInstalledIfSaveModuleDoesNotThrow(DependencySnapshotInstallationMode installationMode)
        {
            var manifestEntries =
                new[] { new DependencyManifestEntry("Module", VersionSpecificationType.ExactVersion, "Version") };

            var installer = CreateDependenciesSnapshotInstallerWithMocks();

            installer.InstallSnapshot(manifestEntries, _targetPathInstalled, PowerShell.Create(), installationMode, _mockLogger.Object);

            _mockStorage.Verify(_ => _.CreateInstallingSnapshot(_targetPathInstalled), Times.Once);
            _mockStorage.Verify(_ => _.PromoteInstallingSnapshotToInstalledAtomically(_targetPathInstalled), Times.Once);
            _mockSnapshotContentLogger.Verify(_ => _.LogDependencySnapshotContent(_targetPathInstalled, _mockLogger.Object), Times.Once);
        }
コード例 #4
0
        public void CleansUpPowerShellRunspaceAfterSuccessfullySavingModule(DependencySnapshotInstallationMode installationMode)
        {
            var manifestEntries =
                new[] { new DependencyManifestEntry("Module", VersionSpecificationType.ExactVersion, "Version") };

            var dummyPowerShell = PowerShell.Create();

            var installer = CreateDependenciesSnapshotInstallerWithMocks();

            installer.InstallSnapshot(manifestEntries, _targetPathInstalled, dummyPowerShell, installationMode, _mockLogger.Object);

            _mockModuleProvider.Verify(_ => _.Cleanup(dummyPowerShell), Times.Once);
        }
        private void PromoteToInstalled(
            string installingPath,
            string installedPath,
            DependencySnapshotInstallationMode installationMode,
            ILogger logger)
        {
            _storage.PromoteInstallingSnapshotToInstalledAtomically(installedPath);

            logger.Log(
                isUserOnlyLog: false,
                LogLevel.Trace,
                string.Format(PowerShellWorkerStrings.PromotedDependencySnapshot, installingPath, installedPath, installationMode));

            _snapshotContentLogger.LogDependencySnapshotContent(installedPath, logger);
        }
コード例 #6
0
        public void SavesLatestPublishedVersion_WhenMajorVersionIsSpecified(DependencySnapshotInstallationMode installationMode)
        {
            var manifestEntries =
                new[] { new DependencyManifestEntry("Module", VersionSpecificationType.MajorVersion, "Major version") };

            _mockModuleProvider.Setup(
                _ => _.GetLatestPublishedModuleVersion("Module", "Major version"))
            .Returns("Latest version");

            var installer = CreateDependenciesSnapshotInstallerWithMocks();

            installer.InstallSnapshot(manifestEntries, _targetPathInstalled, PowerShell.Create(), installationMode, _mockLogger.Object);

            _mockModuleProvider.Verify(
                _ => _.SaveModule(It.IsAny <PowerShell>(), "Module", "Latest version", _targetPathInstalling),
                Times.Once);
        }
コード例 #7
0
        public void LogsInstallationStartAndFinish(DependencySnapshotInstallationMode installationMode)
        {
            var manifestEntries =
                new[]
            {
                new DependencyManifestEntry("A", VersionSpecificationType.ExactVersion, "Exact A version"),
                new DependencyManifestEntry("B", VersionSpecificationType.MajorVersion, "Major B version")
            };

            _mockModuleProvider.Setup(
                _ => _.GetLatestPublishedModuleVersion(It.IsAny <string>(), It.IsAny <string>()))
            .Returns("Exact B version");

            var installer = CreateDependenciesSnapshotInstallerWithMocks();

            installer.InstallSnapshot(manifestEntries, _targetPathInstalled, PowerShell.Create(), installationMode, _mockLogger.Object);

            VerifyLoggedOnce(new[] { "Started installing", "A", "Exact A version" });
            VerifyLoggedOnce(new[] { "has been installed", "A", "Exact A version" });
            VerifyLoggedOnce(new[] { "Started installing", "B", "Exact B version" });
            VerifyLoggedOnce(new[] { "has been installed", "B", "Exact B version" });
        }
        public void InstallSnapshot(
            IEnumerable <DependencyManifestEntry> dependencies,
            string targetPath,
            PowerShell pwsh,
            DependencySnapshotInstallationMode installationMode,
            ILogger logger)
        {
            var installingPath = CreateInstallingSnapshot(targetPath);

            logger.Log(
                isUserOnlyLog: false,
                LogLevel.Trace,
                string.Format(
                    PowerShellWorkerStrings.InstallingFunctionAppRequiredModules,
                    installingPath,
                    installationMode));

            try
            {
                foreach (DependencyInfo module in GetExactVersionsOfDependencies(dependencies))
                {
                    InstallModule(module, installingPath, pwsh, logger);
                }

                _snapshotContentLogger.LogDependencySnapshotContent(installingPath, logger);

                switch (installationMode)
                {
                case DependencySnapshotInstallationMode.Optional:
                    // If the new snapshot turns out to be equivalent to the latest one,
                    // removing it helps us save storage space and avoid unnecessary worker restarts.
                    // It is ok to do that during background upgrade because the current
                    // worker already has a good enough snapshot, and nothing depends on
                    // the new snapshot yet.
                    PromoteToInstalledOrRemove(installingPath, targetPath, installationMode, logger);
                    break;

                case DependencySnapshotInstallationMode.Required:
                    // Even if the new snapshot turns out to be equivalent to the latest one,
                    // removing it would not be safe because the current worker already depends
                    // on it, as it has the path to this snapshot already added to PSModulePath.
                    // As opposed to the background upgrade case, this snapshot is *required* for
                    // this worker to run, even though it occupies some space (until the workers
                    // restart and the redundant snapshots are purged).
                    PromoteToInstalled(installingPath, targetPath, installationMode, logger);
                    break;

                default:
                    throw new ArgumentException($"Unexpected installation mode: {installationMode}", nameof(installationMode));
                }
            }
            catch (Exception e)
            {
                var message = string.Format(
                    PowerShellWorkerStrings.FailedToInstallDependenciesSnapshot,
                    targetPath,
                    installationMode);

                logger.Log(isUserOnlyLog: false, LogLevel.Warning, message, e);
                _storage.RemoveSnapshot(installingPath);
                throw;
            }
            finally
            {
                _moduleProvider.Cleanup(pwsh);
            }
        }