示例#1
0
        public void TestVolMount()
        {
            // Arrange
            var runtimeInfo = new Mock <IRuntimeInfo <DockerRuntimeConfig> >();

            runtimeInfo.SetupGet(ri => ri.Config).Returns(new DockerRuntimeConfig("1.24", string.Empty));

            var module = new Mock <IModule <DockerConfig> >();

            module.SetupGet(m => m.Config).Returns(new DockerConfig("nginx:latest"));
            module.SetupGet(m => m.Name).Returns(Constants.EdgeAgentModuleName);

            var unixUris = new Dictionary <string, string>
            {
                { Constants.EdgeletWorkloadUriVariableName, "unix:///path/to/workload.sock" },
                { Constants.EdgeletManagementUriVariableName, "unix:///path/to/mgmt.sock" }
            };

            var windowsUris = new Dictionary <string, string>
            {
                { Constants.EdgeletWorkloadUriVariableName, "unix:///C:/path/to/workload/sock" },
                { Constants.EdgeletManagementUriVariableName, "unix:///C:/path/to/mgmt/sock" }
            };

            IConfigurationRoot configRoot = new ConfigurationBuilder().AddInMemoryCollection(
                RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? windowsUris : unixUris
                ).Build();
            var configSource = Mock.Of <IConfigSource>(s => s.Configuration == configRoot);
            ICombinedConfigProvider <CombinedDockerConfig> provider = new CombinedEdgeletConfigProvider(new[] { new AuthConfig() }, configSource);

            // Act
            CombinedDockerConfig config = provider.GetCombinedConfig(module.Object, runtimeInfo.Object);

            // Assert
            Assert.NotNull(config.CreateOptions);
            Assert.NotNull(config.CreateOptions.HostConfig);
            Assert.NotNull(config.CreateOptions.HostConfig.Binds);
            Assert.Equal(2, config.CreateOptions.HostConfig.Binds.Count);
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                Assert.Equal("C:\\path\\to\\workload:C:\\path\\to\\workload", config.CreateOptions.HostConfig.Binds[0]);
                Assert.Equal("C:\\path\\to\\mgmt:C:\\path\\to\\mgmt", config.CreateOptions.HostConfig.Binds[1]);
            }
            else
            {
                Assert.Equal("/path/to/workload.sock:/path/to/workload.sock", config.CreateOptions.HostConfig.Binds[0]);
                Assert.Equal("/path/to/mgmt.sock:/path/to/mgmt.sock", config.CreateOptions.HostConfig.Binds[1]);
            }
        }
        public override CombinedDockerConfig GetCombinedConfig(IModule module, IRuntimeInfo runtimeInfo)
        {
            CombinedDockerConfig combinedConfig = base.GetCombinedConfig(module, runtimeInfo);

            CreateContainerParameters createOptions = CloneOrCreateParams(combinedConfig.CreateOptions);

            // before making any other modifications to createOptions, save edge agent's createOptions + env as
            // container labels so they're available as soon as it loads
            InjectEdgeAgentLabels(module, createOptions);

            // if the workload URI is a Unix domain socket then volume mount it into the container
            this.MountSockets(module, createOptions);
            this.InjectNetworkAliases(module, createOptions);

            return(new CombinedDockerConfig(combinedConfig.Image, createOptions, combinedConfig.Digest, combinedConfig.AuthConfig));
        }
示例#3
0
        public void ValidatePodPropertyTranslation()
        {
            var identity = new ModuleIdentity("hostname", "gatewayhost", "deviceid", "ModuleId", Mock.Of <ICredentials>());
            var config   = new CombinedDockerConfig("image", new global::Microsoft.Azure.Devices.Edge.Agent.Docker.Models.CreateContainerParameters(), Option.None <AuthConfig>());

            config.CreateOptions.Labels = new Dictionary <string, string>
            {
                // Add a label
                { "demo", "test" }
            };
            config.CreateOptions.HostConfig = new global::Microsoft.Azure.Devices.Edge.Agent.Docker.Models.HostConfig
            {
                // Make container privileged
                Privileged = true,
                // Add a readonly mount
                Binds = new List <string> {
                    "/home/blah:/home/blah2:ro"
                }
            };
            var docker = new DockerModule("module1", "v1", ModuleStatus.Running, Core.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", "trustBindleConfigMapName", "apiVersion", new Uri("http://workload"), new Uri("http://management"));
            var labels = new Dictionary <string, string>();

            var deployment = mapper.CreateDeployment(identity, module, labels);
            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 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 4 mounts
            Assert.Equal(3, 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);
        }
示例#4
0
        public void EmptyIsNotAllowedAsPodAnnotation()
        {
            var identity = new ModuleIdentity("hostname", "gatewayhost", "deviceid", "ModuleId", Mock.Of <ICredentials>());
            var config   = new CombinedDockerConfig("image", new global::Microsoft.Azure.Devices.Edge.Agent.Docker.Models.CreateContainerParameters(), Option.None <AuthConfig>());

            config.CreateOptions.Labels = new Dictionary <string, string>
            {
                // string.Empty is an invalid label name
                { string.Empty, "test" }
            };
            var docker = new DockerModule("module1", "v1", ModuleStatus.Running, Core.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", "trustBindleConfigMapName", "apiVersion", new Uri("http://workload"), new Uri("http://management"));
            var labels = new Dictionary <string, string>();

            Assert.Throws <InvalidKubernetesNameException>(() => mapper.CreateDeployment(identity, module, labels));
        }
        public void EmptyIsNotAllowedAsServiceAnnotation()
        {
            var config = new CombinedDockerConfig("image", new Docker.Models.CreateContainerParameters(), Option.None <AuthConfig>());

            config.CreateOptions.Labels = new Dictionary <string, string>
            {
                // string.Empty is an invalid label name
                { string.Empty, "test" }
            };
            var moduleId     = new ModuleIdentity("hub", "gateway", "deviceId", "moduleid", Mock.Of <ICredentials>());
            var docker       = new DockerModule(moduleId.ModuleId, "v1", ModuleStatus.Running, Core.RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars);
            var module       = new KubernetesModule(docker, config);
            var moduleLabels = new Dictionary <string, string>();
            var mapper       = new KubernetesServiceMapper(PortMapServiceType.ClusterIP);

            Assert.Throws <InvalidKubernetesNameException>(() => mapper.CreateService(moduleId, module, moduleLabels));
        }
示例#6
0
        public void TestAddNewRootKeyRegistryCredential()
        {
            var runtimeConfig = new DockerRuntimeConfig(
                "1.0",
                new Dictionary <string, RegistryCredentials>
            {
                ["r1"] = new RegistryCredentials("mcr.microsoft.com", "foo", "foo", "credential")
            });

            var runtimeInfo = new DockerRuntimeInfo("docker", runtimeConfig);

            var module = new Mock <IModule <DockerConfig> >();

            module.SetupGet(m => m.Config).Returns(new DockerConfig("mcr.microsoft.com/windows/nanoserver:1809"));
            module.SetupGet(m => m.Name).Returns(Constants.EdgeAgentModuleName);

            var unixUris = new Dictionary <string, string>
            {
                { Constants.EdgeletWorkloadUriVariableName, "unix:///path/to/workload.sock" },
                { Constants.EdgeletManagementUriVariableName, "unix:///path/to/mgmt.sock" }
            };

            var windowsUris = new Dictionary <string, string>
            {
                { Constants.EdgeletWorkloadUriVariableName, "unix:///C:/path/to/workload/sock" },
                { Constants.EdgeletManagementUriVariableName, "unix:///C:/path/to/mgmt/sock" }
            };

            IConfigurationRoot configRoot = new ConfigurationBuilder().AddInMemoryCollection(
                RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? windowsUris : unixUris).Build();
            var configSource = Mock.Of <IConfigSource>(s => s.Configuration == configRoot);
            var authConfig   = new AuthConfig {
                ServerAddress = "mcr.microsoft.com"
            };
            ICombinedConfigProvider <CombinedDockerConfig> provider = new CombinedEdgeletConfigProvider(new[] { authConfig }, configSource);

            var             systemInfoSample = new SystemInfo("linux", "x86", "1");
            var             moduleManager    = Mock.Of <IModuleManager>(m => m.GetSystemInfoAsync(CancellationToken.None) == Task.FromResult(systemInfoSample));
            ICommandFactory factory          = new EdgeletCommandFactory <CombinedDockerConfig>(moduleManager, configSource, provider);
            // Act
            CombinedDockerConfig config = provider.GetCombinedConfig(module.Object, runtimeInfo);

            // Assert
            Assert.Equal("credential", config.AuthConfig.OrDefault().RegistryToken);
        }
        public void UnknownProtocolDoesNotCreateService()
        {
            var config   = new CombinedDockerConfig("image", new Docker.Models.CreateContainerParameters(), Option.None <AuthConfig>());
            var moduleId = new ModuleIdentity("hostname", "gatewayhost", "deviceid", "moduleid", Mock.Of <ICredentials>());

            config.CreateOptions.ExposedPorts = new Dictionary <string, EmptyStruct>
            {
                // Add unknown protocol
                { "123/XXX", default(EmptyStruct) }
            };
            var docker       = new DockerModule("module1", "v1", ModuleStatus.Running, Core.RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars);
            var module       = new KubernetesModule(docker, config);
            var moduleLabels = new Dictionary <string, string>();
            var mapper       = new KubernetesServiceMapper(PortMapServiceType.ClusterIP);

            var service = mapper.CreateService(moduleId, module, moduleLabels);

            Assert.False(service.HasValue);
        }
示例#8
0
        public async Task ImageNotFoundTest()
        {
            const string Image = "non-existing-image:latest";
            const string Name  = "non-existing-image-name";

            try
            {
                using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(15)))
                {
                    await DockerHelper.Client.CleanupContainerAsync(Name, Image);

                    var config = new CombinedDockerConfig(Image, new CreateContainerParameters(), NoAuth);

                    ICommand pullCommand = new PullCommand(DockerHelper.Client, config);
                    await Assert.ThrowsAsync <ImageNotFoundException>(() => pullCommand.ExecuteAsync(cts.Token));
                }
            }
            finally
            {
                await DockerHelper.Client.CleanupContainerAsync(Name, Image);
            }
        }
示例#9
0
        public async Task PullValidImages(string testFullImage, string image, string tag)
        {
            // Arrange
            string testImage = string.Empty;
            string testTag   = string.Empty;
            var    auth      = new AuthConfig();
            var    client    = new Mock <IDockerClient>();
            var    images    = new Mock <IImageOperations>();

            images.Setup(
                i => i.CreateImageAsync(
                    It.IsAny <ImagesCreateParameters>(),
                    It.IsAny <AuthConfig>(),
                    It.IsAny <IProgress <JSONMessage> >(),
                    It.IsAny <CancellationToken>()))
            .Callback <ImagesCreateParameters, AuthConfig, IProgress <JSONMessage>, CancellationToken>(
                (icp, a, p, t) =>
            {
                testImage = icp.FromImage;
                testTag   = icp.Tag;
            })
            .Returns(TaskEx.Done);
            client.SetupGet(c => c.Images).Returns(images.Object);

            var config = new CombinedDockerConfig(testFullImage, new CreateContainerParameters(), Option.Some(auth));

            // Act
            var command = new PullCommand(client.Object, config);

            await command.ExecuteAsync(CancellationToken.None);

            // Assert
            client.VerifyAll();
            images.VerifyAll();

            Assert.Equal(image, testImage);
            Assert.Equal(tag, testTag);
        }
        public void ExposingPortsCreatesAServiceWithPorts()
        {
            var createOptions = new Docker.Models.CreateContainerParameters
            {
                // Add a port to be exposed
                ExposedPorts = new Dictionary <string, EmptyStruct>
                {
                    ["10/TCP"] = default(EmptyStruct)
                }
            };
            var config       = new CombinedDockerConfig("image", createOptions, Option.None <AuthConfig>());
            var docker       = new DockerModule("module1", "v1", ModuleStatus.Running, Core.RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars);
            var module       = new KubernetesModule(docker, config);
            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);
        }
示例#11
0
        public void InjectNetworkAliasHostNetworkTest()
        {
            // Arrange
            var runtimeInfo = new Mock <IRuntimeInfo <DockerRuntimeConfig> >();

            runtimeInfo.SetupGet(ri => ri.Config).Returns(new DockerRuntimeConfig("1.24", string.Empty));

            string hostNetworkCreateOptions = "{\"NetworkingConfig\":{\"EndpointsConfig\":{\"host\":{}}},\"HostConfig\":{\"NetworkMode\":\"host\"}}";
            var    module = new Mock <IModule <DockerConfig> >();

            module.SetupGet(m => m.Config).Returns(new DockerConfig("nginx:latest", hostNetworkCreateOptions));
            module.SetupGet(m => m.Name).Returns("mod1");

            IConfigurationRoot configRoot = new ConfigurationBuilder().AddInMemoryCollection(
                new Dictionary <string, string>
            {
                { CoreConstants.EdgeletWorkloadUriVariableName, "unix:///var/run/iotedgedworkload.sock" },
                { CoreConstants.EdgeletManagementUriVariableName, "unix:///var/run/iotedgedmgmt.sock" },
                { CoreConstants.NetworkIdKey, "testnetwork1" },
                { CoreConstants.EdgeDeviceHostNameKey, "edhk1" }
            }).Build();
            var configSource = Mock.Of <IConfigSource>(s => s.Configuration == configRoot);

            ICombinedConfigProvider <CombinedDockerConfig> provider = new CombinedKubernetesConfigProvider(new[] { new AuthConfig() }, configSource);

            // Act
            CombinedDockerConfig config = provider.GetCombinedConfig(module.Object, runtimeInfo.Object);

            // Assert
            Assert.NotNull(config.CreateOptions);
            Assert.NotNull(config.CreateOptions.NetworkingConfig);
            Assert.NotNull(config.CreateOptions.NetworkingConfig.EndpointsConfig);
            Assert.False(config.CreateOptions.NetworkingConfig.EndpointsConfig.ContainsKey("testnetwork1"));
            Assert.NotNull(config.CreateOptions.NetworkingConfig.EndpointsConfig["host"]);
            Assert.Null(config.CreateOptions.NetworkingConfig.EndpointsConfig["host"].Aliases);
            Assert.Equal("host", config.CreateOptions.HostConfig.NetworkMode);
        }
示例#12
0
 public PullCommand(IDockerClient client, CombinedDockerConfig combinedDockerConfig)
 {
     this.client = Preconditions.CheckNotNull(client, nameof(client));
     this.combinedDockerConfig = Preconditions.CheckNotNull(combinedDockerConfig, nameof(combinedDockerConfig));
 }
示例#13
0
        public void CompareModule()
        {
            var auth1 = new AuthConfig {
                Username = "******", Password = "******", ServerAddress = "test1-server.com"
            };
            var auth2 = new AuthConfig {
                Username = "******", Password = "******", ServerAddress = "test1-server.com"
            };
            var auth3 = new AuthConfig {
                Username = "******", Password = "******", ServerAddress = "test1-server.com"
            };
            var auth4 = new AuthConfig {
                Username = "******", Password = "******", ServerAddress = "test2-server.com"
            };
            Dictionary <string, EnvVal> goodEnv = new Dictionary <string, EnvVal>();
            Dictionary <string, EnvVal> newEnv  = new Dictionary <string, EnvVal> {
                ["a"] = new EnvVal("B")
            };
            IList <string> dockerEnv = new List <string> {
                "c=d"
            };
            CombinedDockerConfig goodCombinedDockerConfig = new CombinedDockerConfig("image:tag", new CreateContainerParameters(), Option.None <AuthConfig>());
            CombinedDockerConfig imageDifferent           = new CombinedDockerConfig("image:newtag", new CreateContainerParameters(), Option.None <AuthConfig>());
            CombinedDockerConfig auth1Config = new CombinedDockerConfig("image:tag", new CreateContainerParameters(), Option.Some(auth1));
            CombinedDockerConfig auth2Config = new CombinedDockerConfig("image:tag", new CreateContainerParameters(), Option.Some(auth2));
            CombinedDockerConfig auth3Config = new CombinedDockerConfig("image:tag", new CreateContainerParameters(), Option.Some(auth3));
            CombinedDockerConfig auth4Config = new CombinedDockerConfig("image:tag", new CreateContainerParameters(), Option.Some(auth4));
            CombinedDockerConfig createContainerConfigDifferent = new CombinedDockerConfig("image:tag", new CreateContainerParameters {
                Env = dockerEnv
            }, Option.None <AuthConfig>());

            ConfigurationInfo goodInfo = new ConfigurationInfo(string.Empty);

            var m1 = new CombinedDockerModule("name1", "v1", ModuleStatus.Running, RestartPolicy.Always, goodCombinedDockerConfig, goodInfo, goodEnv);
            var m2 = new CombinedDockerModule("name2", "v1", ModuleStatus.Running, RestartPolicy.Always, goodCombinedDockerConfig, goodInfo, goodEnv);

            var m3 = new CombinedDockerModule("name1", "v1", ModuleStatus.Running, RestartPolicy.Always, goodCombinedDockerConfig, goodInfo, goodEnv);
            var m4 = new CombinedDockerModule("name1", "v2", ModuleStatus.Running, RestartPolicy.Always, goodCombinedDockerConfig, goodInfo, goodEnv);

            var m5 = new CombinedDockerModule("name1", "v1", ModuleStatus.Running, RestartPolicy.Always, goodCombinedDockerConfig, goodInfo, goodEnv);
            var m6 = new CombinedDockerModule("name1", "v1", ModuleStatus.Stopped, RestartPolicy.Always, goodCombinedDockerConfig, goodInfo, goodEnv);

            var m7 = new CombinedDockerModule("name1", "v1", ModuleStatus.Running, RestartPolicy.Always, goodCombinedDockerConfig, goodInfo, goodEnv);
            var m8 = new CombinedDockerModule("name1", "v1", ModuleStatus.Running, RestartPolicy.Never, goodCombinedDockerConfig, goodInfo, goodEnv);

            var m9  = new CombinedDockerModule("name1", "v1", ModuleStatus.Running, RestartPolicy.Always, imageDifferent, goodInfo, goodEnv);
            var m10 = new CombinedDockerModule("name1", "v1", ModuleStatus.Running, RestartPolicy.Always, auth1Config, goodInfo, goodEnv);
            var m11 = new CombinedDockerModule("name1", "v1", ModuleStatus.Running, RestartPolicy.Always, auth2Config, goodInfo, goodEnv);
            var m12 = new CombinedDockerModule("name1", "v1", ModuleStatus.Running, RestartPolicy.Always, auth3Config, goodInfo, goodEnv);
            var m13 = new CombinedDockerModule("name1", "v1", ModuleStatus.Running, RestartPolicy.Always, auth4Config, goodInfo, goodEnv);
            var m14 = new CombinedDockerModule("name1", "v1", ModuleStatus.Running, RestartPolicy.Always, createContainerConfigDifferent, goodInfo, goodEnv);

            var m15 = new CombinedDockerModule("name1", "v1", ModuleStatus.Running, RestartPolicy.Always, goodCombinedDockerConfig, goodInfo, newEnv);

            Assert.NotEqual(m1, m2);
            Assert.NotEqual(m3, m4);
            Assert.NotEqual(m5, m6);
            Assert.NotEqual(m7, m8);
            Assert.NotEqual(m1, m9);
            Assert.NotEqual(m9, m1);
            Assert.NotEqual(m10, m9);
            Assert.NotEqual(m9, m10);
            Assert.NotEqual(m10, m11);
            Assert.NotEqual(m11, m10);
            Assert.NotEqual(m10, m12);
            Assert.NotEqual(m10, m13);
            Assert.NotEqual(m11, m14);
            Assert.NotEqual(m11, m15);

            Assert.True(m5.IsOnlyModuleStatusChanged(m6));

            Assert.False(m1.IsOnlyModuleStatusChanged(m2));
            Assert.False(m1.IsOnlyModuleStatusChanged(m9));
        }
        public async void CrdCommandExecuteWithAuthCreateNewObjects()
        {
            CombinedDockerConfig config = new CombinedDockerConfig("image", new Docker.Models.CreateContainerParameters(), Option.None <AuthConfig>());
            IModule m1  = new DockerModule("module1", "v1", ModuleStatus.Running, Core.RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars);
            var     km1 = new KubernetesModule((IModule <DockerConfig>)m1, config);

            KubernetesModule[] modules = { km1 };
            var token = default(CancellationToken);
            var auth  = new AuthConfig()
            {
                Username = "******", Password = "******", ServerAddress = "docker.io"
            };
            var configProvider = new Mock <ICombinedConfigProvider <CombinedDockerConfig> >();

            configProvider.Setup(cp => cp.GetCombinedConfig(km1, Runtime)).Returns(() => new CombinedDockerConfig("test-image:1", Config1.CreateOptions, Option.Maybe(auth)));
            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, modules, Runtime, configProvider.Object);
                await cmd.ExecuteAsync(token);

                Assert.True(getSecretCalled, nameof(getSecretCalled));
                Assert.True(postSecretCalled, nameof(postSecretCalled));
                Assert.True(getCrdCalled, nameof(getCrdCalled));
                Assert.True(postCrdCalled, nameof(postCrdCalled));
            }
        }
        public async void CrdCommandExecuteWithAuthReplaceObjects()
        {
            CombinedDockerConfig config = new CombinedDockerConfig("image", new Docker.Models.CreateContainerParameters(), Option.None <AuthConfig>());
            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 m1         = new DockerModule("module1", "v1", ModuleStatus.Running, Core.RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars);
            var     km1        = new KubernetesModule((IModule <DockerConfig>)m1, config);

            KubernetesModule[] modules = { km1 };
            var token = default(CancellationToken);
            var auth  = new AuthConfig()
            {
                Username = "******", Password = "******", ServerAddress = "docker.io"
            };
            var configProvider = new Mock <ICombinedConfigProvider <CombinedDockerConfig> >();

            configProvider.Setup(cp => cp.GetCombinedConfig(km1, Runtime)).Returns(() => new CombinedDockerConfig("test-image:1", Config1.CreateOptions, Option.Maybe(auth)));
            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(), token);
                    }
                    else if (pathStr.Contains($"namespaces/{Namespace}/{Constants.EdgeDeployment.Plural}/{ResourceName}"))
                    {
                        getCrdCalled = true;
                        await httpContext.Response.Body.WriteAsync(JsonConvert.SerializeObject(existingDeployment).ToBody(), token);
                    }
                }
                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, modules, Runtime, configProvider.Object);
                await cmd.ExecuteAsync(token);

                Assert.True(getSecretCalled, nameof(getSecretCalled));
                Assert.True(putSecretCalled, nameof(putSecretCalled));
                Assert.True(getCrdCalled, nameof(getCrdCalled));
                Assert.True(putCrdCalled, nameof(putCrdCalled));
            }
        }
        public async void CrdCommandExecuteDeploysModulesWithEnvVars()
        {
            CombinedDockerConfig         config        = new CombinedDockerConfig("image", new Docker.Models.CreateContainerParameters(), Option.None <AuthConfig>());
            IDictionary <string, EnvVal> moduleEnvVars = new Dictionary <string, EnvVal>()
            {
                { "ACamelCaseEnvVar", new EnvVal("ACamelCaseEnvVarValue") }
            };

            IModule m1  = new DockerModule("module1", "v1", ModuleStatus.Running, Core.RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, moduleEnvVars);
            var     km1 = new KubernetesModule((IModule <DockerConfig>)m1, config);

            KubernetesModule[] modules = { km1 };
            var token = default(CancellationToken);
            var auth  = new AuthConfig()
            {
                Username = "******", Password = "******", ServerAddress = "docker.io"
            };
            var configProvider = new Mock <ICombinedConfigProvider <CombinedDockerConfig> >();

            configProvider.Setup(cp => cp.GetCombinedConfig(km1, Runtime)).Returns(() => new CombinedDockerConfig("test-image:1", Config1.CreateOptions, Option.Maybe(auth)));
            EdgeDeploymentDefinition postedEdgeDeploymentDefinition = null;
            bool postCrdCalled = 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))
                {
                    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($"namespaces/{Namespace}/{Constants.EdgeDeployment.Plural}"))
                    {
                        postCrdCalled = true;
                        using (var reader = new StreamReader(httpContext.Response.Body))
                        {
                            string crdBody = await reader.ReadToEndAsync();
                            postedEdgeDeploymentDefinition = JsonConvert.DeserializeObject <EdgeDeploymentDefinition>(crdBody);
                        }
                    }
                }

                return(false);
            }))
            {
                var client = new Kubernetes(
                    new KubernetesClientConfiguration
                {
                    Host = server.Uri
                });
                var cmd = new EdgeDeploymentCommand(Namespace, ResourceName, client, modules, Runtime, configProvider.Object);
                await cmd.ExecuteAsync(token);

                Assert.True(postCrdCalled);
                Assert.Equal("module1", postedEdgeDeploymentDefinition.Spec[0].Name);
                Assert.Equal("test-image:1", postedEdgeDeploymentDefinition.Spec[0].Config.Image);
                Assert.True(postedEdgeDeploymentDefinition.Spec[0].Env.Contains(new KeyValuePair <string, EnvVal>("ACamelCaseEnvVar", new EnvVal("ACamelCaseEnvVarValue"))));
            }
        }