public async void KubernetesPlannerPlanFailsWithNonDockerModules()
        {
            var  edgeDefinition = new EdgeDeploymentDefinition("v1", "EdgeDeployment", new V1ObjectMeta(name: ResourceName), new List <KubernetesModule>(), 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).ToBody());
                    }
                }

                return(false);
            }))
            {
                IModule   m1         = new NonDockerModule("module1", "v1", "unknown", ModuleStatus.Running, global::Microsoft.Azure.Devices.Edge.Agent.Core.RestartPolicy.Always, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars, string.Empty);
                ModuleSet addRunning = ModuleSet.Create(m1);

                var client = new Kubernetes(new KubernetesClientConfiguration {
                    Host = server.Uri
                });
                var planner = new KubernetesPlanner(Namespace, ResourceName, client, DefaultCommandFactory, ConfigProvider, EdgeletModuleOwner);
                await Assert.ThrowsAsync <InvalidModuleException>(() => planner.PlanAsync(addRunning, ModuleSet.Empty, RuntimeInfo, ImmutableDictionary <string, IModuleIdentity> .Empty));

                Assert.True(getCrdCalled);
            }
        }
Example #2
0
        public async void KubernetesPlannerNoModulesNoPlan()
        {
            var  planner = new KubernetesPlanner(Namespace, ResourceName, DefaultClient, DefaultCommandFactory, ConfigProvider);
            Plan addPlan = await planner.PlanAsync(ModuleSet.Empty, ModuleSet.Empty, RuntimeInfo, ImmutableDictionary <string, IModuleIdentity> .Empty);

            Assert.Equal(Plan.Empty, addPlan);
        }
Example #3
0
        public async void KubernetesPlannerNoModulesNoPlan()
        {
            var  planner = new KubernetesPlanner <CombinedDockerConfig>(Ns, Hostname, DeviceId, DefaultClient, DefaultCommandFactory, DefaultConfigProvider);
            Plan addPlan = await planner.PlanAsync(ModuleSet.Empty, ModuleSet.Empty, RuntimeInfo, ImmutableDictionary <string, IModuleIdentity> .Empty);

            Assert.Equal(Plan.Empty, addPlan);
        }
Example #4
0
        public async void KubernetesPlannerPlanFailsWithNonDockerModules()
        {
            IModule   m1         = new NonDockerModule("module1", "v1", "unknown", ModuleStatus.Running, RestartPolicy.Always, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars, string.Empty);
            ModuleSet addRunning = ModuleSet.Create(m1);

            var planner = new KubernetesPlanner(Namespace, ResourceName, DefaultClient, DefaultCommandFactory, ConfigProvider);
            await Assert.ThrowsAsync <InvalidModuleException>(() => planner.PlanAsync(addRunning, ModuleSet.Empty, RuntimeInfo, ImmutableDictionary <string, IModuleIdentity> .Empty));
        }
        public async void KubernetesPlannerShutdownTest()
        {
            IModule   m1      = new DockerModule("module1", "v1", ModuleStatus.Running, global::Microsoft.Azure.Devices.Edge.Agent.Core.RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars);
            ModuleSet current = ModuleSet.Create(m1);

            var planner = new KubernetesPlanner(Namespace, ResourceName, DefaultClient, DefaultCommandFactory, ConfigProvider, EdgeletModuleOwner);
            var plan    = await planner.CreateShutdownPlanAsync(current);

            Assert.Equal(Plan.Empty, plan);
        }
Example #6
0
        public async void KubernetesPlannerPlanFailsWithNonDistinctModules()
        {
            IModule   m1         = new DockerModule("module1", "v1", ModuleStatus.Running, RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars);
            IModule   m2         = new DockerModule("Module1", "v1", ModuleStatus.Running, RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars);
            ModuleSet addRunning = ModuleSet.Create(m1, m2);

            var planner = new KubernetesPlanner <CombinedDockerConfig>(Ns, Hostname, DeviceId, DefaultClient, DefaultCommandFactory, DefaultConfigProvider);

            await Assert.ThrowsAsync <InvalidIdentityException>(() => planner.PlanAsync(addRunning, ModuleSet.Empty, RuntimeInfo, ImmutableDictionary <string, IModuleIdentity> .Empty));
        }
Example #7
0
        public async void KubernetesPlannerShutdownTest()
        {
            IModule   m1      = new DockerModule("module1", "v1", ModuleStatus.Running, RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars);
            ModuleSet current = ModuleSet.Create(m1);

            var planner = new KubernetesPlanner <CombinedDockerConfig>(Ns, Hostname, DeviceId, DefaultClient, DefaultCommandFactory, DefaultConfigProvider);
            var plan    = await planner.CreateShutdownPlanAsync(current);

            Assert.Equal(Plan.Empty, plan);
        }
Example #8
0
        public async void KubernetesPlannerEmptyPlanWhenNoChanges()
        {
            IModule   m1      = new DockerModule("module1", "v1", ModuleStatus.Running, RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars);
            IModule   m2      = new DockerModule("module2", "v1", ModuleStatus.Running, RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars);
            ModuleSet desired = ModuleSet.Create(m1, m2);
            ModuleSet current = ModuleSet.Create(m1, m2);

            var planner = new KubernetesPlanner(Namespace, ResourceName, DefaultClient, DefaultCommandFactory, ConfigProvider);
            var plan    = await planner.PlanAsync(desired, current, RuntimeInfo, ImmutableDictionary <string, IModuleIdentity> .Empty);

            Assert.Equal(Plan.Empty, plan);
        }
Example #9
0
        public async void KubernetesPlannerPlanExistsWhenChangesMade()
        {
            IModule   m1      = new DockerModule("module1", "v1", ModuleStatus.Running, RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars);
            IModule   m2      = new DockerModule("module2", "v1", ModuleStatus.Running, RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars);
            ModuleSet desired = ModuleSet.Create(m1);
            ModuleSet current = ModuleSet.Create(m2);

            var planner = new KubernetesPlanner(Namespace, ResourceName, DefaultClient, DefaultCommandFactory, ConfigProvider);
            var plan    = await planner.PlanAsync(desired, current, RuntimeInfo, ImmutableDictionary <string, IModuleIdentity> .Empty);

            Assert.Single(plan.Commands);
            Assert.True(plan.Commands.First() is EdgeDeploymentCommand);
        }
        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 async void KubernetesPlannerPlanExistsWhenDeploymentsQueryFails()
        {
            bool getCrdCalled = 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))
                {
                    if (pathStr.Contains($"namespaces/{Namespace}/{Constants.EdgeDeployment.Plural}/{ResourceName}"))
                    {
                        getCrdCalled = true;
                        httpContext.Response.StatusCode = 404;
                    }
                }

                return(Task.FromResult(false));
            }))
            {
                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);
                ModuleSet desired = ModuleSet.Create(m1);
                ModuleSet current = ModuleSet.Create(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 async void KubernetesPlannerNoModulesNoPlan()
        {
            Option <EdgeDeploymentStatus> reportedStatus = Option.None <EdgeDeploymentStatus>();
            var  edgeDefinition = new EdgeDeploymentDefinition("v1", "EdgeDeployment", new V1ObjectMeta(name: ResourceName), new List <KubernetesModule>(), 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).ToBody());
                    }
                }

                return(false);
            }))
            {
                var client = new Kubernetes(new KubernetesClientConfiguration {
                    Host = server.Uri
                });
                var planner = new KubernetesPlanner(Namespace, ResourceName, client, DefaultCommandFactory, ConfigProvider, EdgeletModuleOwner);

                Plan addPlan = await planner.PlanAsync(ModuleSet.Empty, ModuleSet.Empty, RuntimeInfo, ImmutableDictionary <string, IModuleIdentity> .Empty);

                Assert.True(getCrdCalled);
                Assert.Equal(Plan.Empty, addPlan);
                Assert.False(reportedStatus.HasValue);
            }
        }
Example #13
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();
        }