public void ParseResourceGroupId(string resourceId) { var resourceIdentifier = AzureResourceIdentifier.Parse(resourceId); Assert.Equal(Guid.Empty, resourceIdentifier.SubscriptionId); Assert.Equal("TestRG", resourceIdentifier.ResourceGroup); }
private async Task <string> GetEventsAsync(ComponentTask document) { var output = default(string); if (document.TaskState.IsActive() && AzureResourceIdentifier.TryParse(document.ResourceId, out var resourceId)) { try { var containerGroup = await azureResourceService .GetResourceAsync <AzureContainerGroupResource>(resourceId.ToString()) .ConfigureAwait(false); if (containerGroup is not null) { output = await containerGroup .GetEventContentAsync(document.Id) .ConfigureAwait(false); } } catch { // swallow } } return(output); }
public async Task <string> RunActivity( [ActivityTrigger] IDurableActivityContext activityContext, ILogger log) { if (activityContext is null) { throw new ArgumentNullException(nameof(activityContext)); } var resourceId = activityContext.GetInput <string>(); try { var resourceIdentifier = AzureResourceIdentifier.Parse(resourceId); if (string.IsNullOrEmpty(resourceIdentifier.ResourceGroup)) { throw new RetryCanceledException($"Resource id must include resource group information: {resourceId}"); } else if (resourceIdentifier.ResourceTypes?.Any() ?? false) { throw new RetryCanceledException($"Resource id must not include resource type information: {resourceId}"); } else { var resourceGroup = await azureResourceService .GetResourceGroupAsync(resourceIdentifier.SubscriptionId, resourceIdentifier.ResourceGroup) .ConfigureAwait(false); if (resourceGroup is null) { return(default);
public void ParseResourceGroupId(string resourceId) { var resourceIdentifier = AzureResourceIdentifier.Parse(resourceId); Assert.Equal(SUBSCRIPTION_ID, resourceIdentifier.SubscriptionId); Assert.Equal("TestRG", resourceIdentifier.ResourceGroup); }
private async Task <object[]> GetRegistryCredentialsAsync(Organization organization) { var credentials = new List <object>(); var organizationRegistry = AzureResourceIdentifier.TryParse(organization.RegistryId, out var organizationRegistryId) ? await azureResourceService.GetResourceAsync <AzureContainerRegistryResource>(organizationRegistryId.ToString()).ConfigureAwait(false) : null; if (organizationRegistry is not null) { var registryCredentials = await organizationRegistry .GetCredentialsAsync() .ConfigureAwait(false); if (registryCredentials is not null) { credentials.Add(new { server = registryCredentials.Domain, username = registryCredentials.UserName, password = registryCredentials.Password }); } } return(credentials.ToArray()); }
protected override async Task <Component> CreateComponentAsync(Component component, Organization componentOrganization, DeploymentScope componentDeploymentScope, Project componentProject, User contextUser, IAsyncCollector <ICommand> commandQueue) { if (component is null) { throw new ArgumentNullException(nameof(component)); } if (!AzureResourceIdentifier.TryParse(component.ResourceId, out var resourceId)) { component.ResourceId = await CreateResourceIdAsync(component) .ConfigureAwait(false); resourceId = AzureResourceIdentifier.Parse(component.ResourceId); var sessionIdenity = await azureResourceService.AzureSessionService .GetIdentityAsync() .ConfigureAwait(false); component.ResourceUrl = resourceId.GetPortalUrl(sessionIdenity.TenantId); component = await componentRepository .SetAsync(component) .ConfigureAwait(false); } return(await UpdateComponentAsync(component, contextUser, commandQueue).ConfigureAwait(false)); }
internal ServiceBusManager(AzureCredentials azureCredentials, AzureResourceIdentifier identifier) { _azureCredentials = azureCredentials ?? throw new ArgumentNullException(nameof(azureCredentials)); _identifier = identifier ?? throw new ArgumentNullException(nameof(identifier)); }
public async Task <Component> Run( [ActivityTrigger] IDurableActivityContext context, ILogger log) { if (context is null) { throw new ArgumentNullException(nameof(context)); } if (log is null) { throw new ArgumentNullException(nameof(log)); } var component = context.GetInput <Input>().Component; if (!AzureResourceIdentifier.TryParse(component.IdentityId, out var identityId)) { var deploymentScope = await deploymentScopeRepository .GetAsync(component.Organization, component.DeploymentScopeId) .ConfigureAwait(false); var project = await projectRepository .GetAsync(component.Organization, component.ProjectId) .ConfigureAwait(false); var projectResourceId = AzureResourceIdentifier.Parse(project.ResourceId); var session = await azureResourceService.AzureSessionService .CreateSessionAsync(projectResourceId.SubscriptionId) .ConfigureAwait(false); var identities = await session.Identities .ListByResourceGroupAsync(projectResourceId.ResourceGroup, loadAllPages : true) .ConfigureAwait(false); var identity = identities .SingleOrDefault(i => i.Name.Equals(deploymentScope.Id, StringComparison.OrdinalIgnoreCase)); if (identity is null) { var location = await GetLocationAsync(component) .ConfigureAwait(false); identity = await session.Identities .Define(deploymentScope.Id) .WithRegion(location) .WithExistingResourceGroup(projectResourceId.ResourceGroup) .CreateAsync() .ConfigureAwait(false); } component.IdentityId = identity.Id; } return(component); }
private static string GetResourceGroupId(string resourceId) { if (AzureResourceIdentifier.TryParse(resourceId, out var resourceGroupIdentifier)) { return(resourceGroupIdentifier.ToString(AzureResourceSegment.ResourceGroup)); } return(null); }
public static bool IsAzureResourceId(this string resourceId) { if (resourceId is null) { throw new ArgumentNullException(nameof(resourceId)); } return(AzureResourceIdentifier.TryParse(resourceId, out var _)); }
protected AzureResource(string resourceId, IAzureResourceService azureResourceService) { if (resourceId is null) { throw new ArgumentNullException(nameof(resourceId)); } ResourceId = AzureResourceIdentifier.Parse(resourceId); AzureResourceService = azureResourceService ?? throw new ArgumentNullException(nameof(azureResourceService)); }
internal AzureResource(string resourceId) { if (resourceId is null) { throw new ArgumentNullException(nameof(resourceId)); } ResourceId = AzureResourceIdentifier.Parse(resourceId); AzureResourceService = null; }
public void ParseManagementGroupId(string resourceId) { var resourceIdentifier = AzureResourceIdentifier.Parse(resourceId); Assert.Equal(Guid.Empty, resourceIdentifier.SubscriptionId); Assert.Null(resourceIdentifier.ResourceGroup); Assert.Equal("managementGroups", resourceIdentifier.ResourceTypes[0].Key); Assert.Equal("11111111-1111-1111-1111-111111111111", resourceIdentifier.ResourceTypes[0].Value); }
public async Task <string[]> Run( [ActivityTrigger] IDurableActivityContext context, ILogger log) { if (context is null) { throw new ArgumentNullException(nameof(context)); } if (log is null) { throw new ArgumentNullException(nameof(log)); } var component = context.GetInput <Input>().Component; IAsyncEnumerable <AzureResource> resources = null; if (AzureResourceIdentifier.TryParse(component.ResourceId, out var componentResourceId)) { if (string.IsNullOrEmpty(componentResourceId.ResourceGroup)) { var subscription = await azureResourceService .GetSubscriptionAsync(componentResourceId.SubscriptionId) .ConfigureAwait(false); if (subscription is not null) { resources = subscription.GetResourceGroupsAsync() .SelectMany(rg => rg.GetResourcesAsync()); } } else { var resourceGroup = await azureResourceService .GetResourceGroupAsync(componentResourceId.SubscriptionId, componentResourceId.ResourceGroup) .ConfigureAwait(false); if (resourceGroup is not null) { resources = resourceGroup.GetResourcesAsync(); } } } if (resources is null) { return(Array.Empty <string>()); } return(await resources .Select(r => r.ResourceId.ToString()) .ToArrayAsync() .ConfigureAwait(false)); }
public static async Task RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext functionContext, ILogger log) { if (functionContext is null) { throw new ArgumentNullException(nameof(functionContext)); } var functionLog = functionContext.CreateReplaySafeLogger(log ?? NullLogger.Instance); var resourceIds = functionContext .GetInput <IEnumerable <string> >() .ToHashSet(StringComparer.OrdinalIgnoreCase); await Task.WhenAll(resourceIds.Select(resourceId => { if (AzureResourceIdentifier.TryParse(resourceId, out var resourceIdentifier)) { if (IsResourceGroup(resourceIdentifier)) { functionLog.LogInformation($"Resetting resource group: {resourceId}"); return(functionContext.CallDeploymentAsync(nameof(ResourceGroupResetActivity), resourceId)); } else { functionLog.LogInformation($"Deleting resource: {resourceId}"); return(functionContext.CallActivityWithRetryAsync(nameof(ResourceDeleteActivity), resourceId)); } } return(Task.CompletedTask); })).ConfigureAwait(true); await Task.WhenAll(resourceIds.Select(resourceId => { if (AzureResourceIdentifier.TryParse(resourceId, out var resourceIdentifier) && IsResourceGroup(resourceIdentifier)) { functionLog.LogInformation($"Deleting resource group: {resourceId}"); return(functionContext.CallActivityWithRetryAsync(nameof(ResourceGroupDeleteActivity), resourceId)); } return(Task.CompletedTask); })).ConfigureAwait(true); bool IsResourceGroup(AzureResourceIdentifier azureResourceIdentifier) => !(azureResourceIdentifier.ResourceTypes?.Any() ?? false); }
public async Task <ILogger> CreateLoggerAsync(ComponentTask componentTask, ILogger logger) { if (componentTask is null) { throw new ArgumentNullException(nameof(componentTask)); } logger ??= NullLogger.Instance; try { var project = await projectRepository .GetAsync(componentTask.Organization, componentTask.ProjectId) .ConfigureAwait(false); if (AzureResourceIdentifier.TryParse(project?.StorageId, out var storageId)) { var storageAccount = await azureResourceService .GetResourceAsync <AzureStorageAccountResource>(storageId.ToString(), false) .ConfigureAwait(false); if (storageAccount is not null) { var shareClient = await storageAccount .CreateShareClientAsync(componentTask.ComponentId) .ConfigureAwait(false); var directoryClient = shareClient .GetDirectoryClient(".output"); await directoryClient .CreateIfNotExistsAsync() .ConfigureAwait(false); var fileClient = directoryClient .GetFileClient($"{componentTask.Id}"); var fileStream = await fileClient .OpenWriteAsync(true, 0) .ConfigureAwait(false); return(new AdapterInitializationLogger(logger, fileStream)); } } } catch { // swallow } return(logger); }
public void ParseResourceId(string resourceId) { var resourceIdentifier = AzureResourceIdentifier.Parse(resourceId); Assert.Equal(SUBSCRIPTION_ID, resourceIdentifier.SubscriptionId); Assert.Equal("TestRG", resourceIdentifier.ResourceGroup); Assert.True(resourceIdentifier.ResourceTypes.Count == 2); Assert.Equal("resourceProviders", resourceIdentifier.ResourceTypes[0].Key); Assert.Equal("TestProviderName", resourceIdentifier.ResourceTypes[0].Value); Assert.Equal("TestResourceType", resourceIdentifier.ResourceTypes[1].Key); Assert.Equal("TestResourceName", resourceIdentifier.ResourceTypes[1].Value); }
public void ParseResourceIdUnnamed(string resourceId) { var resourceIdentifier = AzureResourceIdentifier.Parse(resourceId, allowUnnamedResource: true); Assert.Equal(Guid.Empty, resourceIdentifier.SubscriptionId); Assert.Equal("TestRG", resourceIdentifier.ResourceGroup); Assert.True(resourceIdentifier.ResourceTypes.Count == 2); Assert.Null(resourceIdentifier.ResourceName); Assert.Equal("resourceProviders", resourceIdentifier.ResourceTypes[0].Key); Assert.Equal("TestProviderName", resourceIdentifier.ResourceTypes[0].Value); Assert.Equal("TestResourceType", resourceIdentifier.ResourceTypes[1].Key); Assert.Null(resourceIdentifier.ResourceTypes[1].Value); }
public void ParseResourceId(string resourceId) { var resourceIdentifier = AzureResourceIdentifier.Parse(resourceId); Assert.Equal(Guid.Empty, resourceIdentifier.SubscriptionId); Assert.Equal("TestRG", resourceIdentifier.ResourceGroup); Assert.Equal("resourceProviders", resourceIdentifier.ResourceTypes[0].Key); Assert.Equal("TestProviderName", resourceIdentifier.ResourceTypes[0].Value); Assert.Equal("TestResourceType", resourceIdentifier.ResourceTypes[1].Key); Assert.Equal("TestResourceName", resourceIdentifier.ResourceTypes[1].Value); if (resourceIdentifier.ResourceTypes.Count == 3) { Assert.Equal("SubResourceType", resourceIdentifier.ResourceTypes[2].Key); Assert.Equal("SubResourceName", resourceIdentifier.ResourceTypes[2].Value); } }
public async Task RunActivity( [ActivityTrigger] IDurableActivityContext functionContext, ILogger log) { if (functionContext is null) { throw new ArgumentNullException(nameof(functionContext)); } var resourceId = functionContext.GetInput <string>(); try { var resourceIdentifier = AzureResourceIdentifier.Parse(resourceId); if (string.IsNullOrEmpty(resourceIdentifier.ResourceGroup)) { throw new RetryCanceledException($"Resource id must include resource group information: {resourceId}"); } else if (resourceIdentifier.ResourceTypes?.Any() ?? false) { throw new RetryCanceledException($"Resource id must not include resource type information: {resourceId}"); } else { var resourceGroup = await azureResourceService .GetResourceGroupAsync(resourceIdentifier.SubscriptionId, resourceIdentifier.ResourceGroup) .ConfigureAwait(false); await(resourceGroup?.DeleteAsync(true) ?? Task.CompletedTask) .ConfigureAwait(false); } } catch (Exception exc) { log.LogError(exc, $"Activity '{nameof(ResourceGroupDeleteActivity)} failed: {exc.Message}"); throw exc.AsSerializable(); } }
protected override async Task <Component> DeleteComponentAsync(Component component, Organization componentOrganization, DeploymentScope componentDeploymentScope, Project componentProject, User contextUser, IAsyncCollector <ICommand> commandQueue) { if (component is null) { throw new ArgumentNullException(nameof(component)); } if (AzureResourceIdentifier.TryParse(component.ResourceId, out var componentResourceId)) { var resourceGroup = await azureResourceService .GetResourceGroupAsync(componentResourceId.SubscriptionId, componentResourceId.ResourceGroup) .ConfigureAwait(false); if (resourceGroup is not null) { await resourceGroup .DeleteAsync(true) .ConfigureAwait(false); } // remove resource related informations component.ResourceId = null; component.ResourceUrl = null; // ensure resource state is deleted component.ResourceState = Model.Common.ResourceState.Deprovisioned; // update entity to ensure we have it's state updated in case the delete fails component = await componentRepository .SetAsync(component) .ConfigureAwait(false); } return(component); }
public async Task Run( [ActivityTrigger] IDurableActivityContext context) { if (context is null) { throw new ArgumentNullException(nameof(context)); } var project = context.GetInput <Input>().Project; if (AzureResourceIdentifier.TryParse(project.ResourceId, out var resourceId)) { var resourceGroup = await azureResourceService .GetResourceGroupAsync(resourceId.SubscriptionId, resourceId.ResourceGroup) .ConfigureAwait(false); if (resourceGroup is not null) { await resourceGroup .DeleteAsync(true) .ConfigureAwait(false); } } }
public static async Task RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext orchestrationContext, ILogger log) { if (orchestrationContext is null) { throw new ArgumentNullException(nameof(orchestrationContext)); } var functionLog = orchestrationContext.CreateReplaySafeLogger(log ?? NullLogger.Instance); var subscriptionId = orchestrationContext.GetInput <Guid>(); var resourceId = new AzureResourceIdentifier(subscriptionId); var initializationTimeout = TimeSpan.FromMinutes(5); try { var currentSubscriptionVersion = await orchestrationContext .GetSubscriptionVersionAsync(subscriptionId) .ConfigureAwait(true); if (currentSubscriptionVersion != TargetSubscriptionVersion) { using (await orchestrationContext.LockAzureResourceAsync(resourceId).ConfigureAwait(true)) { currentSubscriptionVersion = await orchestrationContext .GetSubscriptionVersionAsync(subscriptionId) .ConfigureAwait(true); if (currentSubscriptionVersion != TargetSubscriptionVersion) { // we have to offload the subscription initialization deployment to // an independant orchestration (StartDeploymentAsync) as we initiate // the deployment inside a critical section. this doesn't allow us // to run the deploy as a nested orchestration (CallDeploymentAsync). var deploymentOutputEventName = subscriptionId.ToString(); _ = await orchestrationContext .StartDeploymentAsync(nameof(ProjectSubscriptonInitializeActivity), subscriptionId, deploymentOutputEventName) .ConfigureAwait(true); await orchestrationContext .WaitForExternalEvent(deploymentOutputEventName, initializationTimeout) .ConfigureAwait(true); _ = await orchestrationContext .SetSubscriptionVersionAsync(subscriptionId, TargetSubscriptionVersion) .ConfigureAwait(true); } } } } catch (TimeoutException exc) { functionLog.LogError(exc, $"Failed to initialize subscription '{subscriptionId}' within a {initializationTimeout} timeout"); } catch (Exception exc) { functionLog.LogError(exc, $"Failed to initialize subscription '{subscriptionId}': {exc.Message}"); } }
public EventHubManager(AzureCredentials azureConfigCredentials, AzureResourceIdentifier azureResourceIdentifier) { _azureCredentials = azureConfigCredentials ?? throw new ArgumentNullException(nameof(azureConfigCredentials)); _azureResourceIdentifier = azureResourceIdentifier ?? throw new ArgumentNullException(nameof(azureResourceIdentifier)); }
private async Task <IEnumerable <Guid> > GetSubscriptionIdsAsync(Component component) { var deploymentScope = await deploymentScopeRepository .GetAsync(component.Organization, component.DeploymentScopeId, true) .ConfigureAwait(false); IEnumerable <Guid> subscriptionIds; if (AzureResourceIdentifier.TryParse(deploymentScope.ManagementGroupId, out var managementGroupResourceId)) { try { var client = await azureResourceService.AzureSessionService .CreateClientAsync <ManagementGroupsAPIClient>() .ConfigureAwait(false); var group = await client.ManagementGroups .GetAsync(managementGroupResourceId.ResourceTypes.Last().Value, expand : "children") .ConfigureAwait(false); subscriptionIds = group.Children .Where(child => child.Type.Equals("/subscriptions", StringComparison.OrdinalIgnoreCase)) .Select(child => Guid.Parse(child.Name)); } catch { subscriptionIds = Enumerable.Empty <Guid>(); } } else { try { var session = await azureResourceService.AzureSessionService .CreateSessionAsync() .ConfigureAwait(false); var subscriptions = await session.Subscriptions .ListAsync(loadAllPages : true) .ConfigureAwait(false); subscriptionIds = subscriptions .Where(subscription => deploymentScope.SubscriptionIds.Contains(Guid.Parse(subscription.SubscriptionId))) .Select(subscription => Guid.Parse(subscription.SubscriptionId)); } catch { subscriptionIds = Enumerable.Empty <Guid>(); } } var identity = await azureResourceService.AzureSessionService .GetIdentityAsync() .ConfigureAwait(false); var subscriptionIdsValidated = await Task .WhenAll(subscriptionIds.Select(subscriptionId => ProveOwnershipAsync(subscriptionId, identity.ObjectId))) .ConfigureAwait(false); return(subscriptionIdsValidated .Where(subscriptionId => subscriptionId != Guid.Empty)); async Task <Guid> ProveOwnershipAsync(Guid subscriptionId, Guid userObjectId) { var subscription = await azureResourceService .GetSubscriptionAsync(subscriptionId) .ConfigureAwait(false); var hasOwnership = await subscription .HasRoleAssignmentAsync(userObjectId.ToString(), AzureRoleDefinition.Owner, true) .ConfigureAwait(false); return(hasOwnership ? subscriptionId : Guid.Empty); } }
protected override async Task <Component> UpdateComponentAsync(Component component, Organization componentOrganization, DeploymentScope componentDeploymentScope, Project componentProject, User contextUser, IAsyncCollector <ICommand> commandQueue) { if (component is null) { throw new ArgumentNullException(nameof(component)); } if (AzureResourceIdentifier.TryParse(component.ResourceId, out var componentResourceId)) { var tasks = new Task[] { UpdateComponentRoleAssignmentsAsync(), UpdateComponentTagsAsync() }; await Task.WhenAll(tasks).ConfigureAwait(false); } return(component); async Task UpdateComponentRoleAssignmentsAsync() { var roleAssignmentMap = await GetRoleAssignmentsAsync(component) .ConfigureAwait(false); if (AzureResourceIdentifier.TryParse(component.IdentityId, out var identityResourceId)) { var session = await azureResourceService.AzureSessionService .CreateSessionAsync(identityResourceId.SubscriptionId) .ConfigureAwait(false); var identity = await session.Identities .GetByIdAsync(identityResourceId.ToString()) .ConfigureAwait(false); roleAssignmentMap .Add(identity.PrincipalId, Enumerable.Repeat(AzureRoleDefinition.Contributor, 1)); } if (string.IsNullOrEmpty(componentResourceId.ResourceGroup)) { var subscription = await azureResourceService .GetSubscriptionAsync(componentResourceId.SubscriptionId, throwIfNotExists : true) .ConfigureAwait(false); if (subscription is not null) { await subscription.SetRoleAssignmentsAsync(roleAssignmentMap).ConfigureAwait(false); } } else { var resourceGroup = await azureResourceService .GetResourceGroupAsync(componentResourceId.SubscriptionId, componentResourceId.ResourceGroup, throwIfNotExists : true) .ConfigureAwait(false); if (resourceGroup is not null) { await resourceGroup.SetRoleAssignmentsAsync(roleAssignmentMap).ConfigureAwait(false); } } } async Task UpdateComponentTagsAsync() { var tenantId = await azureResourceService.AzureSessionService .GetTenantIdAsync() .ConfigureAwait(false); var organization = await organizationRepository .GetAsync(tenantId.ToString(), component.Organization, true) .ConfigureAwait(false); var project = await projectRepository .GetAsync(component.Organization, component.ProjectId, true) .ConfigureAwait(false); var tags = organization.Tags .Union(project.Tags) .GroupBy(kvp => kvp.Key) .ToDictionary(g => g.Key, g => g.First().Value); if (string.IsNullOrEmpty(componentResourceId.ResourceGroup)) { var subscription = await azureResourceService .GetSubscriptionAsync(componentResourceId.SubscriptionId) .ConfigureAwait(false); if (subscription is not null) { await subscription.SetTagsAsync(tags, true).ConfigureAwait(false); } } else { var resourceGroup = await azureResourceService .GetResourceGroupAsync(componentResourceId.SubscriptionId, componentResourceId.ResourceGroup) .ConfigureAwait(false); if (resourceGroup is not null) { await resourceGroup.SetTagsAsync(tags, true).ConfigureAwait(false); } } } }
public void ParseResourceIdUnnamedNotAllowed(string resourceId) { Assert.Throws <ArgumentException>(() => AzureResourceIdentifier.Parse(resourceId, allowUnnamedResource: false)); }
public async Task <ComponentTask> Run( [ActivityTrigger] IDurableActivityContext context) { if (context is null) { throw new ArgumentNullException(nameof(context)); } var componentTask = context.GetInput <Input>().ComponentTask; try { if (AzureResourceIdentifier.TryParse(componentTask.ResourceId, out var resourceId) && await azureResourceService.ExistsResourceAsync(resourceId.ToString()).ConfigureAwait(false)) { var session = await azureResourceService.AzureSessionService .CreateSessionAsync(resourceId.SubscriptionId) .ConfigureAwait(false); var group = await session.ContainerGroups .GetByIdAsync(resourceId.ToString()) .ConfigureAwait(false); var runner = group.Containers .SingleOrDefault(c => c.Key.Equals(componentTask.Id, StringComparison.OrdinalIgnoreCase)) .Value; if (runner?.InstanceView is null) { componentTask.TaskState = TaskState.Initializing; } else if (runner.InstanceView.CurrentState is not null) { componentTask.TaskState = TaskState.Processing; componentTask.ExitCode = runner.InstanceView.CurrentState.ExitCode; componentTask.Started = runner.InstanceView.CurrentState.StartTime; componentTask.Finished = runner.InstanceView.CurrentState.FinishTime; if (componentTask.ExitCode.HasValue) { componentTask.TaskState = componentTask.ExitCode == 0 ? TaskState.Succeeded // ExitCode indicates successful provisioning : TaskState.Failed; // ExitCode indicates failed provisioning } else if (runner.InstanceView.CurrentState.State?.Equals("Terminated", StringComparison.OrdinalIgnoreCase) ?? false) { // container instance was terminated without exit code componentTask.TaskState = TaskState.Failed; } if (componentTask.TaskState == TaskState.Failed && !componentTask.ExitCode.HasValue) { var output = new StringBuilder(); output.AppendLine($"Creating runner {group.Id} ended in state {group.State} !!! {Environment.NewLine}"); output.AppendLine(await group.GetLogContentAsync(runner.Name).ConfigureAwait(false)); var project = await projectRepository .GetAsync(componentTask.Organization, componentTask.ProjectId) .ConfigureAwait(false); if (AzureResourceIdentifier.TryParse(project?.StorageId, out var storageId)) { var storage = await azureResourceService .GetResourceAsync <AzureStorageAccountResource>(storageId.ToString()) .ConfigureAwait(false); if (storage is not null) { var outputDirectory = ".output"; var fileClient = await storage .CreateShareFileClientAsync(componentTask.ComponentId, $"{outputDirectory}/{componentTask.Id}") .ConfigureAwait(false); if (!await fileClient.ExistsAsync().ConfigureAwait(false)) { await storage .EnsureDirectoryPathAsync(componentTask.ComponentId, outputDirectory) .ConfigureAwait(false); var logBuffer = Encoding.Default.GetBytes(output.ToString()); using var fileStream = await fileClient .OpenWriteAsync(true, 0, options : new ShareFileOpenWriteOptions() { MaxSize = logBuffer.Length }) .ConfigureAwait(false); await fileStream .WriteAsync(logBuffer, 0, logBuffer.Length) .ConfigureAwait(false); } } } } } componentTask = await componentTaskRepository .SetAsync(componentTask) .ConfigureAwait(false); } } catch (Exception exc) { throw exc.AsSerializable(); } return(componentTask); }
public async Task <ComponentTask> Run( [ActivityTrigger] IDurableActivityContext context, ILogger log) { if (context is null) { throw new ArgumentNullException(nameof(context)); } if (log is null) { throw new ArgumentNullException(nameof(log)); } var componentTask = context.GetInput <Input>().ComponentTask; try { if (AzureResourceIdentifier.TryParse(componentTask.ResourceId, out var resourceId)) { if (!componentTask.TaskState.IsFinal()) { componentTask.TaskState = TaskState.Failed; componentTask = await componentTaskRepository .SetAsync(componentTask) .ConfigureAwait(false); } var containerGroup = await azureResourceService .GetResourceAsync <AzureContainerGroupResource>(resourceId.ToString()) .ConfigureAwait(false); if (containerGroup is not null) { try { await containerGroup .StopAsync() .ConfigureAwait(false); } catch { // swallow } finally { var location = await containerGroup .GetLocationAsync() .ConfigureAwait(false); var usageData = await AzureContainerGroupResource .GetUsageAsync(azureResourceService, containerGroup.ResourceId.SubscriptionId, location) .ConfigureAwait(false); var usage = usageData .SingleOrDefault(u => u.Unit.Equals("Count") && u.Name.Value.Equals("ContainerGroups")); var limit = usage?.Limit.GetValueOrDefault() ?? 0; var current = usage?.CurrentValue.GetValueOrDefault() ?? 0; if (current >= limit) { await containerGroup .DeleteAsync() .ConfigureAwait(false); } } } } } catch (Exception exc) { throw exc.AsSerializable(); } return(componentTask); }
private async Task <string> GetOutputAsync(ComponentTask document) { var output = default(string); var outputKey = $"{GetType()}|{document.GetType()}|{document.Id}"; var outputUrl = await cache .GetOrCreateAsync(outputKey, GetOutputUrlAsync) .ConfigureAwait(false); if (outputUrl is null) { cache.Remove(outputKey); } else { if (document.TaskState.IsActive()) { output = await GetOutputLogAsync(null) .ConfigureAwait(false); } else { output = await cache .GetOrCreateAsync(outputUrl, GetOutputLogAsync) .ConfigureAwait(false); if (string.IsNullOrEmpty(output)) { cache.Remove(outputUrl); } } } return(output); async Task <string> GetOutputLogAsync(ICacheEntry entry) { try { using var stream = await outputUrl.ToString() .WithHeader("responsecontent-disposition", "file; attachment") .WithHeader("responsecontent-type", "binary") .GetStreamAsync() .ConfigureAwait(false); if ((stream?.Length ?? 0) > 0) { using var reader = new StreamReader(stream); if (entry is not null) { entry.AbsoluteExpiration = DateTime.UtcNow.AddDays(1); entry.Value = await reader .ReadToEndAsync() .ConfigureAwait(false); } else { return(await reader .ReadToEndAsync() .ConfigureAwait(false)); } } } catch { // swallow } return(entry?.Value as string); } async Task <Uri> GetOutputUrlAsync(ICacheEntry entry) { try { var project = await projectRepository .GetAsync(document.Organization, document.ProjectId) .ConfigureAwait(false); if (AzureResourceIdentifier.TryParse(project?.StorageId, out var storageId)) { var storageAccount = await azureResourceService .GetResourceAsync <AzureStorageAccountResource>(storageId.ToString(), false) .ConfigureAwait(false); if (storageAccount is not null) { entry.AbsoluteExpiration = DateTimeOffset.UtcNow.AddDays(1); entry.Value = await storageAccount // create a shared access token with an additional expiration offset to avoid time sync issues when fetching the output .CreateShareFileSasUriAsync(document.ComponentId, $".output/{document.Id}", ShareFileSasPermissions.Read, entry.AbsoluteExpiration.Value.AddMinutes(5)) .ConfigureAwait(false); } } } catch { // swallow } return(entry?.Value as Uri); } }