示例#1
0
        V1PersistentVolumeClaim ExtractPvc(Mount mount, IDictionary <string, string> labels)
        {
            string name     = KubeUtils.SanitizeK8sValue(mount.Source);
            bool   readOnly = mount.ReadOnly;
            var    persistentVolumeClaimSpec = new V1PersistentVolumeClaimSpec()
            {
                // What happens if the PV access mode is not compatible with the access we're requesting?
                // Deployment will be created and will be in a failed state. The user will see this as
                // module running == false.
                AccessModes = new List <string> {
                    readOnly ? "ReadOnlyMany" : "ReadWriteMany"
                },
                Resources = new V1ResourceRequirements()
                {
                    Requests = new Dictionary <string, ResourceQuantity>()
                    {
                        { "storage", new ResourceQuantity($"{this.persistentVolumeClaimSizeMb}Mi") }
                    }
                },
            };

            // prefer persistent volume name to storage class name, if both are set.
            if (this.persistentVolumeName.HasValue)
            {
                this.persistentVolumeName.ForEach(volumeName => persistentVolumeClaimSpec.VolumeName = volumeName);
            }
            else if (this.storageClassName.HasValue)
            {
                this.storageClassName.ForEach(storageClass => persistentVolumeClaimSpec.StorageClassName = storageClass);
            }

            return(new V1PersistentVolumeClaim(metadata: new V1ObjectMeta(name: name, labels: labels), spec: persistentVolumeClaimSpec));
        }
 public EdgeDeploymentCommand(
     string deviceNamespace,
     ResourceName resourceName,
     IKubernetes client,
     IEnumerable <IModule> modules,
     IRuntimeInfo runtimeInfo,
     ICombinedConfigProvider <CombinedKubernetesConfig> configProvider)
 {
     this.deviceNamespace = KubeUtils.SanitizeK8sValue(Preconditions.CheckNonWhiteSpace(deviceNamespace, nameof(deviceNamespace)));
     this.resourceName    = Preconditions.CheckNotNull(resourceName, nameof(resourceName));
     this.client          = Preconditions.CheckNotNull(client, nameof(client));
     this.modules         = Preconditions.CheckNotNull(modules, nameof(modules)).ToList();
     this.runtimeInfo     = Preconditions.CheckNotNull(runtimeInfo, nameof(runtimeInfo));
     this.configProvider  = Preconditions.CheckNotNull(configProvider, nameof(configProvider));
     this.id = new Lazy <string>(() => this.modules.Aggregate(string.Empty, (prev, module) => module.Name + prev));
     this.serializerSettings = new JsonSerializerSettings
     {
         ContractResolver = new OverrideJsonIgnoreOfBaseClassContractResolver(
             new Dictionary <Type, string[]>
         {
             [typeof(KubernetesModule)] = new[] { nameof(KubernetesModule.Name) }
         })
         {
             // Environment variable (env) property JSON casing should be left alone
             NamingStrategy = new CamelCaseNamingStrategy
             {
                 ProcessDictionaryKeys = false
             }
         }
     };
 }
示例#3
0
        public async Task <Plan> PlanAsync(
            ModuleSet desired,
            ModuleSet current,
            IRuntimeInfo runtimeInfo,
            IImmutableDictionary <string, IModuleIdentity> moduleIdentities)
        {
            Events.LogDesired(desired);
            Events.LogCurrent(current);
            Events.LogIdentities(moduleIdentities);

            // Check that module names sanitize and remain unique.
            var groupedModules = desired.Modules.ToLookup(pair => KubeUtils.SanitizeK8sValue(pair.Key));

            if (groupedModules.Any(c => c.Count() > 1))
            {
                string nameList = groupedModules
                                  .Where(c => c.Count() > 1)
                                  .SelectMany(g => g, (pairs, pair) => pair.Key)
                                  .Join(",");
                throw new InvalidIdentityException($"Deployment will cause a name collision in Kubernetes namespace, modules: [{nameList}]");
            }

            // TODO: improve this so it is generic for all potential module types.
            if (!desired.Modules.Values.All(p => p is IModule <DockerConfig>))
            {
                throw new InvalidModuleException($"Kubernetes deployment currently only handles type={typeof(DockerConfig).FullName}");
            }

            // This is a workaround for K8s Public Preview Refresh
            // TODO: remove this workaround when merging to the main release
            desired = new ModuleSet(desired.Modules.Remove(Constants.EdgeAgentModuleName));
            current = new ModuleSet(current.Modules.Remove(Constants.EdgeAgentModuleName));

            Diff moduleDifference = desired.Diff(current);

            Plan plan;

            if (!moduleDifference.IsEmpty)
            {
                // The "Plan" here is very simple - if we have any change, publish all desired modules to a EdgeDeployment CRD.
                // The CRD allows us to give the customer a Kubernetes-centric way to see the deployment
                // and the status of that deployment through the "edgedeployments" API.
                var crdCommand  = new EdgeDeploymentCommand(this.deviceNamespace, this.resourceName, this.client, desired.Modules.Values, runtimeInfo, this.configProvider);
                var planCommand = await this.commandFactory.WrapAsync(crdCommand);

                var planList = new List <ICommand>
                {
                    planCommand
                };
                Events.PlanCreated(planList);
                plan = new Plan(planList);
            }
            else
            {
                plan = Plan.Empty;
            }

            return(plan);
        }
示例#4
0
        public async Task <Plan> PlanAsync(
            ModuleSet desired,
            ModuleSet current,
            IRuntimeInfo runtimeInfo,
            IImmutableDictionary <string, IModuleIdentity> moduleIdentities)
        {
            Events.LogDesired(desired);
            Events.LogCurrent(current);
            Events.LogIdentities(moduleIdentities);

            // Check that module names sanitize and remain unique.
            var groupedModules = desired.Modules.GroupBy(pair => KubeUtils.SanitizeK8sValue(pair.Key)).ToArray();

            if (groupedModules.Any(c => c.Count() > 1))
            {
                string nameList = groupedModules.Where(c => c.Count() > 1).SelectMany(g => g, (pairs, pair) => pair.Key).Join(",");
                throw new InvalidIdentityException($"Deployment will cause a name collision in Kubernetes namespace, modules: [{nameList}]");
            }

            // TODO: improve this so it is generic for all potential module types.
            if (!desired.Modules.Values.All(p => p is IModule <DockerConfig>))
            {
                throw new InvalidModuleException($"Kubernetes deployment currently only handles type={typeof(T).FullName}");
            }

            Diff moduleDifference = desired.Diff(current);

            Plan plan;

            if (!moduleDifference.IsEmpty)
            {
                // The "Plan" here is very simple - if we have any change, publish all desired modules to a CRD.
                // The CRD allows us to give the customer a Kubernetes-centric way to see the deployment
                // and the status of that deployment through the "edgedeployments" API.
                var k8sModules = desired.Modules.Select(m => new KubernetesModule <DockerConfig>(m.Value as IModule <DockerConfig>));

                var crdCommand  = new KubernetesCrdCommand <CombinedDockerConfig>(this.deviceNamespace, this.iotHubHostname, this.deviceId, this.client, k8sModules.ToArray(), Option.Some(runtimeInfo), this.combinedConfigProvider as ICombinedConfigProvider <CombinedDockerConfig>);
                var planCommand = await this.commandFactory.WrapAsync(crdCommand);

                var planList = new List <ICommand>
                {
                    planCommand
                };
                Events.PlanCreated(planList);
                plan = new Plan(planList);
            }
            else
            {
                plan = Plan.Empty;
            }

            return(plan);
        }
示例#5
0
        V1PersistentVolumeClaim ExtractPvc(KubernetesModule module, Mount mount, IDictionary <string, string> labels)
        {
            string volumeName = KubeUtils.SanitizeK8sValue(mount.Source);
            string pvcName    = KubernetesModule.PvcName(module, mount);
            bool   readOnly   = mount.ReadOnly;

            var persistentVolumeClaimSpec = new V1PersistentVolumeClaimSpec()
            {
                // What happens if the PV access mode is not compatible with the access we're requesting?
                // Deployment will be created and will be in a failed state. The user will see this as
                // module running == false.
                AccessModes = new List <string> {
                    readOnly ? "ReadOnlyMany" : "ReadWriteMany"
                },
                Resources = new V1ResourceRequirements()
                {
                    Requests = new Dictionary <string, ResourceQuantity>()
                    {
                        { "storage", new ResourceQuantity($"{this.persistentVolumeClaimSizeMb}Mi") }
                    }
                },
            };

            if (this.persistentVolumeName.HasValue)
            {
                string pvName = this.persistentVolumeName.OrDefault();
                if (pvName != volumeName)
                {
                    throw new InvalidModuleException(string.Format("The mount name {0} has to be the same as the PV name {1}", volumeName, pvName));
                }

                persistentVolumeClaimSpec.VolumeName = volumeName;
            }

            if (this.storageClassName.HasValue)
            {
                persistentVolumeClaimSpec.StorageClassName = this.storageClassName.OrDefault();
            }

            var pvcMeta = new V1ObjectMeta(
                name: pvcName,
                labels: labels,
                ownerReferences: module.Owner.ToOwnerReferences());

            return(new V1PersistentVolumeClaim(metadata: pvcMeta, spec: persistentVolumeClaimSpec));
        }
 public EdgeDeploymentCommand(
     string deviceNamespace,
     ResourceName resourceName,
     IKubernetes client,
     IEnumerable <IModule> desiredmodules,
     ModuleSet currentmodules,
     IRuntimeInfo runtimeInfo,
     ICombinedConfigProvider <CombinedKubernetesConfig> configProvider)
 {
     this.deviceNamespace = KubeUtils.SanitizeK8sValue(Preconditions.CheckNonWhiteSpace(deviceNamespace, nameof(deviceNamespace)));
     this.resourceName    = Preconditions.CheckNotNull(resourceName, nameof(resourceName));
     this.client          = Preconditions.CheckNotNull(client, nameof(client));
     this.modules         = Preconditions.CheckNotNull(desiredmodules, nameof(desiredmodules)).ToList();
     this.currentmodules  = Preconditions.CheckNotNull(currentmodules, nameof(currentmodules));
     this.runtimeInfo     = Preconditions.CheckNotNull(runtimeInfo, nameof(runtimeInfo));
     this.configProvider  = Preconditions.CheckNotNull(configProvider, nameof(configProvider));
     this.id = new Lazy <string>(() => this.modules.Aggregate(string.Empty, (prev, module) => module.Name + prev));
     this.serializerSettings = EdgeDeploymentSerialization.SerializerSettings;
 }
示例#7
0
        public KubernetesCrdCommand(string deviceNamespace, string iotHubHostname, string deviceId, IKubernetes client, KubernetesModule <DockerConfig>[] modules, Option <IRuntimeInfo> runtimeInfo, ICombinedConfigProvider <T> combinedConfigProvider)
        {
            this.deviceNamespace        = KubeUtils.SanitizeK8sValue(Preconditions.CheckNonWhiteSpace(deviceNamespace, nameof(deviceNamespace)));
            this.iotHubHostname         = KubeUtils.SanitizeK8sValue(Preconditions.CheckNonWhiteSpace(iotHubHostname, nameof(iotHubHostname)));
            this.deviceId               = KubeUtils.SanitizeK8sValue(Preconditions.CheckNonWhiteSpace(deviceId, nameof(deviceId)));
            this.client                 = Preconditions.CheckNotNull(client, nameof(client));
            this.modules                = Preconditions.CheckNotNull(modules, nameof(modules));
            this.runtimeInfo            = Preconditions.CheckNotNull(runtimeInfo, nameof(runtimeInfo));
            this.combinedConfigProvider = Preconditions.CheckNotNull(combinedConfigProvider, nameof(combinedConfigProvider));
            this.id = new Lazy <string>(() => this.modules.Aggregate(string.Empty, (prev, module) => module.Name + prev));
            var deserializerTypesMap = new Dictionary <Type, IDictionary <string, Type> >
            {
                [typeof(IModule)] = new Dictionary <string, Type>
                {
                    ["docker"] = typeof(CombinedDockerConfig)
                }
            };

            this.deploymentSerde = new TypeSpecificSerDe <EdgeDeploymentDefinition <DockerConfig> >(deserializerTypesMap);
        }
示例#8
0
        public bool Equals(V1Deployment x, V1Deployment y)
        {
            if (ReferenceEquals(x, y))
            {
                return(true);
            }

            if (ReferenceEquals(x, null))
            {
                return(false);
            }

            if (ReferenceEquals(y, null))
            {
                return(false);
            }

            if (x.GetType() != y.GetType())
            {
                return(false);
            }

            if (x.Metadata.Name != y.Metadata.Name)
            {
                return(false);
            }

            // EdgeAgent deployments are equal when they have identical image sections
            if (x.Metadata.Name == KubeUtils.SanitizeK8sValue(CoreConstants.EdgeAgentModuleName))
            {
                return(V1DeploymentEx.ImageEquals(x, y));
            }

            // compares by creation string
            string xCreationString = GetCreationString(x);
            string yCreationString = GetCreationString(y);

            return(xCreationString == yCreationString);
        }
示例#9
0
        public async Task <Plan> PlanAsync(
            ModuleSet desired,
            ModuleSet current,
            IRuntimeInfo runtimeInfo,
            IImmutableDictionary <string, IModuleIdentity> moduleIdentities)
        {
            Events.LogDesired(desired);

            // We receive current ModuleSet from Agent based on what it reports (i.e. pods).
            // We need to rebuild the current ModuleSet based on deployments (i.e. CRD).
            Option <EdgeDeploymentDefinition> activeDeployment = await this.GetCurrentEdgeDeploymentDefinitionAsync();

            ModuleSet currentModules =
                activeDeployment.Match(
                    a => ModuleSet.Create(a.Spec.ToArray()),
                    () => ModuleSet.Empty);

            Events.LogCurrent(currentModules);

            // Check that module names sanitize and remain unique.
            var groupedModules = desired.Modules.ToLookup(pair => KubeUtils.SanitizeK8sValue(pair.Key));

            if (groupedModules.Any(c => c.Count() > 1))
            {
                string nameList = groupedModules
                                  .Where(c => c.Count() > 1)
                                  .SelectMany(g => g, (pairs, pair) => pair.Key)
                                  .Join(",");
                throw new InvalidIdentityException($"Deployment will cause a name collision in Kubernetes namespace, modules: [{nameList}]");
            }

            // TODO: improve this so it is generic for all potential module types.
            if (!desired.Modules.Values.All(p => p is IModule <DockerConfig>))
            {
                throw new InvalidModuleException($"Kubernetes deployment currently only handles type={typeof(DockerConfig).FullName}");
            }

            Diff moduleDifference = desired.Diff(currentModules);

            Plan plan;

            if (!moduleDifference.IsEmpty)
            {
                // The "Plan" here is very simple - if we have any change, publish all desired modules to a EdgeDeployment CRD.
                var crdCommand  = new EdgeDeploymentCommand(this.resourceName, this.deviceSelector, this.deviceNamespace, this.client, desired.Modules.Values, activeDeployment, runtimeInfo, this.configProvider, this.moduleOwner);
                var planCommand = await this.commandFactory.WrapAsync(crdCommand);

                var planList = new List <ICommand>
                {
                    planCommand
                };
                Events.PlanCreated(planList);
                plan = new Plan(planList);
            }
            else
            {
                plan = Plan.Empty;
            }

            return(plan);
        }
示例#10
0
        protected override void Load(ContainerBuilder builder)
        {
            // IKubernetesClient
            builder.Register(
                c =>
            {
                if (this.enableServiceCallTracing)
                {
                    // enable tracing of k8s requests made by the client
                    var loggerFactory = c.Resolve <ILoggerFactory>();
                    ILogger logger    = loggerFactory.CreateLogger(typeof(Kubernetes));
                    ServiceClientTracing.IsEnabled = true;
                    ServiceClientTracing.AddTracingInterceptor(new DebugTracer(logger));
                }

                // load the k8s config from KUBECONFIG or $HOME/.kube/config or in-cluster if its available
                KubernetesClientConfiguration kubeConfig = Option.Maybe(Environment.GetEnvironmentVariable("KUBECONFIG"))
                                                           .Else(() => Option.Maybe(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".kube", "config")))
                                                           .Filter(File.Exists)
                                                           .Map(path => KubernetesClientConfiguration.BuildConfigFromConfigFile(path))
                                                           .GetOrElse(KubernetesClientConfiguration.InClusterConfig);

                return(new Kubernetes(kubeConfig));
            })
            .As <IKubernetes>()
            .SingleInstance();

            // IModuleClientProvider
            builder.Register(
                c => new ModuleClientProvider(
                    c.Resolve <ISdkModuleClientProvider>(),
                    this.upstreamProtocol,
                    this.proxy,
                    this.productInfo.OrDefault(),
                    this.closeOnIdleTimeout,
                    this.idleTimeout))
            .As <IModuleClientProvider>()
            .SingleInstance();

            // IModuleManager
            builder.Register(c => new ModuleManagementHttpClient(this.managementUri, this.apiVersion, Core.Constants.EdgeletClientApiVersion))
            .As <IModuleManager>()
            .As <IIdentityManager>()
            .SingleInstance();

            // IModuleIdentityLifecycleManager
            var identityBuilder = new ModuleIdentityProviderServiceBuilder(this.resourceName.Hostname, this.resourceName.DeviceId, this.edgeDeviceHostName);

            builder.Register(c => new KubernetesModuleIdentityLifecycleManager(c.Resolve <IIdentityManager>(), identityBuilder, this.workloadUri))
            .As <IModuleIdentityLifecycleManager>()
            .SingleInstance();

            // CombinedKubernetesConfigProvider
            builder.Register(
                c =>
            {
                bool enableKubernetesExtensions = this.experimentalFeatures.Enabled && this.experimentalFeatures.EnableExtensions;
                return(new CombinedKubernetesConfigProvider(this.dockerAuthConfig, this.workloadUri, this.managementUri, enableKubernetesExtensions));
            })
            .As <ICombinedConfigProvider <CombinedKubernetesConfig> >()
            .SingleInstance();

            // ICommandFactory
            builder.Register(
                c =>
            {
                var loggerFactory            = c.Resolve <ILoggerFactory>();
                var kubernetesCommandFactory = new KubernetesCommandFactory();
                ICommandFactory factory      = new LoggingCommandFactory(kubernetesCommandFactory, loggerFactory);
                return(Task.FromResult(factory));
            })
            .As <Task <ICommandFactory> >()
            .SingleInstance();

            // IPlanner
            builder.Register(
                async c =>
            {
                var configProvider             = c.Resolve <ICombinedConfigProvider <CombinedKubernetesConfig> >();
                ICommandFactory commandFactory = await c.Resolve <Task <ICommandFactory> >();
                IPlanner planner = new KubernetesPlanner(this.deviceNamespace, this.resourceName, c.Resolve <IKubernetes>(), commandFactory, configProvider);
                return(planner);
            })
            .As <Task <IPlanner> >()
            .SingleInstance();

            // KubernetesRuntimeInfoProvider
            builder.Register(c => new KubernetesRuntimeInfoProvider(this.deviceNamespace, c.Resolve <IKubernetes>(), c.Resolve <IModuleManager>()))
            .As <IRuntimeInfoProvider>()
            .As <IRuntimeInfoSource>()
            .SingleInstance();

            // KubernetesDeploymentProvider
            builder.Register(
                c => new KubernetesDeploymentMapper(
                    this.deviceNamespace,
                    this.edgeDeviceHostName,
                    this.proxyImage,
                    this.proxyConfigPath,
                    this.proxyConfigVolumeName,
                    this.proxyConfigMapName,
                    this.proxyTrustBundlePath,
                    this.proxyTrustBundleVolumeName,
                    this.proxyTrustBundleConfigMapName,
                    this.persistentVolumeName,
                    this.storageClassName,
                    this.apiVersion,
                    this.workloadUri,
                    this.managementUri))
            .As <IKubernetesDeploymentMapper>();

            // KubernetesServiceMapper
            builder.Register(c => new KubernetesServiceMapper(this.defaultMapServiceType))
            .As <IKubernetesServiceMapper>();

            // KubernetesPvcMapper
            builder.Register(c => new KubernetesPvcMapper(this.persistentVolumeName, this.storageClassName, this.persistentVolumeClaimSizeMb))
            .As <IKubernetesPvcMapper>();

            // KubernetesServiceAccountProvider
            builder.Register(c => new KubernetesServiceAccountMapper())
            .As <IKubernetesServiceAccountMapper>();

            // EdgeDeploymentController
            builder.Register(
                c =>
            {
                var deploymentSelector = $"{Constants.K8sEdgeDeviceLabel}={KubeUtils.SanitizeK8sValue(this.resourceName.DeviceId)},{Constants.K8sEdgeHubNameLabel}={KubeUtils.SanitizeK8sValue(this.resourceName.Hostname)}";
                IEdgeDeploymentController watchOperator = new EdgeDeploymentController(
                    this.resourceName,
                    deploymentSelector,
                    this.deviceNamespace,
                    c.Resolve <IKubernetes>(),
                    c.Resolve <IModuleIdentityLifecycleManager>(),
                    c.Resolve <IKubernetesServiceMapper>(),
                    c.Resolve <IKubernetesDeploymentMapper>(),
                    c.Resolve <IKubernetesPvcMapper>(),
                    c.Resolve <IKubernetesServiceAccountMapper>());

                return(watchOperator);
            })
            .As <IEdgeDeploymentController>()
            .SingleInstance();

            // IEdgeDeploymentOperator
            builder.Register(
                c =>
            {
                IEdgeDeploymentOperator watchOperator = new EdgeDeploymentOperator(
                    this.resourceName,
                    this.deviceNamespace,
                    c.Resolve <IKubernetes>(),
                    c.Resolve <IEdgeDeploymentController>());

                return(watchOperator);
            })
            .As <IEdgeDeploymentOperator>()
            .SingleInstance();

            // IKubernetesEnvironmentOperator
            builder.Register(
                c =>
            {
                IKubernetesEnvironmentOperator watchOperator = new KubernetesEnvironmentOperator(
                    this.deviceNamespace,
                    c.Resolve <IRuntimeInfoSource>(),
                    c.Resolve <IKubernetes>());

                return(watchOperator);
            })
            .As <IKubernetesEnvironmentOperator>()
            .SingleInstance();

            // Task<IEnvironmentProvider>
            builder.Register(
                async c =>
            {
                var moduleStateStore     = c.Resolve <IEntityStore <string, ModuleState> >();
                var restartPolicyManager = c.Resolve <IRestartPolicyManager>();
                IRuntimeInfoProvider runtimeInfoProvider       = c.Resolve <IRuntimeInfoProvider>();
                IEnvironmentProvider dockerEnvironmentProvider = await DockerEnvironmentProvider.CreateAsync(runtimeInfoProvider, moduleStateStore, restartPolicyManager);
                return(dockerEnvironmentProvider);
            })
            .As <Task <IEnvironmentProvider> >()
            .SingleInstance();
        }
示例#11
0
 public KubernetesModule(
     string iotHubHostname,
     string deviceId,
     string edgeDeviceHostName,
     string proxyImage,
     Option <string> proxyImagePullSecretName,
     string proxyConfigPath,
     string proxyConfigVolumeName,
     string proxyConfigMapName,
     string proxyTrustBundlePath,
     string proxyTrustBundleVolumeName,
     string proxyTrustBundleConfigMapName,
     string apiVersion,
     string deviceNamespace,
     Uri managementUri,
     Uri workloadUri,
     IEnumerable <global::Docker.DotNet.Models.AuthConfig> dockerAuthConfig,
     Option <UpstreamProtocol> upstreamProtocol,
     Option <string> productInfo,
     PortMapServiceType defaultMapServiceType,
     bool enableServiceCallTracing,
     string persistentVolumeName,
     string storageClassName,
     Option <uint> persistentVolumeClaimSizeMb,
     Option <IWebProxy> proxy,
     bool closeOnIdleTimeout,
     TimeSpan idleTimeout,
     KubernetesExperimentalFeatures experimentalFeatures,
     KubernetesModuleOwner moduleOwner,
     bool runAsNonRoot)
 {
     this.resourceName                  = new ResourceName(iotHubHostname, deviceId);
     this.edgeDeviceHostName            = Preconditions.CheckNonWhiteSpace(edgeDeviceHostName, nameof(edgeDeviceHostName));
     this.proxyImage                    = Preconditions.CheckNonWhiteSpace(proxyImage, nameof(proxyImage));
     this.proxyImagePullSecretName      = proxyImagePullSecretName;
     this.proxyConfigPath               = Preconditions.CheckNonWhiteSpace(proxyConfigPath, nameof(proxyConfigPath));
     this.proxyConfigVolumeName         = Preconditions.CheckNonWhiteSpace(proxyConfigVolumeName, nameof(proxyConfigVolumeName));
     this.proxyConfigMapName            = Preconditions.CheckNonWhiteSpace(proxyConfigMapName, nameof(proxyConfigMapName));
     this.proxyTrustBundlePath          = Preconditions.CheckNonWhiteSpace(proxyTrustBundlePath, nameof(proxyTrustBundlePath));
     this.proxyTrustBundleVolumeName    = Preconditions.CheckNonWhiteSpace(proxyTrustBundleVolumeName, nameof(proxyTrustBundleVolumeName));
     this.proxyTrustBundleConfigMapName = Preconditions.CheckNonWhiteSpace(proxyTrustBundleConfigMapName, nameof(proxyTrustBundleConfigMapName));
     this.apiVersion                    = Preconditions.CheckNonWhiteSpace(apiVersion, nameof(apiVersion));
     this.deviceSelector                = $"{Constants.K8sEdgeDeviceLabel}={KubeUtils.SanitizeK8sValue(this.resourceName.DeviceId)},{Constants.K8sEdgeHubNameLabel}={KubeUtils.SanitizeK8sValue(this.resourceName.Hostname)}";
     this.deviceNamespace               = Preconditions.CheckNonWhiteSpace(deviceNamespace, nameof(deviceNamespace));
     this.managementUri                 = Preconditions.CheckNotNull(managementUri, nameof(managementUri));
     this.workloadUri                   = Preconditions.CheckNotNull(workloadUri, nameof(workloadUri));
     this.dockerAuthConfig              = Preconditions.CheckNotNull(dockerAuthConfig, nameof(dockerAuthConfig));
     this.upstreamProtocol              = Preconditions.CheckNotNull(upstreamProtocol, nameof(upstreamProtocol));
     this.productInfo                   = productInfo;
     this.defaultMapServiceType         = defaultMapServiceType;
     this.enableServiceCallTracing      = enableServiceCallTracing;
     this.persistentVolumeName          = persistentVolumeName;
     this.storageClassName              = storageClassName;
     this.persistentVolumeClaimSizeMb   = persistentVolumeClaimSizeMb;
     this.proxy = proxy;
     this.closeOnIdleTimeout   = closeOnIdleTimeout;
     this.idleTimeout          = idleTimeout;
     this.experimentalFeatures = experimentalFeatures;
     this.moduleOwner          = moduleOwner;
     this.runAsNonRoot         = runAsNonRoot;
 }
示例#12
0
 public void SanitizeK8sValueFailTest(string raw) => Assert.Throws <InvalidKubernetesNameException>(() => KubeUtils.SanitizeK8sValue(raw));
示例#13
0
 public void SanitizeK8sValueTest(string expected, string raw) => Assert.Equal(expected, KubeUtils.SanitizeK8sValue(raw));
示例#14
0
 private string DeploymentName(string moduleId) => KubeUtils.SanitizeK8sValue(moduleId);
        public async Task ManageFileShareSecretAsync(V1Secret secret)
        {
            byte[] accountKeyData;
            byte[] accountNameData;

            if (!secret.Data.TryGetValue(AccountKey, out accountKeyData))
            {
                Console.WriteLine($"Secret {secret.Metadata.Name} doesn't have [{AccountKey}] Data");
                return;
            }
            if (!secret.Data.TryGetValue(AccountName, out accountNameData))
            {
                Console.WriteLine($"Secret {secret.Metadata.Name} doesn't have [{AccountName}] Data");
                return;
            }

            var pvLabels = new Dictionary <string, string>
            {
                [Constants.LabelSelectorKey] = Constants.LabelSelectorValue
            };
            var mountOptions = new List <string>
            {
                "dir_mode=0777",
                "file_mode=0777",
                "uid=1000",
                "gid=1000",
                "mfsymlinks",
                "nobrl"
            };
            V1PersistentVolumeList currentPvs = await k8sClient.ListPersistentVolumeAsync(labelSelector : Constants.LabelSelector);

            var existingPvSet = new Set <V1PersistentVolume>(currentPvs.Items
                                                             .Where(pv => pv.Spec?.AzureFile?.SecretName == secret.Metadata.Name)
                                                             .ToDictionary(pv => pv.Metadata.Name));
            var desiredPvs = new ConcurrentDictionary <string, V1PersistentVolume>();

            string accountKey       = Encoding.UTF8.GetString(accountKeyData);
            string accountName      = Encoding.UTF8.GetString(accountNameData);
            string connectionString = $"DefaultEndpointsProtocol=https;AccountName={accountName};AccountKey={accountKey};EndpointSuffix=core.windows.net";

            // Open a FileShare client with secret.
            var serviceClient = new ShareServiceClient(connectionString);
            var shares        = serviceClient.GetSharesAsync(ShareTraits.Metadata, ShareStates.None);

            await foreach (var share in shares)
            {
                // Get all file shares from client that match a trait
                if ((share.Properties?.Metadata != null) &&
                    (share.Properties.Metadata.TryGetValue(Constants.LabelSelectorKey, out string labelValue)) &&
                    (labelValue == Constants.LabelSelectorValue))
                {
                    // Create a PV from secret and ShareItem
                    Console.WriteLine($"ShareItem {share.Name} found!");
                    string name        = KubeUtils.SanitizeK8sValue($"{accountName}-{share.Name}");
                    var    metadata    = new V1ObjectMeta(name: name, labels: pvLabels);
                    var    accessModes = new List <string> {
                        AccessMode
                    };
                    var azurefile = new V1AzureFilePersistentVolumeSource(secret.Metadata.Name, share.Name, readOnlyProperty: false, secret.Metadata.NamespaceProperty);
                    var capacity  = new Dictionary <string, ResourceQuantity> {
                        ["storage"] = new ResourceQuantity($"{share.Properties.QuotaInGB}Gi")
                    };
                    var spec = new V1PersistentVolumeSpec(
                        accessModes: accessModes,
                        azureFile: azurefile,
                        capacity: capacity,
                        storageClassName: StorageClassName,
                        mountOptions: mountOptions);
                    var pv = new V1PersistentVolume(metadata: metadata, spec: spec);
                    if (!desiredPvs.TryAdd(name, pv))
                    {
                        Console.WriteLine($"Duplicate share name {name}");
                    }
                }
            }

            var desiredPvSet = new Set <V1PersistentVolume>(desiredPvs);
            var diff         = desiredPvSet.Diff(existingPvSet, PvComparer);

            await this.ManagePvs(diff);
        }