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 RunActivity(
            [ActivityTrigger] IDurableActivityContext activityContext,
            ILogger log)
        {
            if (activityContext is null)
            {
                throw new ArgumentNullException(nameof(activityContext));
            }

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

            try
            {
                var resource = await azureResourceService
                               .GetResourceAsync(resourceId)
                               .ConfigureAwait(false);

                await(resource?.DeleteAsync(true) ?? Task.CompletedTask)
                .ConfigureAwait(false);
            }
            catch (Exception exc)
            {
                log.LogError(exc, $"Activity '{nameof(ResourceDeleteActivity)} failed: {exc.Message}");

                throw exc.AsSerializable();
            }
        }
Esempio n. 3
0
        public async Task RunActivity(
            [ActivityTrigger] IDurableActivityContext functionContext,
            ILogger log)
        {
            if (functionContext is null)
            {
                throw new ArgumentNullException(nameof(functionContext));
            }

            var(project, resourceId) = functionContext.GetInput <(Project, string)>();

            using (log.BeginProjectScope(project))
            {
                try
                {
                    var resource = await azureResourceService
                                   .GetResourceAsync(resourceId, throwIfNotExists : true)
                                   .ConfigureAwait(false);

                    await resource
                    .SetTagsAsync(project.Tags)
                    .ConfigureAwait(false);
                }
                catch (Exception exc)
                {
                    log.LogError(exc, $"{nameof(ProjectResourceTagsActivity)} failed: {exc.Message}");

                    throw exc.AsSerializable();
                }
            }
        }
        public async Task RunActivity(
            [ActivityTrigger] IDurableActivityContext functionContext)
        {
            if (functionContext is null)
            {
                throw new ArgumentNullException(nameof(functionContext));
            }

            var project = functionContext.GetInput <Project>();

            var keyVault = await azureResourceService
                           .GetResourceAsync <AzureKeyVaultResource>(project.KeyVault.VaultId, throwIfNotExists : true)
                           .ConfigureAwait(false);

            var projectIdentityJson = await keyVault
                                      .GetSecretAsync(nameof(ProjectIdentity))
                                      .ConfigureAwait(false);

            if (!string.IsNullOrEmpty(projectIdentityJson))
            {
                await azureDirectoryService
                .DeleteServicePrincipalAsync(project.Id.ToString())
                .ConfigureAwait(false);
            }

            await keyVault
            .SetSecretAsync(nameof(ProjectIdentity), null)
            .ConfigureAwait(false);
        }
        public async Task RunActivity(
            [ActivityTrigger] IDurableActivityContext functionContext,
            ILogger log)
        {
            if (functionContext is null)
            {
                throw new ArgumentNullException(nameof(functionContext));
            }

            var(project, resourceId) = functionContext.GetInput <(Project, string)>();

            using (log.BeginProjectScope(project))
            {
                try
                {
                    var resource = await azureResourceService
                                   .GetResourceAsync(resourceId, throwIfNotExists : true)
                                   .ConfigureAwait(false);

                    var roleAssignments = (project.Users ?? Enumerable.Empty <User>())
                                          .ToDictionary(user => user.Id, user => Enumerable.Repeat((user.ProjectMembership(project.Id)?.Role ?? ProjectUserRole.None).ToRoleDefinitionId(), 1));

                    await resource
                    .SetRoleAssignmentsAsync(roleAssignments)
                    .ConfigureAwait(false);
                }
                catch (Exception exc)
                {
                    log.LogError(exc, $"{nameof(ProjectUsersActivity)} failed: {exc.Message}");

                    throw exc.AsSerializable();
                }
            }
        }
    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 async Task <ISecretsStore> GetSecretsStoreAsync(Organization organization)
    {
        if (organization is null)
        {
            throw new ArgumentNullException(nameof(organization));
        }

        if (string.IsNullOrEmpty(organization.SecretsVaultId))
        {
            throw new ArgumentException($"Secrets vault not available.", nameof(organization));
        }

        var keyVaultResource = await keyVaultResourceCache.GetOrAdd(organization.SecretsVaultId, (key) => new AsyncLazy <AzureKeyVaultResource>(async() =>
        {
            var secretsVault = await azureResourceService
                               .GetResourceAsync <AzureKeyVaultResource>(organization.SecretsVaultId, true)
                               .ConfigureAwait(false);

            var identity = await azureResourceService.AzureSessionService
                           .GetIdentityAsync()
                           .ConfigureAwait(false);

            await secretsVault
            .SetAllSecretPermissionsAsync(identity.ObjectId)
            .ConfigureAwait(false);

            return(secretsVault);
        })).ConfigureAwait(false);

        try
        {
            return(ActivatorUtilities.CreateInstance <TSecretsStore>(serviceProvider, keyVaultResource));
        }
        catch
        {
            throw;
        }
    }
        public async Task RunActivity(
            [ActivityTrigger] IDurableActivityContext functionContext)
        {
            if (functionContext is null)
            {
                throw new ArgumentNullException(nameof(functionContext));
            }

            var project = functionContext.GetInput <Project>();

            var keyVault = await azureResourceService
                           .GetResourceAsync <AzureKeyVaultResource>(project.KeyVault.VaultId, throwIfNotExists : true)
                           .ConfigureAwait(false);

            var projectIdentityJson = await keyVault
                                      .GetSecretAsync(nameof(ProjectIdentity))
                                      .ConfigureAwait(false);

            if (string.IsNullOrEmpty(projectIdentityJson))
            {
                var servicePrincipal = await azureDirectoryService
                                       .CreateServicePrincipalAsync(project.Id.ToString())
                                       .ConfigureAwait(false);

                try
                {
                    var projectIdentity = new ProjectIdentity()
                    {
                        Id            = servicePrincipal.ObjectId.ToString(),
                        ApplicationId = servicePrincipal.ApplicationId,
                        Secret        = servicePrincipal.Password
                    };

                    projectIdentityJson = JsonConvert.SerializeObject(projectIdentity);

                    await keyVault
                    .SetSecretAsync(nameof(ProjectIdentity), projectIdentityJson)
                    .ConfigureAwait(false);
                }
                catch
                {
                    await azureDirectoryService
                    .DeleteServicePrincipalAsync(project.Id.ToString())
                    .ConfigureAwait(false);
                }
            }
        }
        private async Task EnsureKeyVaultAccessAsync(Project project, Guid principalId)
        {
            var keyVault = await azureResourceService
                           .GetResourceAsync <AzureKeyVaultResource>(project.KeyVault.VaultId, throwIfNotExists : true)
                           .ConfigureAwait(false);

            if (keyVault != null)
            {
                var systemIdentity = await azureSessionService
                                     .GetIdentityAsync()
                                     .ConfigureAwait(false);

                if (systemIdentity.ObjectId == principalId)
                {
                    await keyVault
                    .SetAllCertificatePermissionsAsync(principalId)
                    .ConfigureAwait(false);

                    await keyVault
                    .SetAllKeyPermissionsAsync(principalId)
                    .ConfigureAwait(false);

                    await keyVault
                    .SetAllSecretPermissionsAsync(principalId)
                    .ConfigureAwait(false);
                }
                else
                {
                    await keyVault
                    .SetCertificatePermissionsAsync(principalId, CertificatePermissions.Get, CertificatePermissions.List)
                    .ConfigureAwait(false);

                    await keyVault
                    .SetKeyPermissionsAsync(principalId, KeyPermissions.Get, KeyPermissions.List)
                    .ConfigureAwait(false);

                    await keyVault
                    .SetSecretPermissionsAsync(principalId, SecretPermissions.Get, SecretPermissions.List)
                    .ConfigureAwait(false);
                }
            }
        }
        public async Task RunActivity(
            [ActivityTrigger] IDurableActivityContext functionContext,
            ILogger log)
        {
            if (functionContext is null)
            {
                throw new ArgumentNullException(nameof(functionContext));
            }

            var(project, resourceId) = functionContext.GetInput <(Project, string)>();

            using (log.BeginProjectScope(project))
            {
                try
                {
                    var resource = await azureResourceService
                                   .GetResourceAsync(resourceId, throwIfNotExists : true)
                                   .ConfigureAwait(false);

                    var roleAssignments = project.Users
                                          .ToRoleAssignments(project.Id, role => role == ProjectUserRole.Owner
                            ? AzureRoleDefinition.Contributor
                            : AzureRoleDefinition.Reader);

                    await resource
                    .SetRoleAssignmentsAsync(roleAssignments)
                    .ConfigureAwait(false);
                }
                catch (Exception exc)
                {
                    log.LogError(exc, $"{nameof(ProjectUsersActivity)} failed: {exc.Message}");

                    throw exc.AsSerializable();
                }
            }
        }
Esempio n. 11
0
    private async Task <T> WithKubernetesContext <T>(Component component, DeploymentScope deploymentScope, Func <IKubernetes, KubernetesData, V1ClusterRole, V1ServiceAccount, Task <T> > callback)
    {
        if (component is null)
        {
            throw new ArgumentNullException(nameof(component));
        }

        if (deploymentScope is null)
        {
            throw new ArgumentNullException(nameof(deploymentScope));
        }

        if (callback is null)
        {
            throw new ArgumentNullException(nameof(callback));
        }

        var identity = await azureResourceService
                       .GetResourceAsync <AzureIdentityResource>(component.IdentityId, throwIfNotExists : true)
                       .ConfigureAwait(false);

        var data   = GetKubernetesData(deploymentScope);
        var client = GetKubernetesClient(data);

        var roleDefinition = new V1ClusterRole()
        {
            Metadata = new V1ObjectMeta()
            {
                Name = "teamcloud-runner"
            },
            Rules = new List <V1PolicyRule>()
            {
                new V1PolicyRule()
                {
                    ApiGroups = new List <string>()
                    {
                        "", "extensions", "apps"
                    },
                    Resources = new List <string>()
                    {
                        "*"
                    },
                    Verbs = new List <string>()
                    {
                        "*"
                    }
                },
                new V1PolicyRule()
                {
                    ApiGroups = new List <string>()
                    {
                        "batch"
                    },
                    Resources = new List <string>()
                    {
                        "jobs", "cronjobs"
                    },
                    Verbs = new List <string>()
                    {
                        "*"
                    }
                }
            }
        };

        try
        {
            roleDefinition = await client
                             .CreateClusterRoleAsync(roleDefinition)
                             .ConfigureAwait(false);
        }
        catch (HttpOperationException exc) when(exc.Response.StatusCode == System.Net.HttpStatusCode.Conflict)
        {
            roleDefinition = await client
                             .ReadClusterRoleAsync(roleDefinition.Metadata.Name)
                             .ConfigureAwait(false);
        }

        var serviceAccount = new V1ServiceAccount()
        {
            Metadata = new V1ObjectMeta()
            {
                Name = $"{data.Namespace}-{identity.PrincipalId}"
            }
        };

        try
        {
            serviceAccount = await client
                             .CreateNamespacedServiceAccountAsync(serviceAccount, data.Namespace)
                             .ConfigureAwait(false);
        }
        catch (HttpOperationException exc) when(exc.Response.StatusCode == System.Net.HttpStatusCode.Conflict)
        {
            serviceAccount = await client
                             .ReadNamespacedServiceAccountAsync(serviceAccount.Metadata.Name, data.Namespace)
                             .ConfigureAwait(false);
        }

        return(await callback(client, data, roleDefinition, serviceAccount).ConfigureAwait(false));
    }
Esempio n. 12
0
    public async Task ExpandAsync(Component document)
    {
        if (document is null)
        {
            throw new ArgumentNullException(nameof(document));
        }

        if (string.IsNullOrEmpty(document.ValueJson))
        {
            var project = await projectRepository
                          .GetAsync(document.Organization, document.ProjectId)
                          .ConfigureAwait(false);

            if (AzureResourceIdentifier.TryParse(project?.StorageId, out var storageId))
            {
                var cacheKey = $"{GetType()}|{document.GetType()}|{document.Id}";

                try
                {
                    var sasUrl = await cache
                                 .GetOrCreateAsync(cacheKey, AcquireSasUrl)
                                 .ConfigureAwait(false);

                    if (sasUrl is null)
                    {
                        cache.Remove(cacheKey);
                    }
                    else
                    {
                        using var stream = await sasUrl.ToString()
                                           .WithHeader("responsecontent-disposition", "file; attachment")
                                           .WithHeader("responsecontent-type", "binary")
                                           .GetStreamAsync()
                                           .ConfigureAwait(false);

                        if ((stream?.Length ?? 0) > 0)
                        {
                            using var reader = new StreamReader(stream);

                            document.ValueJson = await reader
                                                 .ReadToEndAsync()
                                                 .ConfigureAwait(false);
                        }
                    }
                }
                catch
                {
                    // swallow
                }
            }

            async Task <Uri> AcquireSasUrl(ICacheEntry entry)
            {
                var storageAccount = await azureResourceService
                                     .GetResourceAsync <AzureStorageAccountResource>(storageId.ToString(), false)
                                     .ConfigureAwait(false);

                if (storageAccount is null)
                {
                    return(null);
                }

                entry.AbsoluteExpiration = DateTimeOffset.UtcNow.AddDays(1);

                return(await storageAccount
                       .CreateShareFileSasUriAsync(document.Id, "value.json", ShareFileSasPermissions.Read, entry.AbsoluteExpiration.Value.AddMinutes(5))
                       .ConfigureAwait(false));
            }
        }
    }
    public override async Task <ICommandResult> HandleAsync(ComponentTaskCancelCommand command, IAsyncCollector <ICommand> commandQueue, IDurableOrchestrationContext orchestrationContext, ILogger log)
    {
        if (command is null)
        {
            throw new ArgumentNullException(nameof(command));
        }

        if (commandQueue is null)
        {
            throw new ArgumentNullException(nameof(commandQueue));
        }

        var commandResult = command.CreateResult();

        try
        {
            commandResult.Result = (await componentTaskRepository
                                    .GetAsync(command.Payload.ComponentId, command.Payload.Id)
                                    .ConfigureAwait(Orchestration)) ?? command.Payload;

            if (commandResult.Result.Type != ComponentTaskType.Custom)
            {
                throw new Exception($"Component tasks of type '{commandResult.Result.TypeName}' cannot be canceled!");
            }
            else if (commandResult.Result.TaskState.IsFinal())
            {
                throw new Exception($"Component tasks in state '{commandResult.Result.TaskState}' cannot be canceled!");
            }
            else
            {
                var status = await orchestrationContext
                             .GetCommandStatusAsync(commandResult.Result, showInput : false)
                             .ConfigureAwait(Orchestration);

                if (status is not null && status.RuntimeStatus.IsActive())
                {
                    await orchestrationContext
                    .TerminateCommandAsync(commandResult.Result, $"Canceled by user {command.User.DisplayName}")
                    .ConfigureAwait(Orchestration);
                }

                if (AzureResourceIdentifier.TryParse(commandResult.Result.ResourceId, out var resourceId))
                {
                    var containerGroup = await azureResourceService
                                         .GetResourceAsync <AzureContainerGroupResource>(resourceId.ToString())
                                         .ConfigureAwait(false);

                    if (containerGroup is not null)
                    {
                        await containerGroup
                        .DeleteAsync(true)
                        .ConfigureAwait(false);
                    }
                }

                commandResult.Result.TaskState  = TaskState.Canceled;
                commandResult.Result.Finished   = DateTime.UtcNow;
                commandResult.Result.ResourceId = null;

                commandResult.Result = await componentTaskRepository
                                       .SetAsync(commandResult.Result)
                                       .ConfigureAwait(Orchestration);
            }

            commandResult.RuntimeStatus = CommandRuntimeStatus.Completed;
        }
        catch (Exception exc)
        {
            commandResult.Errors.Add(exc);
        }
        finally
        {
            await orchestrationContext
            .CleanupResourceLocksAsync()
            .ConfigureAwait(Orchestration);
        }

        return(commandResult);
    }