public void ParseResourceGroupId(string resourceId)
        {
            var resourceIdentifier = AzureResourceIdentifier.Parse(resourceId);

            Assert.Equal(Guid.Empty, resourceIdentifier.SubscriptionId);
            Assert.Equal("TestRG", resourceIdentifier.ResourceGroup);
        }
예제 #2
0
    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);
    }
예제 #3
0
        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);
예제 #4
0
    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));
    }
예제 #7
0
 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);
        }
예제 #10
0
    public static bool IsAzureResourceId(this string resourceId)
    {
        if (resourceId is null)
        {
            throw new ArgumentNullException(nameof(resourceId));
        }

        return(AzureResourceIdentifier.TryParse(resourceId, out var _));
    }
예제 #11
0
    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));
    }
예제 #12
0
    internal AzureResource(string resourceId)
    {
        if (resourceId is null)
        {
            throw new ArgumentNullException(nameof(resourceId));
        }

        ResourceId           = AzureResourceIdentifier.Parse(resourceId);
        AzureResourceService = null;
    }
예제 #13
0
    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);
    }
예제 #17
0
    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);
            }
        }
예제 #20
0
        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);
    }
예제 #22
0
    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);
            }
        }
    }
예제 #23
0
        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}");
            }
        }
예제 #24
0
 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);
    }
예제 #30
0
    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);
        }
    }