Example #1
0
    protected async Task <(HttpStatusCode Code, Uri PollUrl)> PostFileAsync(IPublishingProfile pp, HttpClient client, string path)
    {
        var slotHost     = pp.GitUrl.Split(':')[0];
        var zipDeployUrl = new UriBuilder()
        {
            Scheme = "https", Host = slotHost, Path = "/api/zipdeploy", Query = "isAsync=true"
        }.ToString();

        using (var fs = File.OpenRead(path))
        {
            var(code, pollUrl) = await HttpPolicy.ExecuteAsync(async() =>
            {
                Console.WriteLine($"HTTP: POST {fs.Length / 1024.0:f1} KiB to {zipDeployUrl}");

                using (var response = await client.PostAsync(zipDeployUrl, new StreamContent(fs)))
                {
                    var pollUrl = response.Headers.Location;

                    Console.WriteLine("  > " + response.StatusCode);

                    return(response.StatusCode, pollUrl);
                }
            });

            return(code, pollUrl);
        }
    }
Example #2
0
    protected HttpClient CreateHttpClient(IPublishingProfile pp)
    {
        var handler = new HttpClientHandler {
            Credentials = new NetworkCredential(pp.GitUsername, pp.GitPassword)
        };

        return(new HttpClient(handler)
        {
            Timeout = TimeSpan.FromMinutes(30)
        });
    }
        private static FtpWebRequest CreateRequest(IPublishingProfile publishingProfile, Uri address, string method)
        {
            var request = (FtpWebRequest)WebRequest.Create(address);

            request.Method              = method;
            request.KeepAlive           = true;
            request.UseBinary           = true;
            request.UsePassive          = false;
            request.Credentials         = new NetworkCredential(publishingProfile.FtpUsername, publishingProfile.FtpPassword);
            request.ConnectionGroupName = "group";
            return(request);
        }
Example #4
0
        private static void UploadFileToWebApp(IPublishingProfile profile, string filePath, string fileName = null)
        {
            if (HttpMockServer.Mode != HttpRecorderMode.Playback)
            {
                string host = profile.FtpUrl.Split(new char[] { '/' }, 2)[0];

                using (var ftpClient = new FtpClient(new FtpClientConfiguration
                {
                    Host = host,
                    Username = profile.FtpUsername,
                    Password = profile.FtpPassword
                }))
                {
                    var fileinfo = new FileInfo(filePath);
                    ftpClient.LoginAsync().GetAwaiter().GetResult();
                    if (!ftpClient.ListDirectoriesAsync().GetAwaiter().GetResult().Any(fni => fni.Name == "site"))
                    {
                        ftpClient.CreateDirectoryAsync("site").GetAwaiter().GetResult();
                    }
                    ftpClient.ChangeWorkingDirectoryAsync("./site").GetAwaiter().GetResult();
                    if (!ftpClient.ListDirectoriesAsync().GetAwaiter().GetResult().Any(fni => fni.Name == "wwwroot"))
                    {
                        ftpClient.CreateDirectoryAsync("wwwroot").GetAwaiter().GetResult();
                    }
                    ftpClient.ChangeWorkingDirectoryAsync("./wwwroot").GetAwaiter().GetResult();
                    if (!ftpClient.ListDirectoriesAsync().GetAwaiter().GetResult().Any(fni => fni.Name == "webapps"))
                    {
                        ftpClient.CreateDirectoryAsync("webapps").GetAwaiter().GetResult();
                    }
                    ftpClient.ChangeWorkingDirectoryAsync("./webapps").GetAwaiter().GetResult();

                    if (fileName == null)
                    {
                        fileName = Path.GetFileName(filePath);
                    }
                    while (fileName.Contains("/"))
                    {
                        int    slash  = fileName.IndexOf("/");
                        string subDir = fileName.Substring(0, slash);
                        ftpClient.CreateDirectoryAsync(subDir).GetAwaiter().GetResult();
                        ftpClient.ChangeWorkingDirectoryAsync("./" + subDir);
                        fileName = fileName.Substring(slash + 1);
                    }

                    using (var writeStream = ftpClient.OpenFileWriteStreamAsync(fileName).GetAwaiter().GetResult())
                    {
                        var fileReadStream = fileinfo.OpenRead();
                        fileReadStream.CopyToAsync(writeStream).GetAwaiter().GetResult();
                    }
                }
            }
        }
        /// <summary>
        /// Create a function app, upload the files for his running state. The files are run.csx, function.json and host.json
        /// DO NOT WORK ATM : the inputs / outputs of the function app does not works.
        /// </summary>
        public static void CreateFunctionApp()
        {
            string appName = SdkContext.RandomResourceName(functionAppPrefix, 20);
            string suffix  = ".azurewebsites.net";
            string appUrl  = appName + suffix;

            spin.setMessage("Creating function app " + appName + " in resource group " + rgName + "...");
            //Console.WriteLine("Creating function app " + appName + " in resource group " + rgName + "...");
            //Console.ReadLine();

            IFunctionApp app1 = azure.AppServices.FunctionApps.Define(appName)
                                .WithRegion(Region.EuropeWest)
                                .WithExistingResourceGroup(rgName)
                                .Create();

            spin.Stop();
            Console.WriteLine("Created Function App");
            Console.WriteLine(app1);


            Console.WriteLine("");
            spin.setMessage("Deploying to function app" + appName + " with FTP...");
            spin.Start();

            IPublishingProfile profile = app1.GetPublishingProfile();

            Utilities.UploadFileToFunctionApp(profile, Path.Combine(Utilities.ProjectPath, "FunctionAppCore", "host.json"));
            Utilities.UploadFileToFunctionApp(profile, Path.Combine(Utilities.ProjectPath, "FunctionAppCore", "IoTHubTrigger", "function.json"), "IoTHubTrigger/function.json");
            Utilities.UploadFileToFunctionApp(profile, Path.Combine(Utilities.ProjectPath, "FunctionAppCore", "IoTHubTrigger", "run.csx"), "IoTHubTrigger/run.csx");
            //sync triggers
            app1.SyncTriggers();
            spin.Stop();


            Console.WriteLine("Deployment iotHubTrigger to web app" + app1.Name + " completed");

            //warm up
            //Console.WriteLine("Warming up " + appUrl + "/api/IoTHubTrigger");
            //Utilities.PostAddress("http://" + appUrl + "/api/IoTHubTrigger", "toto");
            //SdkContext.DelayProvider.Delay(5000);
            //Console.WriteLine("Curling...");
            //Console.WriteLine(Utilities.PostAddress("http://" + appUrl + "/api/IoTHubTrigger", "toto"));
        }
        /**
         * Azure App Service basic sample for managing function apps.
         *  - Create 4 function apps under the same new app service plan:
         *    - Deploy to 1 using FTP
         *    - Deploy to 2 using local Git repository
         *    - Deploy to 3 using a publicly available Git repository
         *    - Deploy to 4 using a GitHub repository with continuous integration
         */

        public static void RunSample(IAzure azure)
        {
            // New resources
            string suffix   = ".azurewebsites.net";
            string app1Name = SdkContext.RandomResourceName("webapp1-", 20);
            string app2Name = SdkContext.RandomResourceName("webapp2-", 20);
            string app3Name = SdkContext.RandomResourceName("webapp3-", 20);
            string app4Name = SdkContext.RandomResourceName("webapp4-", 20);
            string app1Url  = app1Name + suffix;
            string app2Url  = app2Name + suffix;
            string app3Url  = app3Name + suffix;
            string app4Url  = app4Name + suffix;
            string rgName   = SdkContext.RandomResourceName("rg1NEMV_", 24);

            try {
                //============================================================
                // Create a function app with a new app service plan

                Utilities.Log("Creating function app " + app1Name + " in resource group " + rgName + "...");

                IFunctionApp app1 = azure.AppServices.FunctionApps.Define(app1Name)
                                    .WithRegion(Region.USWest)
                                    .WithNewResourceGroup(rgName)
                                    .Create();

                Utilities.Log("Created function app " + app1.Name);
                Utilities.Print(app1);

                //============================================================
                // Deploy to app 1 through FTP

                Utilities.Log("Deploying a function app to " + app1Name + " through FTP...");

                IPublishingProfile profile = app1.GetPublishingProfile();
                Utilities.UploadFileToFtp(profile, Path.Combine(Utilities.ProjectPath, "Asset", "square-function-app", "host.json"));
                Utilities.UploadFileToFtp(profile, Path.Combine(Utilities.ProjectPath, "Asset", "square-function-app", "square", "function.json"), "square/function.json");
                Utilities.UploadFileToFtp(profile, Path.Combine(Utilities.ProjectPath, "Asset", "square-function-app", "square", "index.js"), "square/index.js");

                Utilities.Log("Deployment square app to web app " + app1.Name + " completed");
                Utilities.Print(app1);

                // warm up
                Utilities.Log("Warming up " + app1Url + "/api/square...");
                Utilities.PostAddress("http://" + app1Url + "/api/square", "625");
                SdkContext.DelayProvider.Delay(5000);
                Utilities.Log("CURLing " + app1Url + "/api/square...");
                Utilities.Log(Utilities.PostAddress("http://" + app1Url + "/api/square", "625"));

                //============================================================
                // Create a second function app with local git source control

                Utilities.Log("Creating another function app " + app2Name + " in resource group " + rgName + "...");
                IAppServicePlan plan = azure.AppServices.AppServicePlans.GetById(app1.AppServicePlanId);
                IFunctionApp    app2 = azure.AppServices.FunctionApps.Define(app2Name)
                                       .WithExistingAppServicePlan(plan)
                                       .WithExistingResourceGroup(rgName)
                                       .WithExistingStorageAccount(app1.StorageAccount)
                                       .WithLocalGitSourceControl()
                                       .Create();

                Utilities.Log("Created function app " + app2.Name);
                Utilities.Print(app2);

                //============================================================
                // Deploy to app 2 through local Git

                Utilities.Log("Deploying a local Tomcat source to " + app2Name + " through Git...");

                profile = app2.GetPublishingProfile();
                Utilities.DeployByGit(profile, "square-function-app");

                Utilities.Log("Deployment to function app " + app2.Name + " completed");
                Utilities.Print(app2);

                // warm up
                Utilities.Log("Warming up " + app2Url + "/api/square...");
                Utilities.PostAddress("http://" + app2Url + "/api/square", "725");
                SdkContext.DelayProvider.Delay(5000);
                Utilities.Log("CURLing " + app2Url + "/api/square...");
                Utilities.Log("Square of 725 is " + Utilities.PostAddress("http://" + app2Url + "/api/square", "725"));

                //============================================================
                // Create a 3rd function app with a public GitHub repo in Azure-Samples

                Utilities.Log("Creating another function app " + app3Name + "...");
                IFunctionApp app3 = azure.AppServices.FunctionApps.Define(app3Name)
                                    .WithExistingAppServicePlan(plan)
                                    .WithNewResourceGroup(rgName)
                                    .WithExistingStorageAccount(app2.StorageAccount)
                                    .DefineSourceControl()
                                    .WithPublicGitRepository("https://github.com/jianghaolu/square-function-app-sample")
                                    .WithBranch("master")
                                    .Attach()
                                    .Create();

                Utilities.Log("Created function app " + app3.Name);
                Utilities.Print(app3);

                // warm up
                Utilities.Log("Warming up " + app3Url + "/api/square...");
                Utilities.PostAddress("http://" + app3Url + "/api/square", "825");
                SdkContext.DelayProvider.Delay(5000);
                Utilities.Log("CURLing " + app3Url + "/api/square...");
                Utilities.Log("Square of 825 is " + Utilities.PostAddress("http://" + app3Url + "/api/square", "825"));

                //============================================================
                // Create a 4th function app with a personal GitHub repo and turn on continuous integration

                Utilities.Log("Creating another function app " + app4Name + "...");
                IFunctionApp app4 = azure.AppServices.FunctionApps
                                    .Define(app4Name)
                                    .WithExistingAppServicePlan(plan)
                                    .WithExistingResourceGroup(rgName)
                                    .WithExistingStorageAccount(app3.StorageAccount)
                                    // Uncomment the following lines to turn on 4th scenario
                                    //.DefineSourceControl()
                                    //    .WithContinuouslyIntegratedGitHubRepository("username", "reponame")
                                    //    .WithBranch("master")
                                    //    .WithGitHubAccessToken("YOUR GITHUB PERSONAL TOKEN")
                                    //    .Attach()
                                    .Create();

                Utilities.Log("Created function app " + app4.Name);
                Utilities.Print(app4);

                // warm up
                Utilities.Log("Warming up " + app4Url + "...");
                Utilities.CheckAddress("http://" + app4Url);
                SdkContext.DelayProvider.Delay(5000);
                Utilities.Log("CURLing " + app4Url + "...");
                Utilities.Log(Utilities.CheckAddress("http://" + app4Url));
            }
            finally
            {
                try
                {
                    Utilities.Log("Deleting Resource Group: " + rgName);
                    azure.ResourceGroups.DeleteByName(rgName);
                    Utilities.Log("Deleted Resource Group: " + rgName);
                }
                catch (NullReferenceException)
                {
                    Utilities.Log("Did not create any resources in Azure. No clean up is necessary");
                }
                catch (Exception g)
                {
                    Utilities.Log(g);
                }
            }
        }
Example #7
0
        /**
         * Azure App Service basic sample for managing function apps.
         *  - Create 4 function apps under the same new app service plan:
         *    - Deploy to 1 using FTP
         *    - Deploy to 2 using local Git repository
         *    - Deploy to 3 using a publicly available Git repository
         *    - Deploy to 4 using a GitHub repository with continuous integration
         */


        public static void RunSample(IAzure azure)
        {
            // New resources
            string suffix   = ".azurewebsites.net";
            string app1Name = SdkContext.RandomResourceName("webapp1-", 20);
            string app2Name = SdkContext.RandomResourceName("webapp2-", 20);
            string app1Url  = app1Name + suffix;
            string app2Url  = app2Name + suffix;
            string rgName   = SdkContext.RandomResourceName("rg1NEMV_", 24);

            try {
                //============================================================
                // Create a function app with admin level auth

                Utilities.Log("Creating function app " + app1Name + " in resource group " + rgName + " with admin level auth...");

                IFunctionApp app1 = azure.AppServices.FunctionApps.Define(app1Name)
                                    .WithRegion(Region.USWest)
                                    .WithNewResourceGroup(rgName)
                                    .WithLocalGitSourceControl()
                                    .Create();

                Utilities.Log("Created function app " + app1.Name);
                Utilities.Print(app1);

                //============================================================
                // Create a second function app with function level auth

                Utilities.Log("Creating another function app " + app2Name + " in resource group " + rgName + " with function level auth...");
                IAppServicePlan plan = azure.AppServices.AppServicePlans.GetById(app1.AppServicePlanId);
                IFunctionApp    app2 = azure.AppServices.FunctionApps.Define(app2Name)
                                       .WithExistingAppServicePlan(plan)
                                       .WithExistingResourceGroup(rgName)
                                       .WithExistingStorageAccount(app1.StorageAccount)
                                       .WithLocalGitSourceControl()
                                       .Create();

                Utilities.Log("Created function app " + app2.Name);
                Utilities.Print(app2);

                //============================================================
                // Deploy to app 1 through Git

                Utilities.Log("Deploying a local function app to " + app1Name + " through Git...");

                IPublishingProfile profile = app1.GetPublishingProfile();
                Utilities.DeployByGit(profile, "square-function-app-admin-auth");

                // warm up
                Utilities.Log("Warming up " + app1Url + "/api/square...");
                Utilities.PostAddress("http://" + app1Url + "/api/square", "625");
                SdkContext.DelayProvider.Delay(5000);
                Utilities.Log("CURLing " + app1Url + "/api/square...");
                Utilities.Log("Square of 625 is " + Utilities.PostAddress("http://" + app1Url + "/api/square?code=" + app1.GetMasterKey(), "625"));

                //============================================================
                // Deploy to app 2 through Git

                Utilities.Log("Deploying a local function app to " + app2Name + " through Git...");

                profile = app2.GetPublishingProfile();
                Utilities.DeployByGit(profile, "square-function-app-function-auth");

                Utilities.Log("Deployment to function app " + app2.Name + " completed");
                Utilities.Print(app2);


                string masterKey       = app2.GetMasterKey();
                var    functionsHeader = new Dictionary <string, string>();
                functionsHeader["x-functions-key"] = masterKey;
                string response    = Utilities.CheckAddress("http://" + app2Url + "/admin/functions/square/keys", functionsHeader);
                Regex  pattern     = new Regex(@"""name"":""default"",""value"":""([\w=/]+)""");
                Match  matcher     = pattern.Match(response);
                string functionKey = matcher.Captures[0].Value;

                // warm up
                Utilities.Log("Warming up " + app2Url + "/api/square...");
                Utilities.PostAddress("http://" + app2Url + "/api/square", "725");
                SdkContext.DelayProvider.Delay(5000);
                Utilities.Log("CURLing " + app2Url + "/api/square...");
                Utilities.Log("Square of 725 is " + Utilities.PostAddress("http://" + app2Url + "/api/square?code=" + functionKey, "725"));
            }
            finally
            {
                try
                {
                    Utilities.Log("Deleting Resource Group: " + rgName);
                    azure.ResourceGroups.DeleteByName(rgName);
                    Utilities.Log("Deleted Resource Group: " + rgName);
                }
                catch (NullReferenceException)
                {
                    Utilities.Log("Did not create any resources in Azure. No clean up is necessary");
                }
                catch (Exception g)
                {
                    Utilities.Log(g);
                }
            }
        }
Example #8
0
 protected async Task <bool> WaitForCompleteAsync(IPublishingProfile ppSlot, Deployment latestDeployment, (HttpStatusCode Code, Uri PollUrl) upload, bool withSwap)
        /**
         * Azure App Service basic sample for managing function apps.
         *  - Create a function app under the same new app service plan:
         *    - Deploy to app using FTP
         *    - stream logs for 30 seconds
         */

        public static void RunSample(IAzure azure)
        {
            // New resources
            string suffix  = ".azurewebsites.net";
            string appName = SdkContext.RandomResourceName("webapp1-", 20);
            string appUrl  = appName + suffix;
            string rgName  = SdkContext.RandomResourceName("rg1NEMV_", 24);

            try {
                //============================================================
                // Create a function app with a new app service plan

                Utilities.Log("Creating function app " + appName + " in resource group " + rgName + "...");

                IFunctionApp app = azure.AppServices.FunctionApps.Define(appName)
                                   .WithRegion(Region.USWest)
                                   .WithNewResourceGroup(rgName)
                                   .Create();

                Utilities.Log("Created function app " + app.Name);
                Utilities.Print(app);

                //============================================================
                // Deploy to app 1 through FTP

                Utilities.Log("Deploying a function app to " + appName + " through FTP...");

                IPublishingProfile profile = app.GetPublishingProfile();
                Utilities.UploadFileToFunctionApp(profile, Path.Combine(Utilities.ProjectPath, "Asset", "square-function-app", "host.json"));
                Utilities.UploadFileToFunctionApp(profile, Path.Combine(Utilities.ProjectPath, "Asset", "square-function-app", "square", "function.json"), "square/function.json");
                Utilities.UploadFileToFunctionApp(profile, Path.Combine(Utilities.ProjectPath, "Asset", "square-function-app", "square", "index.js"), "square/index.js");

                // sync triggers
                app.SyncTriggers();

                Utilities.Log("Deployment square app to web app " + app.Name + " completed");
                Utilities.Print(app);

                // warm up
                Utilities.Log("Warming up " + appUrl + "/api/square...");
                Utilities.PostAddress("http://" + appUrl + "/api/square", "625");
                SdkContext.DelayProvider.Delay(5000);
                Utilities.Log("CURLing " + appUrl + "/api/square...");
                Utilities.Log(Utilities.PostAddress("http://" + appUrl + "/api/square", "625"));

                //============================================================
                // Listen to logs synchronously for 30 seconds

                using (var stream = app.StreamApplicationLogs())
                {
                    var reader = new StreamReader(stream);
                    Utilities.Log("Streaming logs from function app " + appName + "...");
                    string    line      = reader.ReadLine();
                    Stopwatch stopWatch = new Stopwatch();
                    stopWatch.Start();
                    Task.Factory.StartNew(() =>
                    {
                        Utilities.PostAddress("http://" + appUrl + "/api/square", "625");
                        SdkContext.DelayProvider.Delay(10000);
                        Utilities.PostAddress("http://" + appUrl + "/api/square", "725");
                        SdkContext.DelayProvider.Delay(10000);
                        Utilities.PostAddress("http://" + appUrl + "/api/square", "825");
                    });
                    while (line != null && stopWatch.ElapsedMilliseconds < 30000)
                    {
                        Utilities.Log(line);
                        line = reader.ReadLine();
                    }
                }
            }
            finally
            {
                try
                {
                    Utilities.Log("Deleting Resource Group: " + rgName);
                    azure.ResourceGroups.DeleteByName(rgName);
                    Utilities.Log("Deleted Resource Group: " + rgName);
                }
                catch (NullReferenceException)
                {
                    Utilities.Log("Did not create any resources in Azure. No clean up is necessary");
                }
                catch (Exception g)
                {
                    Utilities.Log(g);
                }
            }
        }
        /**
         * Azure App Service basic sample for managing function apps.
         *  - Create 3 function apps under the same new app service plan and with the same storage account
         *    - Deploy 1 & 2 via Git a function that calculates the square of a number
         *    - Deploy 3 via Web Deploy
         *    - Enable app level authentication for the 1st function app
         *    - Verify the 1st function app can be accessed with the admin key
         *    - Enable function level authentication for the 2nd function app
         *    - Verify the 2nd function app can be accessed with the function key
         *    - Enable function level authentication for the 3rd function app
         *    - Verify the 3rd function app can be accessed with the function key
         */


        public static void RunSample(IAzure azure)
        {
            // New resources
            string suffix   = ".azurewebsites.net";
            string app1Name = SdkContext.RandomResourceName("webapp1-", 20);
            string app2Name = SdkContext.RandomResourceName("webapp2-", 20);
            string app3Name = SdkContext.RandomResourceName("webapp3-", 20);
            string app1Url  = app1Name + suffix;
            string app2Url  = app2Name + suffix;
            string app3Url  = app3Name + suffix;
            string rgName   = SdkContext.RandomResourceName("rg1NEMV_", 24);

            try {
                //============================================================
                // Create a function app with admin level auth

                Utilities.Log("Creating function app " + app1Name + " in resource group " + rgName + " with admin level auth...");

                IFunctionApp app1 = azure.AppServices.FunctionApps.Define(app1Name)
                                    .WithRegion(Region.USWest)
                                    .WithNewResourceGroup(rgName)
                                    .WithLocalGitSourceControl()
                                    .Create();

                Utilities.Log("Created function app " + app1.Name);
                Utilities.Print(app1);

                //============================================================
                // Create a second function app with function level auth

                Utilities.Log("Creating another function app " + app2Name + " in resource group " + rgName + " with function level auth...");
                IAppServicePlan plan = azure.AppServices.AppServicePlans.GetById(app1.AppServicePlanId);
                IFunctionApp    app2 = azure.AppServices.FunctionApps.Define(app2Name)
                                       .WithExistingAppServicePlan(plan)
                                       .WithExistingResourceGroup(rgName)
                                       .WithExistingStorageAccount(app1.StorageAccount)
                                       .WithLocalGitSourceControl()
                                       .Create();

                Utilities.Log("Created function app " + app2.Name);
                Utilities.Print(app2);

                //============================================================
                // Create a third function app with function level auth

                Utilities.Log("Creating another function app " + app3Name + " in resource group " + rgName + " with function level auth...");
                IFunctionApp app3 = azure.AppServices.FunctionApps.Define(app3Name)
                                    .WithExistingAppServicePlan(plan)
                                    .WithExistingResourceGroup(rgName)
                                    .WithExistingStorageAccount(app1.StorageAccount)
                                    .WithLocalGitSourceControl()
                                    .Create();

                Utilities.Log("Created function app " + app3.Name);
                Utilities.Print(app3);

                //============================================================
                // Deploy to app 1 through Git

                Utilities.Log("Deploying a local function app to " + app1Name + " through Git...");

                IPublishingProfile profile = app1.GetPublishingProfile();
                Utilities.DeployByGit(profile, "square-function-app-admin-auth");

                // warm up
                Utilities.Log("Warming up " + app1Url + "/api/square...");
                Utilities.PostAddress("http://" + app1Url + "/api/square", "625");
                SdkContext.DelayProvider.Delay(5000);
                Utilities.Log("CURLing " + app1Url + "/api/square...");
                Utilities.Log("Square of 625 is " + Utilities.PostAddress("http://" + app1Url + "/api/square?code=" + app1.GetMasterKey(), "625"));

                //============================================================
                // Deploy to app 2 through Git

                Utilities.Log("Deploying a local function app to " + app2Name + " through Git...");

                profile = app2.GetPublishingProfile();
                Utilities.DeployByGit(profile, "square-function-app-function-auth");

                Utilities.Log("Deployment to function app " + app2.Name + " completed");
                Utilities.Print(app2);


                string functionKey = app2.ListFunctionKeys("square").Values.First();

                // warm up
                Utilities.Log("Warming up " + app2Url + "/api/square...");
                Utilities.PostAddress("http://" + app2Url + "/api/square", "725");
                SdkContext.DelayProvider.Delay(5000);
                Utilities.Log("CURLing " + app2Url + "/api/square...");
                Utilities.Log("Square of 725 is " + Utilities.PostAddress("http://" + app2Url + "/api/square?code=" + functionKey, "725"));

                Utilities.Log("Adding a new key to function app " + app2.Name + "...");

                var newKey = app2.AddFunctionKey("square", "newkey", null);

                Utilities.Log("CURLing " + app2Url + "/api/square...");
                Utilities.Log("Square of 825 is " + Utilities.PostAddress("http://" + app2Url + "/api/square?code=" + newKey.Value, "825"));

                //============================================================
                // Deploy to app 3 through web deploy

                Utilities.Log("Deploying a local function app to " + app3Name + " throuh web deploy...");

                app3.Deploy()
                .WithPackageUri("https://github.com/Azure/azure-libraries-for-net/raw/master/Samples/Asset/square-function-app-function-auth.zip")
                .WithExistingDeploymentsDeleted(false)
                .Execute();

                Utilities.Log("Deployment to function app " + app3.Name + " completed");

                Utilities.Log("Adding a new key to function app " + app3.Name + "...");
                app3.AddFunctionKey("square", "newkey", "mysecretkey");

                // warm up
                Utilities.Log("Warming up " + app3Url + "/api/square...");
                Utilities.PostAddress("http://" + app3Url + "/api/square", "925");
                SdkContext.DelayProvider.Delay(5000);
                Utilities.Log("CURLing " + app3Url + "/api/square...");
                Utilities.Log("Square of 925 is " + Utilities.PostAddress("http://" + app3Url + "/api/square?code=mysecretkey", "925"));
            }
            finally
            {
                try
                {
                    Utilities.Log("Deleting Resource Group: " + rgName);
                    azure.ResourceGroups.DeleteByName(rgName);
                    Utilities.Log("Deleted Resource Group: " + rgName);
                }
                catch (NullReferenceException)
                {
                    Utilities.Log("Did not create any resources in Azure. No clean up is necessary");
                }
                catch (Exception g)
                {
                    Utilities.Log(g);
                }
            }
        }
        public static async Task UploadFilesAsync(this IWebApp site, DirectoryInfo from, string to, IPublishingProfile publishingProfile, ILogger logger)
        {
            foreach (var info in from.GetFileSystemInfos("*"))
            {
                var address = new Uri(
                    "ftp://" + publishingProfile.FtpUrl + to + info.FullName.Substring(from.FullName.Length + 1).Replace('\\', '/'));

                if (info is FileInfo file)
                {
                    logger.LogInformation($"Uploading {file.FullName} to {address}");

                    var request = CreateRequest(publishingProfile, address, WebRequestMethods.Ftp.UploadFile);
                    using (var fileStream = File.OpenRead(file.FullName))
                    {
                        using (var requestStream = await request.GetRequestStreamAsync())
                        {
                            await fileStream.CopyToAsync(requestStream);
                        }
                    }
                    await request.GetResponseAsync();
                }
                if (info is DirectoryInfo directory)
                {
                    var request = CreateRequest(publishingProfile, address, WebRequestMethods.Ftp.MakeDirectory);
                    await request.GetResponseAsync();
                    await UploadFilesAsync(site, directory, to + directory.Name + '/', publishingProfile, logger);
                }
            }
        }