src/Azure.Deployments.Extensibility.Providers.Kubernetes/Extensions/ExtensibilityOperationRequestExtensions.cs (83 lines of code) (raw):

// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using Azure.Deployments.Extensibility.Core; using Azure.Deployments.Extensibility.Core.Exceptions; using Azure.Deployments.Extensibility.Core.Extensions; using Azure.Deployments.Extensibility.Providers.Kubernetes.Models; using k8s; using k8s.Models; namespace Azure.Deployments.Extensibility.Providers.Kubernetes.Extensions { public static class ExtensibilityOperationRequestExtensions { public async static Task<KubernetesResource> ProcessAsync(this ExtensibilityOperationRequest request, CancellationToken cancellationToken) { var (import, resource) = Validate(request); var resourceType = KubernetesResourceType.Parse(resource.Type); var properties = resource.Properties .PatchProperty("apiVersion", resourceType.ApiVersion) .PatchProperty("kind", resourceType.Kind); var clientConfiguration = await CreateClientConfigurationAsync(import); IKubernetes? kubernetes = null; try { kubernetes = new k8s.Kubernetes(clientConfiguration); var client = new GenericClient(kubernetes, resourceType.Group, resourceType.Version, plural: ""); var apiResouceList = await client.ListAsync<V1APIResourceList>(cancellationToken); var apiResource = apiResouceList.Resources.FirstOrDefault(x => x.Kind.Equals(resourceType.Kind, StringComparison.Ordinal)); if (apiResource is null) { throw new ExtensibilityException( "UnknownResourceKind", resource.GetJsonPointer(x => x.Type), @$"Unknown resource kind ""{resourceType.Kind}"" in resource type ""{resource.Type}""."); } if (!apiResource.Namespaced && properties.Metadata.Namespace is not null) { throw new ExtensibilityException( "NamespaceSpecifiedForClusterResource", resource.GetJsonPointer(x => x.Properties.Metadata.Namespace!), "A namespace should not be specified for a cluster-scoped resource."); } var @namespace = apiResource.Namespaced ? resource.Properties.Metadata.Namespace ?? import.Config.Namespace : null; return new(kubernetes, resourceType.Group, resourceType.Version, @namespace, apiResource.Name, properties); } catch { kubernetes?.Dispose(); throw; } } private static ExtensibilityOperationRequest<KubernetesConfig, KubernetesResourceProperties> Validate(ExtensibilityOperationRequest request) { // Validate kubeConfig format. if (request.Import.Config.TryGetProperty("kubeConfig", out var kubeConfig) && !kubeConfig.GetString().IsBase64Encoded()) { throw new ExtensibilityException( "InvalidKubeConfig", request.Import.GetJsonPointer(x => x.Config).Combine("kubeConfig"), @$"Value must be a Base64-encoded string."); } // Run JSON schema validation. return request.Validate<KubernetesConfig, KubernetesResourceProperties>( KubernetesConfig.Schema, KubernetesResourceType.TypePattern, KubernetesResourceProperties.Schema); } private static async Task<KubernetesClientConfiguration> CreateClientConfigurationAsync(ExtensibleImport<KubernetesConfig> import) { try { return await KubernetesClientConfiguration.BuildConfigFromConfigFileAsync( new MemoryStream(import.Config.KubeConfig), currentContext: import.Config.Context); } catch (Exception exception) { exception = exception.GetBaseException(); throw new ExtensibilityException( "InvalidImportConfig", import.GetJsonPointer(x => x.Config), exception.Message ?? exception.ToString()); } } } }