示例#1
0
        public async Task <FunctionEnvelope> CreateOrUpdateAsync(string name, FunctionEnvelope functionEnvelope, Action setConfigChanged)
        {
            var functionDir = Path.Combine(_environment.FunctionsPath, name);

            // Make sure the function folder exists
            if (!FileSystemHelpers.DirectoryExists(functionDir))
            {
                // Cleanup any leftover artifacts from a function with the same name before.
                DeleteFunctionArtifacts(name);
                FileSystemHelpers.EnsureDirectory(functionDir);
            }

            string newConfig    = null;
            string configPath   = Path.Combine(functionDir, Constants.FunctionsConfigFile);
            string dataFilePath = GetFunctionTestDataFilePath(name);

            // If files are included, write them out
            if (functionEnvelope?.Files != null)
            {
                // If the config is passed in the file collection, save it and don't process it as a file
                if (functionEnvelope.Files.TryGetValue(Constants.FunctionsConfigFile, out newConfig))
                {
                    functionEnvelope.Files.Remove(Constants.FunctionsConfigFile);
                }

                // Delete all existing files in the directory. This will also delete current function.json, but it gets recreated below
                FileSystemHelpers.DeleteDirectoryContentsSafe(functionDir);

                await Task.WhenAll(functionEnvelope.Files.Select(e => FileSystemHelpers.WriteAllTextToFileAsync(Path.Combine(functionDir, e.Key), e.Value)));
            }

            // Get the config (if it was not already passed in as a file)
            if (newConfig == null && functionEnvelope?.Config != null)
            {
                newConfig = JsonConvert.SerializeObject(functionEnvelope?.Config, Formatting.Indented);
            }

            // Get the current config, if any
            string currentConfig = null;

            if (FileSystemHelpers.FileExists(configPath))
            {
                currentConfig = await FileSystemHelpers.ReadAllTextFromFileAsync(configPath);
            }

            // Save the file and set changed flag is it has changed. This helps optimize the syncTriggers call
            if (newConfig != currentConfig)
            {
                await FileSystemHelpers.WriteAllTextToFileAsync(configPath, newConfig);

                setConfigChanged();
            }

            if (functionEnvelope?.TestData != null)
            {
                await FileSystemHelpers.WriteAllTextToFileAsync(dataFilePath, functionEnvelope.TestData);
            }

            return(await GetFunctionConfigAsync(name)); // test_data took from incoming request, it will not exceed the limit
        }
示例#2
0
        private string RefreshShutdownNotificationFilePath(string jobName, string jobsTypePath)
        {
            string shutdownFilesDirectory = Path.Combine(Environment.TempPath, "JobsShutdown", jobsTypePath, jobName);

            FileSystemHelpers.DeleteDirectoryContentsSafe(shutdownFilesDirectory, ignoreErrors: true);
            return(Path.Combine(shutdownFilesDirectory, Path.GetRandomFileName()));
        }
示例#3
0
        /// <summary>
        /// Specifically used for Linux Consumption to support Server Side build scenario
        /// </summary>
        /// <param name="context"></param>
        public static async Task SetupLinuxConsumptionFunctionAppDeployment(
            IEnvironment env,
            IDeploymentSettingsManager settings,
            DeploymentContext context,
            bool shouldSyncTriggers)
        {
            string sas = settings.GetValue(Constants.ScmRunFromPackage) ?? System.Environment.GetEnvironmentVariable(Constants.ScmRunFromPackage);

            string builtFolder     = context.OutputPath;
            string packageFolder   = env.DeploymentsPath;
            string packageFileName = OryxBuildConstants.FunctionAppBuildSettings.LinuxConsumptionArtifactName;

            // Package built content from oryx build artifact
            string filePath = PackageArtifactFromFolder(env, settings, context, builtFolder, packageFolder, packageFileName);

            // Log function app dependencies to kusto (requirements.txt, package.json, .csproj)
            await LogDependenciesFile(context.RepositoryPath);

            // Upload from DeploymentsPath
            await UploadLinuxConsumptionFunctionAppBuiltContent(context, sas, filePath);

            // Clean up local built content
            FileSystemHelpers.DeleteDirectoryContentsSafe(context.OutputPath);

            // Remove Linux consumption plan functionapp workers for the site
            await RemoveLinuxConsumptionFunctionAppWorkers(context);

            // Invoke a warmup call to the main function site
            if (shouldSyncTriggers)
            {
                await Task.Delay(TimeSpan.FromSeconds(5));
                await FunctionHostSyncTriggersAsync(context);
            }
        }
示例#4
0
        public static void CopyWithManifest(string sourcePath, string destinationPath, IDeploymentManifestReader previousManifest, bool skipOldFiles = true)
        {
            sourcePath      = Path.GetFullPath(sourcePath);
            destinationPath = Path.GetFullPath(destinationPath);

            using (var progressWriter = new ProgressWriter())
            {
                progressWriter.Start();

                if (previousManifest != null)
                {
                    var previousFiles = new HashSet <string>(previousManifest.GetPaths(), StringComparer.OrdinalIgnoreCase);

                    SmartCopy(sourcePath, destinationPath, previousFiles.Contains, new DirectoryInfoWrapper(new DirectoryInfo(sourcePath)), new DirectoryInfoWrapper(new DirectoryInfo(destinationPath)), path => new DirectoryInfoWrapper(new DirectoryInfo(path)));
                }
                else
                {
                    // On first deployment, delete the contents of the destination path before copying
                    FileSystemHelpers.DeleteDirectoryContentsSafe(destinationPath);

                    // If there's no manifest then there's nothing to copy
                    FileSystemHelpers.Copy(sourcePath, destinationPath);
                }
            }
        }
        public async Task <bool> UninstallExtension(string id)
        {
            ITracer tracer = _traceFactory.GetTracer();

            string installationDirectory = GetInstallationDirectory(id);

            SiteExtensionInfo info = await GetLocalExtension(id, checkLatest : false);

            if (info == null || !FileSystemHelpers.DirectoryExists(info.LocalPath))
            {
                tracer.TraceError("Site extension {0} not found.", id);
                throw new DirectoryNotFoundException(installationDirectory);
            }

            if (IsInstalledToWebRoot(id))
            {
                // special handling for package that install in wwwroot instead of under site extension folder
                tracer.Trace("Clear all content in wwwroot");
                OperationManager.Attempt(() => FileSystemHelpers.DeleteDirectoryContentsSafe(_environment.WebRootPath));
            }
            else
            {
                // default action for site extension uninstall

                // only site extension has below infomation
                var externalCommandFactory = new ExternalCommandFactory(_environment, _settings, installationDirectory);

                string uninstallScript = Path.Combine(installationDirectory, _uninstallScriptName);

                if (FileSystemHelpers.FileExists(uninstallScript))
                {
                    using (tracer.Step("Execute uninstall.cmd"))
                    {
                        OperationManager.Attempt(() =>
                        {
                            Executable exe = externalCommandFactory.BuildCommandExecutable(uninstallScript,
                                                                                           installationDirectory,
                                                                                           _settings.GetCommandIdleTimeout(), NullLogger.Instance);
                            exe.ExecuteWithProgressWriter(NullLogger.Instance, _traceFactory.GetTracer(), String.Empty);
                        });
                    }
                }

                using (tracer.Step("Remove site extension job"))
                {
                    OperationManager.Attempt(() => CleanupSiteExtensionJobs(id));
                }
            }

            using (tracer.Step("Delete site extension package, directory and arm settings"))
            {
                OperationManager.Attempt(() => FileSystemHelpers.DeleteFileSafe(GetNuGetPackageFile(info.Id, info.Version)));
                OperationManager.Attempt(() => FileSystemHelpers.DeleteDirectorySafe(installationDirectory));
                SiteExtensionStatus armSettings = new SiteExtensionStatus(_environment.SiteExtensionSettingsPath, id, tracer);
                await armSettings.RemoveStatus();
            }

            return(await GetLocalExtension(id, checkLatest : false) == null);
        }
        public void Delete(int deleteWebRoot = 0, int ignoreErrors = 0)
        {
            // Fail if a deployment is in progress
            bool acquired = _deploymentLock.TryLockOperation(() =>
            {
                using (_tracer.Step("Deleting repository"))
                {
                    string repositoryPath = Path.Combine(_environment.SiteRootPath, Constants.RepositoryPath);
                    if (String.Equals(repositoryPath, _environment.RepositoryPath, StringComparison.OrdinalIgnoreCase))
                    {
                        // Delete the repository
                        FileSystemHelpers.DeleteDirectorySafe(_environment.RepositoryPath, ignoreErrors != 0);
                    }
                    else
                    {
                        // Just delete .git folder
                        FileSystemHelpers.DeleteDirectorySafe(Path.Combine(_environment.RepositoryPath, ".git"), ignoreErrors != 0);

                        FileSystemHelpers.DeleteDirectorySafe(Path.Combine(_environment.RepositoryPath, ".hg"), ignoreErrors != 0);
                    }
                }

                using (_tracer.Step("Deleting ssh key"))
                {
                    // Delete the ssh key
                    FileSystemHelpers.DeleteDirectorySafe(_environment.SSHKeyPath, ignoreErrors != 0);
                }

                if (deleteWebRoot != 0)
                {
                    using (_tracer.Step("Deleting web root"))
                    {
                        // Delete the wwwroot folder
                        FileSystemHelpers.DeleteDirectoryContentsSafe(_environment.WebRootPath, ignoreErrors != 0);
                    }

                    using (_tracer.Step("Deleting diagnostics"))
                    {
                        // Delete the diagnostic log. This is a slight abuse of deleteWebRoot, but the
                        // real semantic is more to reset the site to a fully clean state
                        FileSystemHelpers.DeleteDirectorySafe(_environment.DiagnosticsPath, ignoreErrors != 0);
                    }
                }

                using (_tracer.Step("Deleting deployment cache"))
                {
                    // Delete the deployment cache
                    FileSystemHelpers.DeleteDirectorySafe(_environment.DeploymentsPath, ignoreErrors != 0);
                }
            }, TimeSpan.Zero);

            if (!acquired)
            {
                HttpResponseMessage response = Request.CreateErrorResponse(HttpStatusCode.Conflict, Resources.Error_DeploymentInProgess);
                throw new HttpResponseException(response);
            }
        }
示例#7
0
        public void RemoveAllFilesInDirectory(string directoryPath, StorageLocation location, string blobSasUri)
        {
            if (UseBlobStorage(location, blobSasUri))
            {
                return;
            }

            string baseDir  = GetRootStoragePathForWhenBlobStorageIsNotConfigured(location);
            string fullPath = Path.Combine(baseDir, directoryPath);

            if (System.IO.File.Exists(fullPath))
            {
                FileSystemHelpers.DeleteDirectoryContentsSafe(fullPath);
            }
        }
        /// <summary>
        /// Specifically used for Linux Consumption to support Server Side build scenario
        /// </summary>
        /// <param name="context"></param>
        public static async Task SetupLinuxConsumptionFunctionAppDeployment(
            IEnvironment env,
            IDeploymentSettingsManager settings,
            DeploymentContext context,
            bool shouldSyncTriggers,
            bool shouldUpdateWebsiteRunFromPackage)
        {
            string builtFolder     = context.OutputPath;
            string packageFolder   = env.ArtifactsPath;
            string packageFileName = OryxBuildConstants.FunctionAppBuildSettings.LinuxConsumptionArtifactName;

            // Indicate the memory limitation on Linux Consumption
            context.Logger.Log($"Linux Consumption plan has a 1.5 GB memory limit on a remote build container.");
            context.Logger.Log($"To check our service limit, please visit https://docs.microsoft.com/en-us/azure/azure-functions/functions-scale#service-limits");

            // Try create a placeholder blob in AzureWebJobsStorage
            CloudBlockBlob blob = await GetPlaceholderBlob(context, settings, shouldUpdateWebsiteRunFromPackage);

            // Package built content from oryx build artifact
            string filePath = PackageArtifactFromFolder(env, settings, context, builtFolder, packageFolder, packageFileName);

            // Log function app dependencies to kusto (requirements.txt, package.json, .csproj)
            await LogDependenciesFile(context.RepositoryPath);

            // Upload from DeploymentsPath
            await UploadLinuxConsumptionFunctionAppBuiltContent(context, blob, filePath);

            // Clean up local built content
            FileSystemHelpers.DeleteDirectoryContentsSafe(context.OutputPath);

            // Change WEBSITE_RUN_FROM_PACKAGE app setting
            if (shouldUpdateWebsiteRunFromPackage)
            {
                await UpdateWebsiteRunFromPackageAppSetting(context, blob);
            }

            // Remove Linux consumption plan functionapp workers for the site
            await RemoveLinuxConsumptionFunctionAppWorkers(context);

            // Invoke a warmup call to the main function site
            if (shouldSyncTriggers)
            {
                await Task.Delay(TimeSpan.FromSeconds(5));
                await FunctionHostSyncTriggersAsync(context);
            }
        }
示例#9
0
        public async Task RemoveStatus()
        {
            try
            {
                string dirName = Path.GetDirectoryName(_filePath);
                if (FileSystemHelpers.DirectoryExists(dirName))
                {
                    FileSystemHelpers.DeleteDirectoryContentsSafe(dirName);
                    // call DeleteDirectorySafe directly would sometime causing "Access denied" on folder
                    // work-around: remove content and wait briefly before delete folder
                    await Task.Delay(300);

                    FileSystemHelpers.DeleteDirectorySafe(dirName);
                }
            }
            catch (Exception ex)
            {
                // no-op
                _tracer.TraceError(ex);
            }
        }
示例#10
0
        /// <summary>
        /// <para>Check if there is damanged leftover data</para>
        /// <para>If there is leftover data, will try to cleanup.</para>
        /// <para>If fail to cleanup, will move leftover data to Temp folder</para>
        /// </summary>
        private static void EnsureInstallationEnviroment(string installationDir, ITracer tracer)
        {
            // folder is there but nupkg is gone, means previous uninstallation must encounter some error
            bool isInstalledPackageBroken = FileSystemHelpers.DirectoryExists(installationDir) && FileSystemHelpers.GetFiles(installationDir, "*.nupkg").Length == 0;

            if (!isInstalledPackageBroken)
            {
                return;
            }

            using (tracer.Step("There was leftover data from previous uninstallation. Trying to cleanup now."))
            {
                try
                {
                    OperationManager.Attempt(() => FileSystemHelpers.DeleteDirectorySafe(installationDir, ignoreErrors: false));
                    return;
                }
                catch (Exception ex)
                {
                    tracer.TraceError(ex);
                }

                FileSystemHelpers.EnsureDirectory(_toBeDeletedDirectoryPath);
                DirectoryInfo dirInfo  = new DirectoryInfo(installationDir);
                string        tmpFoder = Path.Combine(
                    _toBeDeletedDirectoryPath,
                    string.Format(CultureInfo.InvariantCulture, "{0}-{1}", dirInfo.Name, Guid.NewGuid().ToString("N").Substring(0, 8)));

                using (tracer.Step("Failed to cleanup. Moving leftover data to {0}", tmpFoder))
                {
                    // if failed, let exception bubble up to trigger bad request
                    OperationManager.Attempt(() => FileSystemHelpers.MoveDirectory(installationDir, tmpFoder));
                }
            }

            FileSystemHelpers.DeleteDirectoryContentsSafe(_toBeDeletedDirectoryPath);
        }
示例#11
0
        public void Delete(int deleteWebRoot = 0, int ignoreErrors = 0)
        {
            try
            {
                // Fail if a deployment is in progress
                _deploymentLock.LockOperation(() =>
                {
                    using (_tracer.Step("Deleting repository"))
                    {
                        string repositoryPath = Path.Combine(_environment.SiteRootPath, Constants.RepositoryPath);
                        if (String.Equals(repositoryPath, _environment.RepositoryPath, StringComparison.OrdinalIgnoreCase))
                        {
                            // Delete the repository
                            FileSystemHelpers.DeleteDirectorySafe(_environment.RepositoryPath, ignoreErrors != 0);
                        }
                        else
                        {
                            // Just delete .git folder
                            FileSystemHelpers.DeleteDirectorySafe(Path.Combine(_environment.RepositoryPath, ".git"), ignoreErrors != 0);

                            FileSystemHelpers.DeleteDirectorySafe(Path.Combine(_environment.RepositoryPath, ".hg"), ignoreErrors != 0);
                        }
                    }

                    using (_tracer.Step("Delete auto swap lock file"))
                    {
                        FileSystemHelpers.DeleteFileSafe(Path.Combine(_environment.LocksPath, AutoSwapHandler.AutoSwapLockFile));
                    }

                    using (_tracer.Step("Deleting ssh key"))
                    {
                        // Delete the ssh key
                        FileSystemHelpers.DeleteDirectorySafe(_environment.SSHKeyPath, ignoreErrors != 0);
                    }

                    if (deleteWebRoot != 0)
                    {
                        // This logic is primarily used to help with site reuse during test.
                        // The flag is not documented for general use.

                        using (_tracer.Step("Deleting web root"))
                        {
                            // Delete the wwwroot folder
                            FileSystemHelpers.DeleteDirectoryContentsSafe(_environment.WebRootPath, ignoreErrors != 0);
                        }

                        using (_tracer.Step("Deleting diagnostics"))
                        {
                            // Delete the diagnostic log. This is a slight abuse of deleteWebRoot, but the
                            // real semantic is more to reset the site to a fully clean state
                            FileSystemHelpers.DeleteDirectorySafe(_environment.DiagnosticsPath, ignoreErrors != 0);
                        }

                        using (_tracer.Step("Deleting ASP.NET 5 approot"))
                        {
                            // Delete the approot folder used by ASP.NET 5 apps
                            FileSystemHelpers.DeleteDirectorySafe(Path.Combine(_environment.SiteRootPath, "approot"), ignoreErrors != 0);
                        }

                        // Delete first deployment manifest since it is no longer needed
                        FileSystemHelpers.DeleteFileSafe(Path.Combine(_environment.SiteRootPath, Constants.FirstDeploymentManifestFileName));
                    }
                    else
                    {
                        using (_tracer.Step("Updating initial deployment manifest"))
                        {
                            // The active deployment manifest becomes the baseline initial deployment manifest
                            // When SCM is reconnected, the new deployment will use this manifest to clean the wwwroot
                            SaveInitialDeploymentManifest();
                        }
                    }

                    using (_tracer.Step("Deleting deployment cache"))
                    {
                        // Delete the deployment cache
                        FileSystemHelpers.DeleteDirectorySafe(_environment.DeploymentsPath, ignoreErrors != 0);
                    }
                }, "Deleting repository", TimeSpan.Zero);
            }
            catch (LockOperationException ex)
            {
                HttpResponseMessage response = Request.CreateErrorResponse(HttpStatusCode.Conflict, ex.Message);
                throw new HttpResponseException(response);
            }
        }