Beispiel #1
0
        public async Task OpenCircuit(
            [OrchestrationTrigger] IDurableOrchestrationContext context,
            ILogger log)
        {
            if (!context.IsReplaying)
            {
                log.LogInformation("Disabling function app to open circuit");
            }

            var resourceId = context.GetInput <string>();

            var stopFunctionRequest = new DurableHttpRequest(
                HttpMethod.Post,
                new Uri($"https://management.azure.com{resourceId}/stop?api-version=2016-08-01"),
                tokenSource: new ManagedIdentityTokenSource("https://management.core.windows.net"));

            var restartResponse = await context.CallHttpAsync(stopFunctionRequest);

            if (restartResponse.StatusCode != HttpStatusCode.OK)
            {
                throw new ArgumentException($"Failed to stop Function App: {restartResponse.StatusCode}: {restartResponse.Content}");
            }

            if (!context.IsReplaying)
            {
                log.LogInformation("Function disabled");
            }
        }
        public static DurableHttpRequest ConvertTestRequestToDurableHttpRequest(TestDurableHttpRequest testRequest)
        {
            Dictionary <string, StringValues> testHeaders = new Dictionary <string, StringValues>(StringComparer.OrdinalIgnoreCase);

            if (testRequest.Headers != null)
            {
                foreach (KeyValuePair <string, string> header in testRequest.Headers)
                {
                    StringValues stringValues;
                    if (testHeaders.TryGetValue(header.Key, out stringValues))
                    {
                        stringValues.Append(header.Value);
                        testHeaders[header.Key] = stringValues;
                    }
                    else
                    {
                        stringValues            = new StringValues(header.Value);
                        testHeaders[header.Key] = stringValues;
                    }
                }
            }

            DurableHttpRequest durableHttpRequest = new DurableHttpRequest(
                method: testRequest.HttpMethod,
                uri: new Uri(testRequest.Uri),
                headers: testHeaders,
                content: testRequest.Content,
                tokenSource: testRequest.TokenSource,
                asynchronousPatternEnabled: testRequest.AsynchronousPatternEnabled);

            return(durableHttpRequest);
        }
        public static async Task <string> RunOrchestrator(
            [OrchestrationTrigger] IDurableOrchestrationContext context, ILogger log)
        {
            string endpoint = context.GetInput <object>().ToString();
            var    request  = new DurableHttpRequest(HttpMethod.Get, new Uri(endpoint));
            DurableHttpResponse endpointResponse = await context.CallHttpAsync(request);

            if (endpointResponse.StatusCode != HttpStatusCode.OK)
            {
                throw new ArgumentException($"Failed to contact endpoint: {endpointResponse.StatusCode}: {endpointResponse.Content}");
            }
            log.LogInformation($"Information retrieved from endpoint = {endpointResponse.Content}.");

            string[] words = endpointResponse.Content.Split(" ");
            log.LogInformation($"Words count = {words.Count()}.");

            var entityId = new EntityId("OrchestrationSample_Counter", "charCounter");

            context.SignalEntity(entityId, "reset");

            foreach (string word in words)
            {
                context.SignalEntity(entityId, "Add", word);
            }

            await context.CallActivityAsync("OrchestrationSample_LogBlob", endpoint.Replace("/", "bar"));

            int count = await context.CallEntityAsync <int>(entityId, "Get");

            return($"Endpoint: {endpoint} has the total of {count} chars");
        }
        public static async Task <DurableHttpResponse> CallHttpAsyncOrchestrator([OrchestrationTrigger] IDurableOrchestrationContext ctx)
        {
            TestDurableHttpRequest testRequest        = ctx.GetInput <TestDurableHttpRequest>();
            DurableHttpRequest     durableHttpRequest = ConvertTestRequestToDurableHttpRequest(testRequest);
            DurableHttpResponse    response           = await ctx.CallHttpAsync(durableHttpRequest);

            return(response);
        }
Beispiel #5
0
        public async Task CallHttpActionOrchestrationWithManagedIdentityOptions()
        {
            DurableHttpRequest request = null;

            // Mock the CallHttpAsync API so we can capture the request and return a fixed response.
            var contextMock = new Mock <IDurableOrchestrationContext>();

            contextMock
            .Setup(ctx => ctx.CallHttpAsync(It.IsAny <DurableHttpRequest>()))
            .Callback <DurableHttpRequest>(req => request = req)
            .Returns(Task.FromResult(new DurableHttpResponse(System.Net.HttpStatusCode.OK)));

            var shim = new OutOfProcOrchestrationShim(contextMock.Object);

            var executionJson = @"
{
    ""isDone"": false,
    ""actions"": [
        [{
            ""actionType"": ""CallHttp"",
            ""httpRequest"": {
                ""method"": ""GET"",
                ""uri"": ""https://example.com"",
                ""tokenSource"": {
                    ""kind"": ""AzureManagedIdentity"",
                    ""resource"": ""https://management.core.windows.net/.default"",
                    ""options"": {
                        ""authorityhost"": ""https://login.microsoftonline.com/"",
                        ""tenantid"": ""example_tenant_id""
                    }
                }
            }
        }]
    ]
}";

            // Feed the out-of-proc execution result JSON to the out-of-proc shim.
            var jsonObject = JObject.Parse(executionJson);
            OrchestrationInvocationResult result = new OrchestrationInvocationResult()
            {
                ReturnValue = jsonObject,
            };
            bool moreWork = await shim.ScheduleDurableTaskEvents(result);

            Assert.NotNull(request);
            Assert.Equal(HttpMethod.Get, request.Method);
            Assert.Equal(new Uri("https://example.com"), request.Uri);
            Assert.Null(request.Content);

            Assert.NotNull(request.TokenSource);
            ManagedIdentityTokenSource tokenSource = Assert.IsType <ManagedIdentityTokenSource>(request.TokenSource);

            Assert.Equal("https://management.core.windows.net/.default", tokenSource.Resource);
            Assert.Equal("https://login.microsoftonline.com/", tokenSource.Options.AuthorityHost.ToString());
            Assert.Equal("example_tenant_id", tokenSource.Options.TenantId);
        }
Beispiel #6
0
        internal static Task <DurableHttpResponse> PostData(IDurableOrchestrationContext context, string url, object body, string authToken)
        {
            var authHeaders = new Dictionary <string, StringValues>
            {
                ["Authorization"] = new StringValues($"Bearer {authToken}")
            };

            var request = new DurableHttpRequest(
                HttpMethod.Post, new Uri(url), authHeaders, JsonConvert.SerializeObject(body));

            return(context.CallHttpAsync(request));
        }
        public static async Task RunOrchestrator(
            [OrchestrationTrigger] IDurableOrchestrationContext context)
        {
            ResourceInfo vmInfo         = context.GetInput <ResourceInfo>();
            string       apiVersion     = vmInfo.ApiVersion ?? "2018-06-01";
            string       subscriptionId = vmInfo.SubscriptionId;
            string       resourceGroup  = vmInfo.ResourceGroup;

            // Implicitly uses the Azure AD identity of the current app to make an HTTP call to Azure Resource Manager
            var managedIdentity = new ManagedIdentityTokenSource("https://management.core.windows.net");

            // List all of the VMs in my subscription and add them to a list.
            DurableHttpRequest request = new DurableHttpRequest(
                HttpMethod.Get,
                new Uri($"https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Compute/virtualMachines?api-version=2018-06-01"),
                tokenSource: managedIdentity);
            DurableHttpResponse response = await context.CallHttpAsync(request);

            if (response.StatusCode != HttpStatusCode.OK)
            {
                throw new ArgumentException($"Failed to list VMs: {response.StatusCode}: {response.Content}");
            }

            // Deserializes content to just get the names of the VMs in the subscription
            JObject jObject     = JsonConvert.DeserializeObject <JObject>(response.Content);
            var     vmNamesList = new List <string>();

            foreach (JToken value in jObject["value"])
            {
                string vmName = value["name"].ToString();
                vmNamesList.Add(vmName);
            }

            // Restart all of the VMs in my subscription
            foreach (string vmName in vmNamesList)
            {
                var restartRequest = new DurableHttpRequest(
                    HttpMethod.Post,
                    new Uri($"https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroup}/providers/Microsoft.Compute/virtualMachines/{vmName}/restart?api-version={apiVersion}"),
                    tokenSource: managedIdentity);
                DurableHttpResponse restartResponse = await context.CallHttpAsync(restartRequest);

                if (restartResponse.StatusCode != HttpStatusCode.OK)
                {
                    throw new ArgumentException($"Failed to restart VM: {restartResponse.StatusCode}: {restartResponse.Content}");
                }
            }
        }
    public static async Task <List <string> > RunOrchestrator(
        [OrchestrationTrigger] IDurableOrchestrationContext context)
    {
        // param into orchestrator
        OrchestratorInput oi = context.GetInput <OrchestratorInput>();
        // call activity function
        await context.CallActivityAsync <List <string> >(nameof(MyActivityFunction), oi.Url);

        // call durable entity
        List <string> result = await ContactDurableEntity(context);

        // call http
        var request = new DurableHttpRequest(HttpMethod.Post, new Uri(oi.Url), content: "myContent");
        DurableHttpResponse response = await context.CallHttpAsync(request);

        return(result);
    }
        public async Task CallHttpActionOrchestrationWithManagedIdentity()
        {
            DurableHttpRequest request = null;

            // Mock the CallHttpAsync API so we can capture the request and return a fixed response.
            var contextMock = new Mock <IDurableOrchestrationContext>();

            contextMock
            .Setup(ctx => ctx.CallHttpAsync(It.IsAny <DurableHttpRequest>()))
            .Callback <DurableHttpRequest>(req => request = req)
            .Returns(Task.FromResult(new DurableHttpResponse(System.Net.HttpStatusCode.OK)));

            var shim = new OutOfProcOrchestrationShim(contextMock.Object);

            var executionJson = @"
{
    ""isDone"": false,
    ""actions"": [
        [{
            ""actionType"": ""CallHttp"",
            ""httpRequest"": {
                ""method"": ""GET"",
                ""uri"": ""https://example.com"",
                ""tokenSource"": {
                    ""kind"": ""AzureManagedIdentity"",
                    ""resource"": ""https://management.core.windows.net""
                }
            }
        }]
    ]
}";

            // Feed the out-of-proc execution result JSON to the out-of-proc shim.
            var jsonObject = JObject.Parse(executionJson);
            await shim.ExecuteAsync(jsonObject);

            Assert.NotNull(request);
            Assert.Equal(HttpMethod.Get, request.Method);
            Assert.Equal(new Uri("https://example.com"), request.Uri);
            Assert.Null(request.Content);

            Assert.NotNull(request.TokenSource);
            ManagedIdentityTokenSource tokenSource = Assert.IsType <ManagedIdentityTokenSource>(request.TokenSource);

            Assert.Equal("https://management.core.windows.net", tokenSource.Resource);
        }
Beispiel #10
0
        public static async Task SingleClientOnboardingOrchestration(
            [OrchestrationTrigger] IDurableOrchestrationContext createAccountContext
            )
        {
            AccountOpeningData payload = createAccountContext.GetInput <AccountOpeningData>();

            if (null != payload)
            {
                string newAccountNumber = await createAccountContext.CallActivityAsync <string>(nameof( CreateRandomAccountNumber), null);

                string jsonContent = JsonConvert.SerializeObject(payload);

                var newAccountRequest = new DurableHttpRequest(
                    HttpMethod.Post,
                    new Uri($"https://retailbankazurefunctionapp.azurewebsites.net/api/OpenAccount/{newAccountNumber}?code=9IcflcYh904F3Dcbp5IGCPuDrqelVJniQK5Ck1ZcVdacOd3Mx4ShWQ=="),
                    content: jsonContent);


                newAccountRequest.Headers.Add(@"Content-Type", @"application/json");

                DurableHttpResponse restartResponse = await createAccountContext.CallHttpAsync(newAccountRequest);
            }
        }
Beispiel #11
0
        public async Task CallHttpActionOrchestration()
        {
            DurableHttpRequest request = null;

            // Mock the CallHttpAsync API so we can capture the request and return a fixed response.
            var contextMock = new Mock <IDurableOrchestrationContext>();

            contextMock
            .Setup(ctx => ctx.CallHttpAsync(It.IsAny <DurableHttpRequest>()))
            .Callback <DurableHttpRequest>(req => request = req)
            .Returns(Task.FromResult(new DurableHttpResponse(System.Net.HttpStatusCode.OK)));

            var shim = new OutOfProcOrchestrationShim(contextMock.Object);

            var executionJson = @"
{
    ""isDone"": false,
    ""actions"": [
        [{
            ""actionType"": ""CallHttp"",
            ""httpRequest"":
            {
                ""method"": ""POST"",
                ""uri"": ""https://example.com"",
                ""headers"": {
                    ""Content-Type"": ""application/json"",
                    ""Accept"": [""application/json"",""application/xml""],
                    ""x-ms-foo"": []
                },
                ""content"": ""5""
            }
        }]
    ]
}";

            // Feed the out-of-proc execution result JSON to the out-of-proc shim.
            var jsonObject = JObject.Parse(executionJson);
            OrchestrationInvocationResult result = new OrchestrationInvocationResult()
            {
                ReturnValue = jsonObject,
            };
            bool moreWork = await shim.ScheduleDurableTaskEvents(result);

            // The request should not have completed because one additional replay is needed
            // to handle the result of CallHttpAsync. However, this test doesn't care about
            // completing the orchestration - we just need to validate the CallHttpAsync call.
            Assert.True(moreWork);
            Assert.NotNull(request);
            Assert.Equal(HttpMethod.Post, request.Method);
            Assert.Equal(new Uri("https://example.com"), request.Uri);
            Assert.Equal("5", request.Content);
            Assert.Equal(3, request.Headers.Count);

            Assert.True(request.Headers.TryGetValue("Content-Type", out StringValues contentTypeValues));
            Assert.Single(contentTypeValues);
            Assert.Equal("application/json", contentTypeValues[0]);

            Assert.True(request.Headers.TryGetValue("Accept", out StringValues acceptValues));
            Assert.Equal(2, acceptValues.Count);
            Assert.Equal("application/json", acceptValues[0]);
            Assert.Equal("application/xml", acceptValues[1]);

            Assert.True(request.Headers.TryGetValue("x-ms-foo", out StringValues customHeaderValues));
            Assert.Empty(customHeaderValues);
        }
        public async Task OpenCircuit(
            [OrchestrationTrigger] IDurableOrchestrationContext context,
            ILogger log)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            try
            {
                var failureRequest = context.GetInput <FailureRequest>();
                var resourceId     = failureRequest.ResourceId;

                if (!context.IsReplaying)
                {
                    log.LogInformation("Disabling function app ({resourceId}) to open circuit.", resourceId);
                }

                var managedIdentity = new ManagedIdentityTokenSource("https://management.azure.com/.default");

                // Note: Configurable resourceId works only for other Azure App Service applications.
                var stopFunctionRequest = new DurableHttpRequest(
                    HttpMethod.Post,
                    new Uri($"https://management.azure.com{resourceId}/stop?api-version=2019-08-01"),
                    tokenSource: managedIdentity);

                // Note: Use of ConfigureAwait can break orchestration tasks (prevents from completing; instance remains in a 'running' state).
                // See https://github.com/Azure/azure-functions-durable-extension/issues/995 and
                // https://docs.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-code-constraints
#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
                DurableHttpResponse restartResponse = await context.CallHttpAsync(stopFunctionRequest);

#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task

                if (restartResponse.StatusCode != HttpStatusCode.OK)
                {
                    if (!context.IsReplaying)
                    {
                        log.LogError("Failed to stop Function App: {restartResponse.StatusCode}: {restartResponse.Content}", restartResponse.StatusCode, restartResponse.Content);
                    }

                    throw new ApplicationException($"Failed to stop Function App: {restartResponse.StatusCode}: {restartResponse.Content}");
                }

                if (restartResponse.StatusCode == HttpStatusCode.OK)
                {
                    if (!context.IsReplaying)
                    {
                        // Logging as a warning to aide in noticing this messages, as stopping of an Azure Function
                        // may be an action worthy of human intervention.
                        log.LogWarning("Successfully STOPPED Azure Function with Resource ID {resourceId}.", resourceId);
                    }
                }

                return;
            }
            catch (Exception e)
            {
                log.LogError(e, "Unexpected error '{msg}' while processing.", e.Message);
                throw;
            }
        }
Beispiel #13
0
 public async Task <DurableHttpResponse> CallHttpAsync(DurableHttpRequest req)
 {
     throw new NotImplementedException();
 }
Beispiel #14
0
        public Task <DurableHttpResponse> CallHttpAsync(DurableHttpRequest req)
        {
            var response = _client.CallHttpHandler?.Invoke(req) ?? new DurableHttpResponse(HttpStatusCode.OK);

            return(Task.FromResult(response));
        }
        public static async Task <LoanApplicationResult> Orchestrate(
            [OrchestrationTrigger] IDurableOrchestrationContext context,
            [SignalR(HubName = "dashboard")] IAsyncCollector <SignalRMessage> dashboardMessages,
            ILogger logger)
        {
            var loanApplication = context.GetInput <LoanApplication>();
            var agencyTasks     = new List <Task <CreditAgencyResult> >();
            var agencies        = new List <CreditAgencyRequest>();
            var results         = new CreditAgencyResult[] {};

            logger.LogWarning($"Status of application for {loanApplication.Applicant.ToString()} for {loanApplication.LoanAmount}: Checking with agencies.");

            // start the process and perform initial validation
            bool loanPreApproved = await context.CallActivityAsync <bool>(nameof(Receive), loanApplication);

            // fan out and check the credit agencies
            agencies.AddRange(new CreditAgencyRequest[] {
                new CreditAgencyRequest {
                    AgencyName = "Contoso, Ltd.", AgencyId = "contoso", Application = loanApplication
                },
                new CreditAgencyRequest {
                    AgencyName = "Fabrikam, Inc.", AgencyId = "fabrikam", Application = loanApplication
                },
                new CreditAgencyRequest {
                    AgencyName = "Woodgrove Bank", AgencyId = "woodgrove", Application = loanApplication
                },
            });

            foreach (var agency in agencies)
            {
                agencyTasks.Add(context.CallActivityAsync <CreditAgencyResult>(nameof(CheckCreditAgency), agency));
            }

            await context.CallActivityAsync(nameof(SendDashboardMessage), new SignalRMessage
            {
                Target    = "agencyCheckPhaseStarted",
                Arguments = new object[] { }
            });

            // wait for all the agencies to return their results
            results = await Task.WhenAll(agencyTasks);

            await context.CallActivityAsync(nameof(SendDashboardMessage), new SignalRMessage
            {
                Target    = "agencyCheckPhaseCompleted",
                Arguments = new object[] { !(results.Any(x => x.IsApproved == false)) }
            });

            var loanApplicationResult = new LoanApplicationResult
            {
                IsApproved  = loanPreApproved && !(results.Any(x => x.IsApproved == false)),
                Application = loanApplication
            };

            logger.LogWarning($"Agency checks result with {loanApplicationResult.IsApproved} for loan amount of {loanApplication.LoanAmount.Amount} to customer {loanApplication.Applicant.ToString()}");

            foreach (var agencyResult in results)
            {
                loanApplicationResult.AgencyResults.Add(new AgencyCheckResult
                {
                    AgencyName = agencyResult.AgencyId,
                    IsApproved = agencyResult.IsApproved
                });
            }

            // send the loan for final human validation
            logger.LogInformation($"Sending loan application for {loanApplicationResult.Application.Applicant.FirstName} {loanApplicationResult.Application.Applicant.LastName} for approval");

            var json = System.Text.Json.JsonSerializer.Serialize <LoanApplicationResult>(loanApplicationResult,
                                                                                         new JsonSerializerOptions
            {
                WriteIndented = true
            });

            logger.LogInformation(json);

            var url = Environment.GetEnvironmentVariable("LoanOfficerServiceUrl");

            logger.LogInformation(url);

            var request = new DurableHttpRequest(
                HttpMethod.Post,
                new Uri(url),
                headers: new Dictionary <string, StringValues> {
                { "Content-Type", "application/json" }
            },
                content: json,
                asynchronousPatternEnabled: false
                );

            DurableHttpResponse restartResponse = await context.CallHttpAsync(request);

            logger.LogInformation($"Status code returned: {restartResponse.StatusCode}");

            if (restartResponse.StatusCode == HttpStatusCode.Accepted)
            {
                await context.CallActivityAsync(nameof(SendDashboardMessage), new SignalRMessage
                {
                    Target    = "loanApplicationComplete",
                    Arguments = new object[] { loanApplicationResult }
                });
            }

            return(loanApplicationResult);
        }