public void CreateServiceExposedPortsOnlyCreatesExposedPortService() { var module = CreateKubernetesModule(CreatePodParameters.Create(exposedPorts: ExposedPorts)); var mapper = new KubernetesServiceMapper(PortMapServiceType.LoadBalancer); Option <V1Service> result = mapper.CreateService(CreateIdentity, module, DefaultLabels); Assert.True(result.HasValue); var service = result.OrDefault(); V1ServicePort port80 = service.Spec.Ports.Single(p => p.Port == 80); Assert.Equal("exposedport-80-tcp", port80.Name); Assert.Equal("TCP", port80.Protocol); V1ServicePort port5000 = service.Spec.Ports.Single(p => p.Port == 5000); Assert.Equal("exposedport-5000-udp", port5000.Name); Assert.Equal("UDP", port5000.Protocol); }
public void ServiceAnnotationsAreLabels() { var dockerLabels = new Dictionary <string, string> { ["Complicated Value that doesn't fit in k8s label name"] = "Complicated Value that doesn't fit in k8s label value", ["Label2"] = "Value2" }; var module = CreateKubernetesModule(CreatePodParameters.Create(exposedPorts: ExposedPorts, hostConfig: HostPorts, labels: dockerLabels)); var mapper = new KubernetesServiceMapper(PortMapServiceType.LoadBalancer); Option <V1Service> result = mapper.CreateService(CreateIdentity, module, DefaultLabels); Assert.True(result.HasValue); var service = result.OrDefault(); Assert.Equal("Complicated Value that doesn't fit in k8s label value", service.Metadata.Annotations["ComplicatedValuethatdoesntfitink8slabelname"]); Assert.Equal("Value2", service.Metadata.Annotations["Label2"]); }
public void AppliesNodeSelectorFromCreateOptionsToPodSpec() { var identity = new ModuleIdentity("hostname", "gatewayhost", "deviceid", "Module1", Mock.Of <ICredentials>()); var docker = new DockerModule("module1", "v1", ModuleStatus.Running, RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVarsDict); IDictionary <string, string> nodeSelector = new Dictionary <string, string> { ["disktype"] = "ssd" }; var config = new KubernetesConfig("image", CreatePodParameters.Create(nodeSelector: nodeSelector), Option.None <AuthConfig>()); var module = new KubernetesModule(docker, config); var mapper = new KubernetesDeploymentMapper("namespace", "edgehub", "proxy", "configPath", "configVolumeName", "configMapName", "trustBundlePAth", "trustBundleVolumeName", "trustBundleConfigMapName", string.Empty, string.Empty, "apiVersion", new Uri("http://workload"), new Uri("http://management")); var labels = new Dictionary <string, string>(); var deployment = mapper.CreateDeployment(identity, module, labels); Assert.Equal(nodeSelector, deployment.Spec.Template.Spec.NodeSelector, new DictionaryComparer <string, string>()); }
public void ConstructorThrowsOnInvalidParams() { KubernetesConfig config = new KubernetesConfig("image", CreatePodParameters.Create(), Option.None <AuthConfig>()); IModule m1 = new DockerModule("module1", "v1", ModuleStatus.Running, RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); KubernetesModule km1 = new KubernetesModule(m1, config, EdgeletModuleOwner); KubernetesModule[] modules = { km1 }; EdgeDeploymentDefinition edgeDefinition = new EdgeDeploymentDefinition("v1", "EdgeDeployment", new V1ObjectMeta(name: ResourceName), new List <KubernetesModule>(), null); Assert.Throws <ArgumentException>(() => new EdgeDeploymentCommand(null, ResourceName, DefaultClient, modules, Option.Maybe(edgeDefinition), Runtime, ConfigProvider, EdgeletModuleOwner)); Assert.Throws <ArgumentNullException>(() => new EdgeDeploymentCommand(Namespace, null, DefaultClient, modules, Option.Maybe(edgeDefinition), Runtime, ConfigProvider, EdgeletModuleOwner)); Assert.Throws <ArgumentNullException>(() => new EdgeDeploymentCommand(Namespace, ResourceName, null, modules, Option.Maybe(edgeDefinition), Runtime, ConfigProvider, EdgeletModuleOwner)); Assert.Throws <ArgumentNullException>(() => new EdgeDeploymentCommand(Namespace, ResourceName, DefaultClient, null, Option.Maybe(edgeDefinition), Runtime, ConfigProvider, EdgeletModuleOwner)); Assert.Throws <ArgumentNullException>(() => new EdgeDeploymentCommand(Namespace, ResourceName, DefaultClient, modules, Option.Maybe(edgeDefinition), null, ConfigProvider, EdgeletModuleOwner)); Assert.Throws <ArgumentNullException>(() => new EdgeDeploymentCommand(Namespace, ResourceName, DefaultClient, modules, Option.Maybe(edgeDefinition), Runtime, null, EdgeletModuleOwner)); Assert.Throws <ArgumentNullException>(() => new EdgeDeploymentCommand(Namespace, ResourceName, DefaultClient, modules, Option.Maybe(edgeDefinition), Runtime, ConfigProvider, null)); }
public void AppliesNodeSelectorFromCreateOptionsToPodSpec() { var identity = new ModuleIdentity("hostname", "gatewayhost", "deviceid", "Module1", Mock.Of <ICredentials>()); var docker = new DockerModule("module1", "v1", ModuleStatus.Running, RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVarsDict); IDictionary <string, string> nodeSelector = new Dictionary <string, string> { ["disktype"] = "ssd" }; var config = new KubernetesConfig("image", CreatePodParameters.Create(nodeSelector: nodeSelector), Option.None <AuthConfig>()); var module = new KubernetesModule(docker, config, EdgeletModuleOwner); var labels = new Dictionary <string, string>(); var mapper = CreateMapper(); var deployment = mapper.CreateDeployment(identity, module, labels); Assert.Equal(nodeSelector, deployment.Spec.Template.Spec.NodeSelector, new DictionaryComparer <string, string>()); }
public void SimpleDeploymentStoppedHasZeroReplicas() { var identity = new ModuleIdentity("hostname", "gatewayhost", "deviceid", "Module1", Mock.Of <ICredentials>()); var config = new KubernetesConfig("image", CreatePodParameters.Create(), Option.None <AuthConfig>()); var docker = new DockerModule("module1", "v1", ModuleStatus.Stopped, RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, Constants.DefaultPriority, DefaultConfigurationInfo, EnvVarsDict); var module = new KubernetesModule(docker, config, EdgeletModuleOwner); var labels = new Dictionary <string, string>(); var mapper = CreateMapper(); var deployment = mapper.CreateDeployment(identity, module, labels); Assert.NotNull(deployment); Assert.Equal(1, deployment.Metadata.OwnerReferences.Count); Assert.Equal(V1Deployment.KubeKind, deployment.Metadata.OwnerReferences[0].Kind); Assert.Equal(EdgeletModuleOwner.Name, deployment.Metadata.OwnerReferences[0].Name); Assert.Equal(0, deployment.Spec.Replicas); }
public void ApplyPodSecurityContextFromCreateOptionsWhenProvided() { var identity = new ModuleIdentity("hostname", "gatewayhost", "deviceid", "Module1", Mock.Of <ICredentials>()); var securityContext = new V1PodSecurityContext { RunAsNonRoot = true, RunAsUser = 20001 }; var config = new KubernetesConfig("image", CreatePodParameters.Create(securityContext: securityContext), Option.Some(new AuthConfig("user-registry1"))); var module = new KubernetesModule("module1", "v1", "docker", ModuleStatus.Running, RestartPolicy.Always, DefaultConfigurationInfo, EnvVarsDict, config, ImagePullPolicy.OnCreate, EdgeletModuleOwner); var labels = new Dictionary <string, string>(); var mapper = CreateMapper(); var deployment = mapper.CreateDeployment(identity, module, labels); Assert.Equal(1, deployment.Spec.Template.Spec.ImagePullSecrets.Count); Assert.Equal(true, deployment.Spec.Template.Spec.SecurityContext.RunAsNonRoot); Assert.Equal(20001, deployment.Spec.Template.Spec.SecurityContext.RunAsUser); }
public void UnknownProtocolDoesNotCreateService() { // Add unknown protocol var exposedPorts = new Dictionary <string, EmptyStruct> { { "123/XXX", default(EmptyStruct) } }; var createOptions = CreatePodParameters.Create(exposedPorts: exposedPorts); var config = new KubernetesConfig("image", createOptions, Option.None <AuthConfig>()); var moduleId = new ModuleIdentity("hostname", "gatewayhost", "deviceid", "moduleid", Mock.Of <ICredentials>()); var docker = new DockerModule("module1", "v1", ModuleStatus.Running, RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, Constants.DefaultPriority, DefaultConfigurationInfo, EnvVars); var module = new KubernetesModule(docker, config, EdgeletModuleOwner); var moduleLabels = new Dictionary <string, string>(); var mapper = new KubernetesServiceMapper(PortMapServiceType.ClusterIP); var service = mapper.CreateService(moduleId, module, moduleLabels); Assert.False(service.HasValue); }
public async void KubernetesPlannerPlanExistsWhenNoChanges() { IModule m1 = new DockerModule("module1", "v1", ModuleStatus.Running, global::Microsoft.Azure.Devices.Edge.Agent.Core.RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); IModule m2 = new DockerModule("module2", "v1", ModuleStatus.Running, global::Microsoft.Azure.Devices.Edge.Agent.Core.RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); KubernetesConfig kc1 = new KubernetesConfig("image1", CreatePodParameters.Create(), Option.None <AuthConfig>()); KubernetesConfig kc2 = new KubernetesConfig("image2", CreatePodParameters.Create(), Option.None <AuthConfig>()); var edgeDefinition = new EdgeDeploymentDefinition("v1", "EdgeDeployment", new V1ObjectMeta(name: ResourceName), new List <KubernetesModule>() { new KubernetesModule(m1, kc1, EdgeletModuleOwner), new KubernetesModule(m2, kc2, EdgeletModuleOwner) }, null); bool getCrdCalled = false; using (var server = new KubernetesApiServer( resp: string.Empty, shouldNext: async httpContext => { string pathStr = httpContext.Request.Path.Value; string method = httpContext.Request.Method; if (string.Equals(method, "GET", StringComparison.OrdinalIgnoreCase)) { if (pathStr.Contains($"namespaces/{Namespace}/{Constants.EdgeDeployment.Plural}/{ResourceName}")) { getCrdCalled = true; await httpContext.Response.Body.WriteAsync(JsonConvert.SerializeObject(edgeDefinition, EdgeDeploymentSerialization.SerializerSettings).ToBody()); } } return(false); })) { ModuleSet desired = ModuleSet.Create(m1, m2); ModuleSet current = ModuleSet.Create(m1, m2); var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri }); var planner = new KubernetesPlanner(Namespace, ResourceName, client, DefaultCommandFactory, ConfigProvider, EdgeletModuleOwner); var plan = await planner.PlanAsync(desired, current, RuntimeInfo, ImmutableDictionary <string, IModuleIdentity> .Empty); Assert.True(getCrdCalled); Assert.Single(plan.Commands); Assert.True(plan.Commands.First() is EdgeDeploymentCommand); } }
public void EdgeAgentEnvSettingsHaveLotsOfStuff() { var identity = new ModuleIdentity("hostname", "gatewayhost", "deviceid", "$edgeAgent", Mock.Of <ICredentials>()); var config = new KubernetesConfig("image", CreatePodParameters.Create(), Option.Some(new AuthConfig("user-registry1"))); var module = new KubernetesModule("edgeAgent", "v1", "docker", ModuleStatus.Running, RestartPolicy.Always, DefaultConfigurationInfo, EnvVarsDict, config, ImagePullPolicy.OnCreate, EdgeletModuleOwner); var labels = new Dictionary <string, string>(); var features = new Dictionary <string, bool> { ["feature1"] = true, ["feature2"] = false }; var mapper = CreateMapper(runAsNonRoot: true, persistentVolumeName: "pvname", storageClassName: "scname", proxyImagePullSecretName: "secret name", experimentalFeatures: features); var deployment = mapper.CreateDeployment(identity, module, labels); var container = deployment.Spec.Template.Spec.Containers.Single(c => c.Name == "edgeagent"); Assert.Equal(Constants.KubernetesMode, container.Env.Single(e => e.Name == Constants.ModeKey).Value); var managementUri = container.Env.Single(e => e.Name == Constants.EdgeletManagementUriVariableName); Assert.Equal("http://management/", container.Env.Single(e => e.Name == Constants.EdgeletManagementUriVariableName).Value); Assert.Equal("azure-iot-edge", container.Env.Single(e => e.Name == Constants.NetworkIdKey).Value); Assert.Equal("proxy", container.Env.Single(e => e.Name == KubernetesConstants.ProxyImageEnvKey).Value); Assert.Equal("secret name", container.Env.Single(e => e.Name == KubernetesConstants.ProxyImagePullSecretNameEnvKey).Value); Assert.Equal("configPath", container.Env.Single(e => e.Name == KubernetesConstants.ProxyConfigPathEnvKey).Value); Assert.Equal("configVolumeName", container.Env.Single(e => e.Name == KubernetesConstants.ProxyConfigVolumeEnvKey).Value); Assert.Equal("configMapName", container.Env.Single(e => e.Name == KubernetesConstants.ProxyConfigMapNameEnvKey).Value); Assert.Equal("trustBundlePath", container.Env.Single(e => e.Name == KubernetesConstants.ProxyTrustBundlePathEnvKey).Value); Assert.Equal("trustBundleVolumeName", container.Env.Single(e => e.Name == KubernetesConstants.ProxyTrustBundleVolumeEnvKey).Value); Assert.Equal("trustBundleConfigMapName", container.Env.Single(e => e.Name == KubernetesConstants.ProxyTrustBundleConfigMapEnvKey).Value); Assert.Equal("namespace", container.Env.Single(e => e.Name == KubernetesConstants.K8sNamespaceKey).Value); Assert.Equal("True", container.Env.Single(e => e.Name == KubernetesConstants.RunAsNonRootKey).Value); Assert.Equal("v1", container.Env.Single(e => e.Name == KubernetesConstants.EdgeK8sObjectOwnerApiVersionKey).Value); Assert.Equal("Deployment", container.Env.Single(e => e.Name == KubernetesConstants.EdgeK8sObjectOwnerKindKey).Value); Assert.Equal("iotedged", container.Env.Single(e => e.Name == KubernetesConstants.EdgeK8sObjectOwnerNameKey).Value); Assert.Equal("123", container.Env.Single(e => e.Name == KubernetesConstants.EdgeK8sObjectOwnerUidKey).Value); Assert.Equal("ClusterIP", container.Env.Single(e => e.Name == KubernetesConstants.PortMappingServiceType).Value); Assert.Equal("False", container.Env.Single(e => e.Name == KubernetesConstants.EnableK8sServiceCallTracingName).Value); Assert.Equal("pvname", container.Env.Single(e => e.Name == KubernetesConstants.PersistentVolumeNameKey).Value); Assert.Equal("scname", container.Env.Single(e => e.Name == KubernetesConstants.StorageClassNameKey).Value); Assert.Equal("100", container.Env.Single(e => e.Name == KubernetesConstants.PersistentVolumeClaimDefaultSizeInMbKey).Value); Assert.Equal("True", container.Env.Single(e => e.Name == "feature1").Value); Assert.Equal("False", container.Env.Single(e => e.Name == "feature2").Value); }
public void ExposingPortsCreatesAServiceWithPorts() { var exposedPorts = new Dictionary <string, EmptyStruct> { ["10/TCP"] = default(EmptyStruct) }; var createOptions = CreatePodParameters.Create(exposedPorts: exposedPorts); var config = new KubernetesConfig("image", createOptions, Option.None <AuthConfig>()); var docker = new DockerModule("module1", "v1", ModuleStatus.Running, RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, Constants.DefaultPriority, DefaultConfigurationInfo, EnvVars); var module = new KubernetesModule(docker, config, EdgeletModuleOwner); var moduleLabels = new Dictionary <string, string>(); var mapper = new KubernetesServiceMapper(PortMapServiceType.ClusterIP); var moduleId = new ModuleIdentity("hostname", "gatewayhost", "deviceid", "moduleid", Mock.Of <ICredentials>()); var service = mapper.CreateService(moduleId, module, moduleLabels).OrDefault(); Assert.Equal(1, service.Spec.Ports.Count); AssertPort(new V1ServicePort(10, "exposedport-10-tcp", null, "TCP"), service.Spec.Ports.First()); Assert.Equal("ClusterIP", service.Spec.Type); }
public void ConstructorThrowsOnInvalidParams() { KubernetesConfig config = new KubernetesConfig("image", CreatePodParameters.Create(), Option.None <AuthConfig>()); IModule m1 = new DockerModule("module1", "v1", ModuleStatus.Running, RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); KubernetesModule km1 = new KubernetesModule(m1, config); KubernetesModule[] modules = { km1 }; ModuleSet currentModules = new ModuleSet(new Dictionary <string, IModule> { ["module1"] = m1 }); Assert.Throws <ArgumentException>(() => new EdgeDeploymentCommand(null, ResourceName, DefaultClient, modules, currentModules, Runtime, ConfigProvider)); Assert.Throws <ArgumentNullException>(() => new EdgeDeploymentCommand(Namespace, null, DefaultClient, modules, currentModules, Runtime, ConfigProvider)); Assert.Throws <ArgumentNullException>(() => new EdgeDeploymentCommand(Namespace, ResourceName, null, modules, currentModules, Runtime, ConfigProvider)); Assert.Throws <ArgumentNullException>(() => new EdgeDeploymentCommand(Namespace, ResourceName, DefaultClient, null, currentModules, Runtime, ConfigProvider)); Assert.Throws <ArgumentNullException>(() => new EdgeDeploymentCommand(Namespace, ResourceName, DefaultClient, modules, null, Runtime, ConfigProvider)); Assert.Throws <ArgumentNullException>(() => new EdgeDeploymentCommand(Namespace, ResourceName, DefaultClient, modules, currentModules, null, ConfigProvider)); Assert.Throws <ArgumentNullException>(() => new EdgeDeploymentCommand(Namespace, ResourceName, DefaultClient, modules, currentModules, Runtime, null)); }
public void CreateServiceHostPortsCreatesHostportService() { var module = CreateKubernetesModule(CreatePodParameters.Create(hostConfig: HostPorts)); var mapper = new KubernetesServiceMapper(PortMapServiceType.LoadBalancer); Option <V1Service> result = mapper.CreateService(CreateIdentity, module, DefaultLabels); Assert.True(result.HasValue); var service = result.OrDefault(); V1ServicePort port80 = service.Spec.Ports.Single(p => p.Port == 8080); Assert.Equal("hostport-80-tcp", port80.Name); Assert.Equal("TCP", port80.Protocol); Assert.Equal(80, (int)port80.TargetPort); V1ServicePort port5000 = service.Spec.Ports.Single(p => p.Port == 5050); Assert.Equal("hostport-5000-udp", port5000.Name); Assert.Equal("UDP", port5000.Protocol); Assert.Equal(5000, (int)port5000.TargetPort); }
public void LeaveVolumesIntactWhenNothingProvidedInCreateOptions() { var identity = new ModuleIdentity("hostname", "gatewayhost", "deviceid", "Module1", Mock.Of <ICredentials>()); var docker = new DockerModule("module1", "v1", ModuleStatus.Running, RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVarsDict); var config = new KubernetesConfig("image", CreatePodParameters.Create(), Option.None <AuthConfig>()); var module = new KubernetesModule(docker, config, EdgeletModuleOwner); var labels = new Dictionary <string, string>(); var mapper = CreateMapper(); var deployment = mapper.CreateDeployment(identity, module, labels); // 2 volumes for proxy by default Assert.Equal(2, deployment.Spec.Template.Spec.Volumes.Count); var moduleContainer = deployment.Spec.Template.Spec.Containers.Single(container => container.Name == "module1"); Assert.Equal(0, moduleContainer.VolumeMounts.Count); var proxyContainer = deployment.Spec.Template.Spec.Containers.Single(container => container.Name == "proxy"); Assert.Equal(2, proxyContainer.VolumeMounts.Count); }
public void LeaveVolumesIntactWhenNothingProvidedInCreateOptions() { var identity = new ModuleIdentity("hostname", "gatewayhost", "deviceid", "Module1", Mock.Of <ICredentials>()); var docker = new DockerModule("module1", "v1", ModuleStatus.Running, RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVarsDict); var config = new KubernetesConfig("image", CreatePodParameters.Create(), Option.None <AuthConfig>()); var module = new KubernetesModule(docker, config); var mapper = new KubernetesDeploymentMapper("namespace", "edgehub", "proxy", "configPath", "configVolumeName", "configMapName", "trustBundlePath", "trustBundleVolumeName", "trustBindleConfigMapName", string.Empty, string.Empty, "apiVersion", new Uri("http://workload"), new Uri("http://management")); var labels = new Dictionary <string, string>(); var deployment = mapper.CreateDeployment(identity, module, labels); // 2 volumes for proxy by default Assert.Equal(2, deployment.Spec.Template.Spec.Volumes.Count); var moduleContainer = deployment.Spec.Template.Spec.Containers.Single(container => container.Name == "module1"); Assert.Equal(0, moduleContainer.VolumeMounts.Count); var proxyContainer = deployment.Spec.Template.Spec.Containers.Single(container => container.Name == "proxy"); Assert.Equal(2, proxyContainer.VolumeMounts.Count); }
public void EntrypointOptionsContainerCommands() { var entrypoint = new List <string> { "command", "argument-a" }; var identity = new ModuleIdentity("hostname", "gatewayhost", "deviceid", "Module1", Mock.Of <ICredentials>()); var config = new KubernetesConfig("image", CreatePodParameters.Create(entrypoint: entrypoint), Option.Some(new AuthConfig("user-registry1"))); var module = new KubernetesModule("module1", "v1", "docker", ModuleStatus.Running, RestartPolicy.Always, DefaultConfigurationInfo, EnvVarsDict, config, ImagePullPolicy.OnCreate, EdgeletModuleOwner); var labels = new Dictionary <string, string>(); var mapper = CreateMapper(); var deployment = mapper.CreateDeployment(identity, module, labels); var container = deployment.Spec.Template.Spec.Containers.Single(c => c.Name == "module1"); Assert.NotNull(container.Command); Assert.Equal(2, container.Command.Count); Assert.Equal("command", container.Command[0]); Assert.Equal("argument-a", container.Command[1]); }
public void EmptyDirMappingForVolume() { var identity = new ModuleIdentity("hostname", "gatewayhost", "deviceid", "ModuleId", Mock.Of <ICredentials>()); var labels = new Dictionary <string, string>(); var hostConfig = VolumeMountHostConfig; var config = new KubernetesConfig("image", CreatePodParameters.Create(labels: labels, hostConfig: hostConfig), Option.None <AuthConfig>()); var docker = new DockerModule("module1", "v1", ModuleStatus.Running, RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVarsDict); var module = new KubernetesModule(docker, config, EdgeletModuleOwner); var mapper = CreateMapper(storageClassName: null); var deployment = mapper.CreateDeployment(identity, module, labels); var pod = deployment.Spec.Template; Assert.True(pod != null); var podVolume = pod.Spec.Volumes.Single(v => v.Name == "a-volume"); Assert.NotNull(podVolume.EmptyDir); var podVolumeMount = pod.Spec.Containers.Single(p => p.Name != "proxy").VolumeMounts.Single(vm => vm.Name == "a-volume"); Assert.Equal("/tmp/volume", podVolumeMount.MountPath); Assert.True(podVolumeMount.ReadOnlyProperty); }
private KubernetesModule CreateKubernetesModuleWithHostConfig(string moduleName, string persistentVolumeName) { var hostConfig = new HostConfig { Mounts = new List <Mount> { new Mount { Type = "volume", ReadOnly = true, Source = persistentVolumeName, Target = "/tmp/volume" } } }; var createOptions = CreatePodParameters.Create(hostConfig: hostConfig); KubernetesConfig config = new KubernetesConfig("image", createOptions, Option.None <AuthConfig>()); IModule m1 = new DockerModule(moduleName, "v1", ModuleStatus.Running, Core.RestartPolicy.Always, new DockerConfig("test-image:1"), ImagePullPolicy.OnCreate, Core.Constants.DefaultStartupOrder, null, null); return(new KubernetesModule(m1, config, new KubernetesModuleOwner("v1", "Deployment", "iotedged", "123"))); }
public void AddsVolumesFromCreateOptionsToContainerSpecEvenIfTheyOverrideExistingOnes() { var identity = new ModuleIdentity("hostname", "gatewayhost", "deviceid", "Module1", Mock.Of <ICredentials>()); var docker = new DockerModule("module1", "v1", ModuleStatus.Running, RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVarsDict); var volumes = new[] { new KubernetesModuleVolumeSpec( new V1Volume("homeblah", configMap: new V1ConfigMapVolumeSource(name: "additional-config-map")), new[] { new V1VolumeMount(name: "homeblah", mountPath: "/home/blah") }) }; var hostConfig = new HostConfig { Binds = new List <string> { "/home/blah:/home/blah2:ro" } }; var config = new KubernetesConfig("image", CreatePodParameters.Create(volumes: volumes, hostConfig: hostConfig), Option.None <AuthConfig>()); var module = new KubernetesModule(docker, config, EdgeletModuleOwner); var labels = new Dictionary <string, string>(); var mapper = CreateMapper(); var deployment = mapper.CreateDeployment(identity, module, labels); // Validate module volume mounts var moduleContainer = deployment.Spec.Template.Spec.Containers.Single(container => container.Name == "module1"); Assert.Equal(2, moduleContainer.VolumeMounts.Count(vm => vm.Name.Equals("homeblah"))); // Validate proxy volume mounts var proxyContainer = deployment.Spec.Template.Spec.Containers.Single(p => p.Name == "proxy"); Assert.Equal(2, proxyContainer.VolumeMounts.Count); Assert.Contains(proxyContainer.VolumeMounts, vm => vm.Name.Equals("configVolumeName")); Assert.Contains(proxyContainer.VolumeMounts, vm => vm.Name.Equals("trustBundleVolumeName")); // Validate pod volumes Assert.Equal(4, deployment.Spec.Template.Spec.Volumes.Count); Assert.Equal(2, deployment.Spec.Template.Spec.Volumes.Count(v => v.Name.Equals("homeblah"))); Assert.Contains(deployment.Spec.Template.Spec.Volumes, v => v.Name.Equals("configVolumeName")); Assert.Contains(deployment.Spec.Template.Spec.Volumes, v => v.Name.Equals("trustBundleVolumeName")); }
public void VolumeNameMappingForVolume() { var config = new KubernetesConfig("image", CreatePodParameters.Create(hostConfig: VolumeMountHostConfig), Option.None <AuthConfig>()); var docker = new DockerModule("module1", "v1", ModuleStatus.Running, RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, Constants.DefaultPriority, DefaultConfigurationInfo, EnvVarsDict); var module = new KubernetesModule(docker, config, EdgeletModuleOwner); var mapper = new KubernetesPvcMapper("pvname", "storage-class", 37); var resourceQuantity = new ResourceQuantity("37Mi"); var pvcs = mapper.CreatePersistentVolumeClaims(module, DefaultLabels); Assert.True(pvcs.HasValue); var pvcList = pvcs.OrDefault(); Assert.True(pvcList.Any()); Assert.Equal(2, pvcList.Count); var aVolumeClaim = pvcList[0]; Assert.Equal("pvname", aVolumeClaim.Metadata.Name); Assert.True(aVolumeClaim.Metadata.Labels.SequenceEqual(DefaultLabels)); Assert.Equal("ReadOnlyMany", aVolumeClaim.Spec.AccessModes[0]); Assert.Equal("storage-class", aVolumeClaim.Spec.StorageClassName); Assert.Equal("pvname", aVolumeClaim.Spec.VolumeName); Assert.Equal(resourceQuantity, aVolumeClaim.Spec.Resources.Requests["storage"]); Assert.Equal(1, aVolumeClaim.Metadata.OwnerReferences.Count); Assert.Equal(V1Deployment.KubeKind, aVolumeClaim.Metadata.OwnerReferences[0].Kind); Assert.Equal(EdgeletModuleOwner.Name, aVolumeClaim.Metadata.OwnerReferences[0].Name); var bVolumeClaim = pvcList[1]; Assert.Equal("pvname", bVolumeClaim.Metadata.Name); Assert.True(bVolumeClaim.Metadata.Labels.SequenceEqual(DefaultLabels)); Assert.Equal("ReadWriteMany", bVolumeClaim.Spec.AccessModes[0]); Assert.Equal("storage-class", bVolumeClaim.Spec.StorageClassName); Assert.Equal("pvname", bVolumeClaim.Spec.VolumeName); Assert.Equal(resourceQuantity, bVolumeClaim.Spec.Resources.Requests["storage"]); Assert.Equal(1, bVolumeClaim.Metadata.OwnerReferences.Count); Assert.Equal(V1Deployment.KubeKind, bVolumeClaim.Metadata.OwnerReferences[0].Kind); Assert.Equal(EdgeletModuleOwner.Name, bVolumeClaim.Metadata.OwnerReferences[0].Name); }
public async void Execute_UpdatesImagePullSecret_WhenExistsWithSameName() { string secretName = "username-docker.io"; var secretData = new Dictionary <string, byte[]> { [KubernetesConstants.K8sPullSecretData] = Encoding.UTF8.GetBytes("Invalid Secret Data") }; var secretMeta = new V1ObjectMeta(name: secretName, namespaceProperty: Namespace); var existingSecret = new V1Secret("v1", secretData, type: KubernetesConstants.K8sPullSecretType, kind: "Secret", metadata: secretMeta); IModule dockerModule = new DockerModule("module1", "v1", ModuleStatus.Running, Core.RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, Core.Constants.DefaultPriority, DefaultConfigurationInfo, EnvVars); var dockerConfigProvider = new Mock <ICombinedConfigProvider <CombinedDockerConfig> >(); dockerConfigProvider.Setup(cp => cp.GetCombinedConfig(dockerModule, Runtime)) .Returns(() => new CombinedDockerConfig("test-image:1", Config1.CreateOptions, Option.None <string>(), Option.Maybe(DockerAuth))); var configProvider = new Mock <ICombinedConfigProvider <CombinedKubernetesConfig> >(); configProvider.Setup(cp => cp.GetCombinedConfig(dockerModule, Runtime)) .Returns(() => new CombinedKubernetesConfig("test-image:1", CreatePodParameters.Create(image: "test-image:1"), Option.Maybe(ImagePullSecret))); var client = new Mock <IKubernetes>(); client.SetupListSecrets().ReturnsAsync(() => CreateResponse(new V1SecretList { Items = new List <V1Secret> { existingSecret } })); V1Secret updatedSecret = null; client.SetupUpdateSecret() .Callback( (V1Secret body, string name, string ns, string dryRun, string fieldManager, string pretty, Dictionary <string, List <string> > customHeaders, CancellationToken token) => { updatedSecret = body; }) .ReturnsAsync(() => CreateResponse(new V1Secret())); client.SetupCreateEdgeDeploymentDefinition().ReturnsAsync(() => CreateResponse(HttpStatusCode.Created, new object())); var cmd = new EdgeDeploymentCommand(ResourceName, Selector, Namespace, client.Object, new[] { dockerModule }, Option.None <EdgeDeploymentDefinition>(), Runtime, configProvider.Object, EdgeletModuleOwner); await cmd.ExecuteAsync(CancellationToken.None); Assert.NotNull(updatedSecret); client.VerifyAll(); }
public void EmptyDirMappingForVolume() { var identity = new ModuleIdentity("hostname", "gatewayhost", "deviceid", "ModuleId", Mock.Of <ICredentials>()); var labels = new Dictionary <string, string>(); var hostConfig = VolumeMountHostConfig; var config = new KubernetesConfig("image", CreatePodParameters.Create(labels: labels, hostConfig: hostConfig), Option.None <AuthConfig>()); var docker = new DockerModule("module1", "v1", ModuleStatus.Running, RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVarsDict); var module = new KubernetesModule(docker, config); var mapper = new KubernetesDeploymentMapper("namespace", "edgehub", "proxy", "configPath", "configVolumeName", "configMapName", "trustBundlePAth", "trustBundleVolumeName", "trustBundleConfigMapName", string.Empty, null, "apiVersion", new Uri("http://workload"), new Uri("http://management")); var deployment = mapper.CreateDeployment(identity, module, labels); var pod = deployment.Spec.Template; Assert.True(pod != null); var podVolume = pod.Spec.Volumes.Single(v => v.Name == "a-volume"); Assert.NotNull(podVolume.EmptyDir); var podVolumeMount = pod.Spec.Containers.Single(p => p.Name != "proxy").VolumeMounts.Single(vm => vm.Name == "a-volume"); Assert.Equal("/tmp/volume", podVolumeMount.MountPath); Assert.True(podVolumeMount.ReadOnlyProperty); }
public void SimpleServiceCreationHappyPath() { var exposedPorts = new Dictionary <string, EmptyStruct> { ["10/TCP"] = default(EmptyStruct) }; var createOptions = CreatePodParameters.Create(exposedPorts: exposedPorts); var config = new KubernetesConfig("image", createOptions, Option.None <AuthConfig>()); var docker = new DockerModule("module1", "v1", ModuleStatus.Running, RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, Constants.DefaultPriority, DefaultConfigurationInfo, EnvVars); var module = new KubernetesModule(docker, config, EdgeletModuleOwner); var moduleLabels = new Dictionary <string, string>(); var mapper = new KubernetesServiceMapper(PortMapServiceType.ClusterIP); var moduleId = new ModuleIdentity("hostname", "gatewayhost", "deviceid", "moduleid", Mock.Of <ICredentials>()); var service = mapper.CreateService(moduleId, module, moduleLabels).OrDefault(); Assert.NotNull(service); Assert.Equal(1, service.Metadata.OwnerReferences.Count); Assert.Equal(V1Deployment.KubeKind, service.Metadata.OwnerReferences[0].Kind); Assert.Equal(EdgeletModuleOwner.Name, service.Metadata.OwnerReferences[0].Name); Assert.Equal(1, service.Spec.Ports.Count); Assert.Equal(0, service.Spec.Selector.Count); }
public async void Execute_CreatesNewImagePullSecret_WhenEmpty() { IModule dockerModule = new DockerModule("module1", "v1", ModuleStatus.Running, Core.RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, Core.Constants.DefaultPriority, DefaultConfigurationInfo, EnvVars); var dockerConfigProvider = new Mock <ICombinedConfigProvider <CombinedDockerConfig> >(); dockerConfigProvider.Setup(cp => cp.GetCombinedConfig(dockerModule, Runtime)) .Returns(() => new CombinedDockerConfig("test-image:1", Config1.CreateOptions, Option.None <string>(), Option.Maybe(DockerAuth))); var configProvider = new Mock <ICombinedConfigProvider <CombinedKubernetesConfig> >(); configProvider.Setup(cp => cp.GetCombinedConfig(dockerModule, Runtime)) .Returns(() => new CombinedKubernetesConfig("test-image:1", CreatePodParameters.Create(image: "test-image:1"), Option.Maybe(ImagePullSecret))); var client = new Mock <IKubernetes>(); client.SetupListSecrets() .ReturnsAsync( () => new HttpOperationResponse <V1SecretList> { Response = new HttpResponseMessage(), Body = new V1SecretList { Items = new List <V1Secret>() } }); V1Secret createdSecret = null; client.SetupCreateSecret() .Callback( (V1Secret body, string ns, string dryRun, string fieldManager, string pretty, Dictionary <string, List <string> > customHeaders, CancellationToken token) => { createdSecret = body; }) .ReturnsAsync(() => CreateResponse(HttpStatusCode.Created, new V1Secret())); client.SetupCreateEdgeDeploymentDefinition().ReturnsAsync(() => CreateResponse(HttpStatusCode.Created, new object())); var cmd = new EdgeDeploymentCommand(ResourceName, Selector, Namespace, client.Object, new[] { dockerModule }, Option.None <EdgeDeploymentDefinition>(), Runtime, configProvider.Object, EdgeletModuleOwner); await cmd.ExecuteAsync(CancellationToken.None); Assert.NotNull(createdSecret); client.VerifyAll(); }
public async void Execute_PreservesCaseOfEnvVars_WhenModuleDeployed() { IDictionary <string, EnvVal> moduleEnvVars = new Dictionary <string, EnvVal> { { "ACamelCaseEnvVar", new EnvVal("ACamelCaseEnvVarValue") } }; IModule dockerModule = new DockerModule("module1", "v1", ModuleStatus.Running, Core.RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, Core.Constants.DefaultPriority, DefaultConfigurationInfo, moduleEnvVars); var dockerConfigProvider = new Mock <ICombinedConfigProvider <CombinedDockerConfig> >(); dockerConfigProvider.Setup(cp => cp.GetCombinedConfig(dockerModule, Runtime)) .Returns(() => new CombinedDockerConfig("test-image:1", Config1.CreateOptions, Option.None <string>(), Option.Maybe(DockerAuth))); var configProvider = new Mock <ICombinedConfigProvider <CombinedKubernetesConfig> >(); configProvider.Setup(cp => cp.GetCombinedConfig(dockerModule, Runtime)) .Returns(() => new CombinedKubernetesConfig("test-image:1", CreatePodParameters.Create(image: "test-image:1"), Option.Maybe(ImagePullSecret))); var client = new Mock <IKubernetes>(); client.SetupListSecrets().ReturnsAsync(() => CreateResponse(new V1SecretList { Items = new List <V1Secret>() })); client.SetupCreateSecret().ReturnsAsync(() => CreateResponse(HttpStatusCode.Created, new V1Secret())); EdgeDeploymentDefinition edgeDeploymentDefinition = null; client.SetupCreateEdgeDeploymentDefinition() .Callback( (object body, string group, string version, string ns, string plural, string name, Dictionary <string, List <string> > headers, CancellationToken token) => { edgeDeploymentDefinition = ((JObject)body).ToObject <EdgeDeploymentDefinition>(); }) .ReturnsAsync(() => CreateResponse <object>(edgeDeploymentDefinition)); var cmd = new EdgeDeploymentCommand(ResourceName, Selector, Namespace, client.Object, new[] { dockerModule }, Option.None <EdgeDeploymentDefinition>(), Runtime, configProvider.Object, EdgeletModuleOwner); await cmd.ExecuteAsync(CancellationToken.None); Assert.Equal("module1", edgeDeploymentDefinition.Spec[0].Name); Assert.Equal("test-image:1", edgeDeploymentDefinition.Spec[0].Config.Image); Assert.True(edgeDeploymentDefinition.Spec[0].Env.Contains(new KeyValuePair <string, EnvVal>("ACamelCaseEnvVar", new EnvVal("ACamelCaseEnvVarValue")))); }
public void AppliesVolumesFromCreateOptionsToContainerSpec() { var identity = new ModuleIdentity("hostname", "deviceid", "Module1", Mock.Of <ICredentials>()); var docker = new DockerModule("module1", "v1", ModuleStatus.Running, Core.RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, Constants.DefaultStartupOrder, DefaultConfigurationInfo, EnvVarsDict); var volumes = new[] { new KubernetesModuleVolumeSpec( new V1Volume("additional-volume", configMap: new V1ConfigMapVolumeSource(name: "additional-config-map")), new[] { new V1VolumeMount(name: "additional-volume", mountPath: "/etc") }) }; var config = new KubernetesConfig("image", CreatePodParameters.Create(volumes: volumes), Option.None <AuthConfig>()); var module = new KubernetesModule(docker, config, EdgeletModuleOwner); var labels = new Dictionary <string, string>(); var mapper = CreateMapper(); var deployment = mapper.CreateDeployment(identity, module, labels); // Validate module volume mounts var moduleContainer = deployment.Spec.Template.Spec.Containers.Single(container => container.Name == "module1"); Assert.Equal(1, moduleContainer.VolumeMounts.Count); Assert.Contains(moduleContainer.VolumeMounts, vm => vm.Name.Equals("additional-volume")); // Validate proxy volume mounts var proxyContainer = deployment.Spec.Template.Spec.Containers.Single(p => p.Name == "proxy"); Assert.Equal(2, proxyContainer.VolumeMounts.Count); Assert.Contains(proxyContainer.VolumeMounts, vm => vm.Name.Equals("configVolumeName")); Assert.Contains(proxyContainer.VolumeMounts, vm => vm.Name.Equals("trustBundleVolumeName")); // Validate pod volumes Assert.Equal(3, deployment.Spec.Template.Spec.Volumes.Count); Assert.Contains(deployment.Spec.Template.Spec.Volumes, v => v.Name.Equals("additional-volume")); Assert.Contains(deployment.Spec.Template.Spec.Volumes, v => v.Name.Equals("configVolumeName")); Assert.Contains(deployment.Spec.Template.Spec.Volumes, v => v.Name.Equals("trustBundleVolumeName")); }
public async void CrdCommandExecuteWithAuthCreateNewObjects() { IModule dockerModule = new DockerModule("module1", "v1", ModuleStatus.Running, RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); var dockerConfigProvider = new Mock <ICombinedConfigProvider <CombinedDockerConfig> >(); dockerConfigProvider.Setup(cp => cp.GetCombinedConfig(dockerModule, Runtime)) .Returns(() => new CombinedDockerConfig("test-image:1", Config1.CreateOptions, Option.Maybe(DockerAuth))); var configProvider = new Mock <ICombinedConfigProvider <CombinedKubernetesConfig> >(); configProvider.Setup(cp => cp.GetCombinedConfig(dockerModule, Runtime)) .Returns(() => new CombinedKubernetesConfig("test-image:1", CreatePodParameters.Create(image: "test-image:1"), Option.Maybe(ImagePullSecret))); bool getSecretCalled = false; bool postSecretCalled = false; bool getCrdCalled = false; bool postCrdCalled = false; using (var server = new KubernetesApiServer( resp: string.Empty, shouldNext: httpContext => { string pathStr = httpContext.Request.Path.Value; string method = httpContext.Request.Method; if (string.Equals(method, "GET", StringComparison.OrdinalIgnoreCase)) { httpContext.Response.StatusCode = 404; if (pathStr.Contains($"api/v1/namespaces/{Namespace}/secrets")) { getSecretCalled = true; } else if (pathStr.Contains($"namespaces/{Namespace}/{Constants.EdgeDeployment.Plural}")) { getCrdCalled = true; } } else if (string.Equals(method, "POST", StringComparison.OrdinalIgnoreCase)) { httpContext.Response.StatusCode = 201; httpContext.Response.Body = httpContext.Request.Body; if (pathStr.Contains($"api/v1/namespaces/{Namespace}/secrets")) { postSecretCalled = true; } else if (pathStr.Contains($"namespaces/{Namespace}/{Constants.EdgeDeployment.Plural}")) { postCrdCalled = true; } } return(Task.FromResult(false)); })) { var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri }); var cmd = new EdgeDeploymentCommand(Namespace, ResourceName, client, new[] { dockerModule }, Runtime, configProvider.Object); await cmd.ExecuteAsync(CancellationToken.None); Assert.True(getSecretCalled, nameof(getSecretCalled)); Assert.True(postSecretCalled, nameof(postSecretCalled)); Assert.True(getCrdCalled, nameof(getCrdCalled)); Assert.True(postCrdCalled, nameof(postCrdCalled)); } }
public async void CrdCommandExecuteWithAuthReplaceObjects() { string secretName = "username-docker.io"; var secretData = new Dictionary <string, byte[]> { [Constants.K8sPullSecretData] = Encoding.UTF8.GetBytes("Invalid Secret Data") }; var secretMeta = new V1ObjectMeta(name: secretName, namespaceProperty: Namespace); IModule dockerModule = new DockerModule("module1", "v1", ModuleStatus.Running, RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); var dockerConfigProvider = new Mock <ICombinedConfigProvider <CombinedDockerConfig> >(); dockerConfigProvider.Setup(cp => cp.GetCombinedConfig(dockerModule, Runtime)) .Returns(() => new CombinedDockerConfig("test-image:1", Config1.CreateOptions, Option.Maybe(DockerAuth))); var configProvider = new Mock <ICombinedConfigProvider <CombinedKubernetesConfig> >(); configProvider.Setup(cp => cp.GetCombinedConfig(dockerModule, Runtime)) .Returns(() => new CombinedKubernetesConfig("test-image:1", CreatePodParameters.Create(image: "test-image:1"), Option.Maybe(ImagePullSecret))); var existingSecret = new V1Secret("v1", secretData, type: Constants.K8sPullSecretType, kind: "Secret", metadata: secretMeta); var existingDeployment = new EdgeDeploymentDefinition(Constants.EdgeDeployment.ApiVersion, Constants.EdgeDeployment.Kind, new V1ObjectMeta(name: ResourceName), new List <KubernetesModule>()); bool getSecretCalled = false; bool putSecretCalled = false; bool getCrdCalled = false; bool putCrdCalled = false; using (var server = new KubernetesApiServer( resp: string.Empty, shouldNext: async httpContext => { string pathStr = httpContext.Request.Path.Value; string method = httpContext.Request.Method; if (string.Equals(method, "GET", StringComparison.OrdinalIgnoreCase)) { if (pathStr.Contains($"api/v1/namespaces/{Namespace}/secrets/{secretName}")) { getSecretCalled = true; await httpContext.Response.Body.WriteAsync(JsonConvert.SerializeObject(existingSecret).ToBody()); } else if (pathStr.Contains($"namespaces/{Namespace}/{Constants.EdgeDeployment.Plural}/{ResourceName}")) { getCrdCalled = true; await httpContext.Response.Body.WriteAsync(JsonConvert.SerializeObject(existingDeployment).ToBody()); } } else if (string.Equals(method, "PUT", StringComparison.OrdinalIgnoreCase)) { httpContext.Response.Body = httpContext.Request.Body; if (pathStr.Contains($"api/v1/namespaces/{Namespace}/secrets/{secretName}")) { putSecretCalled = true; } else if (pathStr.Contains($"namespaces/{Namespace}/{Constants.EdgeDeployment.Plural}/{ResourceName}")) { putCrdCalled = true; } } return(false); })) { var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri }); var cmd = new EdgeDeploymentCommand(Namespace, ResourceName, client, new[] { dockerModule }, Runtime, configProvider.Object); await cmd.ExecuteAsync(CancellationToken.None); Assert.True(getSecretCalled, nameof(getSecretCalled)); Assert.True(putSecretCalled, nameof(putSecretCalled)); Assert.True(getCrdCalled, nameof(getCrdCalled)); Assert.True(putCrdCalled, nameof(putCrdCalled)); } }
public async void CrdCommandExecuteTwoModulesWithSamePullSecret() { string secretName = "username-docker.io"; IModule dockerModule1 = new DockerModule("module1", "v1", ModuleStatus.Running, RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); IModule dockerModule2 = new DockerModule("module2", "v1", ModuleStatus.Running, RestartPolicy.Always, Config2, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); var dockerConfigProvider = new Mock <ICombinedConfigProvider <CombinedDockerConfig> >(); dockerConfigProvider.Setup(cp => cp.GetCombinedConfig(It.IsAny <DockerModule>(), Runtime)) .Returns(() => new CombinedDockerConfig("test-image:1", Config1.CreateOptions, Option.Maybe(DockerAuth))); var configProvider = new Mock <ICombinedConfigProvider <CombinedKubernetesConfig> >(); configProvider.Setup(cp => cp.GetCombinedConfig(It.IsAny <DockerModule>(), Runtime)) .Returns(() => new CombinedKubernetesConfig("test-image:1", CreatePodParameters.Create(image: "test-image:1"), Option.Maybe(ImagePullSecret))); bool getSecretCalled = false; bool putSecretCalled = false; int postSecretCalled = 0; bool getCrdCalled = false; bool putCrdCalled = false; int postCrdCalled = 0; Stream secretBody = Stream.Null; using (var server = new KubernetesApiServer( resp: string.Empty, shouldNext: httpContext => { string pathStr = httpContext.Request.Path.Value; string method = httpContext.Request.Method; if (string.Equals(method, "GET", StringComparison.OrdinalIgnoreCase)) { if (pathStr.Contains($"api/v1/namespaces/{Namespace}/secrets/{secretName}")) { if (secretBody == Stream.Null) { // 1st pass, secret should not exist getSecretCalled = true; httpContext.Response.StatusCode = 404; } else { // 2nd pass, use secret from creation. httpContext.Response.Body = secretBody; } } else if (pathStr.Contains($"namespaces/{Namespace}/{Constants.EdgeDeployment.Plural}/{ResourceName}")) { getCrdCalled = true; httpContext.Response.StatusCode = 404; } } else if (string.Equals(method, "POST", StringComparison.OrdinalIgnoreCase)) { httpContext.Response.StatusCode = 201; httpContext.Response.Body = httpContext.Request.Body; if (pathStr.Contains($"api/v1/namespaces/{Namespace}/secrets")) { postSecretCalled++; secretBody = httpContext.Request.Body; // save this for next query. } else if (pathStr.Contains($"namespaces/{Namespace}/{Constants.EdgeDeployment.Plural}")) { postCrdCalled++; } } else if (string.Equals(method, "PUT", StringComparison.OrdinalIgnoreCase)) { httpContext.Response.Body = httpContext.Request.Body; if (pathStr.Contains($"api/v1/namespaces/{Namespace}/secrets")) { putSecretCalled = true; } else if (pathStr.Contains($"namespaces/{Namespace}/{Constants.EdgeDeployment.Plural}")) { putCrdCalled = true; } } return(Task.FromResult(false)); })) { var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri }); var cmd = new EdgeDeploymentCommand(Namespace, ResourceName, client, new[] { dockerModule1, dockerModule2 }, Runtime, configProvider.Object); await cmd.ExecuteAsync(CancellationToken.None); Assert.True(getSecretCalled, nameof(getSecretCalled)); Assert.Equal(1, postSecretCalled); Assert.False(putSecretCalled, nameof(putSecretCalled)); Assert.True(getCrdCalled, nameof(getCrdCalled)); Assert.Equal(1, postCrdCalled); Assert.False(putCrdCalled, nameof(putCrdCalled)); } }
public void ValidatePodPropertyTranslation() { var identity = new ModuleIdentity("hostname", "gatewayhost", "deviceid", "Module1", Mock.Of <ICredentials>()); var labels = new Dictionary <string, string> { // Add a label { "demo", "test" } }; var hostConfig = new HostConfig { // Make container privileged Privileged = true, // Add a readonly mount Binds = new List <string> { "/home/blah:/home/blah2:ro" } }; var config = new KubernetesConfig("image", CreatePodParameters.Create(labels: labels, hostConfig: hostConfig), Option.None <AuthConfig>()); var docker = new DockerModule("module1", "v1", ModuleStatus.Running, RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVarsDict); var module = new KubernetesModule(docker, config, EdgeletModuleOwner); var moduleLabels = new Dictionary <string, string>(); var mapper = CreateMapper(); var deployment = mapper.CreateDeployment(identity, module, moduleLabels); var pod = deployment.Spec.Template; Assert.NotNull(pod); // Validate annotation Assert.True(pod.Metadata.Annotations.ContainsKey("demo")); // Two containers should exist - proxy and the module Assert.Equal(2, pod.Spec.Containers.Count); // There should only be one module container var moduleContainer = pod.Spec.Containers.Single(p => p.Name != "proxy"); // We made this container privileged Assert.True(moduleContainer.SecurityContext.Privileged); // Validate that there are 1 mounts for module container Assert.Equal(1, moduleContainer.VolumeMounts.Count); // Validate the custom mount that we added Assert.Contains(moduleContainer.VolumeMounts, vm => vm.Name.Equals("homeblah")); var mount = moduleContainer.VolumeMounts.Single(vm => vm.Name.Equals("homeblah")); // Lets make sure that it is read only Assert.True(mount.ReadOnlyProperty); // Validate proxy container var proxyContainer = pod.Spec.Containers.Single(p => p.Name == "proxy"); // Validate that there are 2 mounts for proxy container: config and trust-bundle Assert.Equal(2, proxyContainer.VolumeMounts.Count); Assert.Contains(proxyContainer.VolumeMounts, vm => vm.Name.Equals("configVolumeName")); Assert.Contains(proxyContainer.VolumeMounts, vm => vm.Name.Equals("trustBundleVolumeName")); // Validate pod volumes Assert.Equal(3, pod.Spec.Volumes.Count); Assert.Contains(pod.Spec.Volumes, v => v.Name.Equals("homeblah")); Assert.Contains(pod.Spec.Volumes, v => v.Name.Equals("configVolumeName")); Assert.Contains(pod.Spec.Volumes, v => v.Name.Equals("trustBundleVolumeName")); // Validate no image pull secrets for public images Assert.Null(pod.Spec.ImagePullSecrets); // Validate null pod security context by default Assert.Null(pod.Spec.SecurityContext); }