public void ParseResourceGroupId(string resourceId) { var resourceIdentifier = AzureResourceIdentifier.Parse(resourceId); Assert.Equal(SUBSCRIPTION_ID, resourceIdentifier.SubscriptionId); Assert.Equal("TestRG", resourceIdentifier.ResourceGroup); }
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)); }
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(Guid.Empty, resourceIdentifier.SubscriptionId); Assert.Equal("TestRG", resourceIdentifier.ResourceGroup); }
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); }
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 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(); } }
public void ParseResourceIdUnnamedNotAllowed(string resourceId) { Assert.Throws <ArgumentException>(() => AzureResourceIdentifier.Parse(resourceId, allowUnnamedResource: false)); }
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; var component = await componentRepository .GetAsync(componentTask.ProjectId, componentTask.ComponentId) .ConfigureAwait(false); var componentTemplate = await componentTemplateRepository .GetAsync(component.Organization, component.ProjectId, component.TemplateId) .ConfigureAwait(false); if (string.IsNullOrEmpty(componentTemplate.TaskRunner?.Id)) { componentTask.Started = componentTask.Created; componentTask.Finished = componentTask.Created; componentTask.ExitCode = 0; componentTask.TaskState = TaskState.Succeeded; } else { var pairedRegionFallback = false; pairedRegionFallback: try { var tenantId = await azureSessionService .GetTenantIdAsync() .ConfigureAwait(false); var organization = await organizationRepository .GetAsync(tenantId.ToString(), componentTask.Organization) .ConfigureAwait(false); var project = await projectRepository .GetAsync(componentTask.Organization, componentTask.ProjectId) .ConfigureAwait(false); var projectResourceId = AzureResourceIdentifier .Parse(project.ResourceId); // we must not use the component task's id as runner label as this // will violate the maximum length of a SSL certificats CN name. var componentRunnerCpu = 1; var componentRunnerMemory = 2; var componentRunnerLocation = await GetLocationAsync(component, projectResourceId.SubscriptionId, componentRunnerCpu, componentRunnerMemory, pairedRegionFallback).ConfigureAwait(false); var componentRunnerRoot = $".{componentRunnerLocation}.azurecontainer.io"; var componentRunnerLabel = CreateUniqueString(64 - componentRunnerRoot.Length, componentTask.Id); var componentRunnerHost = string.Concat(componentRunnerLabel, componentRunnerRoot); var componentRunnerDefinition = new { location = componentRunnerLocation, identity = new { type = "UserAssigned", userAssignedIdentities = new Dictionary <string, object>() { { component.IdentityId, new { } } } }, properties = new { imageRegistryCredentials = await GetRegistryCredentialsAsync(organization).ConfigureAwait(false), containers = await GetContainersAsync(organization, component, componentTemplate, componentTask, componentRunnerHost, componentRunnerCpu, componentRunnerMemory).ConfigureAwait(false), osType = "Linux", restartPolicy = "Never", ipAddress = GetIpAddress(componentTemplate, componentRunnerLabel), volumes = await GetVolumesAsync(project, component, componentTemplate).ConfigureAwait(false) } }; var token = await azureSessionService .AcquireTokenAsync() .ConfigureAwait(false); try { var response = await projectResourceId.GetApiUrl(azureSessionService.Environment) .AppendPathSegment($"/providers/Microsoft.ContainerInstance/containerGroups/{component.Id}") .SetQueryParam("api-version", "2021-09-01") .WithOAuthBearerToken(token) .PutJsonAsync(componentRunnerDefinition) .ConfigureAwait(false); var responseJson = await response .GetJsonAsync <JObject>() .ConfigureAwait(false); componentTask.ResourceId = responseJson.SelectToken("$.id").ToString(); } catch (FlurlHttpException apiExc) when(apiExc.StatusCode == StatusCodes.Status409Conflict) { if (pairedRegionFallback) { // give azure some time to do its work // and remove any naming conflicts await Task .Delay(TimeSpan.FromMinutes(1)) .ConfigureAwait(false); } var response = await projectResourceId.GetApiUrl(azureSessionService.Environment) .AppendPathSegment($"/providers/Microsoft.ContainerInstance/containerGroups/{componentTask.Id}") .SetQueryParam("api-version", "2019-12-01") .AllowHttpStatus(HttpStatusCode.NotFound) .WithOAuthBearerToken(token) .GetAsync() .ConfigureAwait(false); if (response.IsSuccessStatusCode()) { var responseJson = await response .GetJsonAsync <JObject>() .ConfigureAwait(false); componentTask.ResourceId = responseJson .SelectToken("$.id")? .ToString(); } else { throw; } } catch (FlurlHttpException apiExc) when(apiExc.StatusCode == StatusCodes.Status504GatewayTimeout && !pairedRegionFallback) { // enable paired region fallback - this will affect error handling pairedRegionFallback = true; // goto paired region fallback label and restart processing goto pairedRegionFallback; } componentTask = await componentTaskRepository .SetAsync(componentTask) .ConfigureAwait(false); } catch (Exception exc) { var errorMessage = exc.Message; if (exc is FlurlHttpException flurlExc && flurlExc.Call.Completed) { var error = await flurlExc .GetResponseJsonAsync <JObject>() .ConfigureAwait(false); errorMessage = error.SelectToken("..message")?.ToString() ?? errorMessage; } log.LogError(exc, $"Failed to create runner for component deployment {componentTask}: {errorMessage}"); throw exc.AsSerializable(); } } return(componentTask); }