Esempio n. 1
0
 TestModule(IModuleIdentity moduleIdentity, string endpointId, IDeviceListener deviceListener, List <IMessage> receivedMessages)
 {
     this.moduleIdentity   = moduleIdentity;
     this.outputName       = endpointId;
     this.deviceListener   = deviceListener;
     this.receivedMessages = receivedMessages;
 }
        public async Task TestGetModulesIdentity_EdgeHubTest()
        {
            const string Name = "filter";

            var symmetricKey = new SymmetricKey();

            symmetricKey.PrimaryKey   = Convert.ToBase64String(Encoding.UTF8.GetBytes("primarySymmetricKey"));
            symmetricKey.SecondaryKey = Convert.ToBase64String(Encoding.UTF8.GetBytes("secondarySymmetricKey"));

            var serviceModuleFilterIdentity = new Module("device1", Name)
            {
                Authentication = new AuthenticationMechanism
                {
                    SymmetricKey = symmetricKey
                }
            };

            var serviceModuleEdgeHubIdentity = new Module("device1", Constants.EdgeHubModuleIdentityName)
            {
                Authentication = new AuthenticationMechanism
                {
                    SymmetricKey = symmetricKey
                }
            };

            var    serviceClient   = new Mock <IServiceClient>();
            string hostname        = "hostname";
            string deviceId        = "deviceId";
            string gatewayHostName = "localhost";

            Module[] serviceIdentities = { serviceModuleFilterIdentity, serviceModuleEdgeHubIdentity };
            serviceClient.Setup(sc => sc.GetModules()).Returns(Task.FromResult(serviceIdentities.AsEnumerable()));
            serviceClient.Setup(sc => sc.CreateModules(It.Is <IEnumerable <string> >(m => !m.Any()))).Returns(Task.FromResult(new Module[0]));
            serviceClient.Setup(sc => sc.UpdateModules(It.Is <IEnumerable <Module> >(m => !m.Any()))).Returns(Task.FromResult(new Module[0]));

            var testMod    = new TestModule(Name, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars);
            var edgeHubMod = new TestModule(Constants.EdgeHubModuleName, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.Always, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars);

            IImmutableDictionary <string, IModuleIdentity> modulesIdentities = await new ModuleIdentityLifecycleManager(serviceClient.Object, hostname, deviceId, gatewayHostName)
                                                                               .GetModuleIdentitiesAsync(ModuleSet.Create(testMod, edgeHubMod), ModuleSet.Empty);

            serviceClient.Verify(sc => sc.CreateModules(It.Is <IEnumerable <string> >(m => !m.Any())), Times.Once);
            serviceClient.Verify(sc => sc.UpdateModules(It.Is <IEnumerable <Module> >(m => !m.Any())), Times.Once);
            Assert.True(modulesIdentities.Count == 2);
            IModuleIdentity edgeHubModuleIdentity = modulesIdentities[Constants.EdgeHubModuleName];

            Assert.NotNull(edgeHubModuleIdentity);
            var edgeHubCreds = edgeHubModuleIdentity.Credentials as ConnectionStringCredentials;

            Assert.NotNull(edgeHubCreds);
            Assert.Equal("HostName=hostname;DeviceId=deviceId;ModuleId=$edgeHub;SharedAccessKey=cHJpbWFyeVN5bW1ldHJpY0tleQ==", edgeHubCreds.ConnectionString);

            IModuleIdentity testModuleIdentity = modulesIdentities[Name];

            Assert.NotNull(testModuleIdentity);
            var testModCreds = testModuleIdentity.Credentials as ConnectionStringCredentials;

            Assert.NotNull(testModCreds);
            Assert.Equal("HostName=hostname;DeviceId=deviceId;ModuleId=filter;SharedAccessKey=cHJpbWFyeVN5bW1ldHJpY0tleQ==;GatewayHostName=localhost", testModCreds.ConnectionString);
        }
        public void Test_CreateIdentity_WithEdgelet_SetAuthScheme_ShouldCreateIdentity(
            string iotHubHostName,
            string deviceId,
            string moduleId,
            string generationId,
            string edgeletUri,
            string authScheme = "sasToken")
        {
            // Arrange
            var builder = new ModuleIdentityProviderServiceBuilder(iotHubHostName, deviceId);

            // Act
            IModuleIdentity identity = builder.Create(moduleId, generationId, edgeletUri, authScheme);

            // Assert
            Assert.Equal(iotHubHostName, identity.IotHubHostname);
            Assert.Equal(deviceId, identity.DeviceId);
            Assert.Equal(moduleId, identity.ModuleId);
            var creds = identity.Credentials as IdentityProviderServiceCredentials;

            Assert.NotNull(creds);
            Assert.Equal(edgeletUri, creds.ProviderUri);
            Assert.Equal(authScheme, creds.AuthScheme);
            Assert.Equal(generationId, creds.ModuleGenerationId);
            Assert.Equal(Option.None <string>(), creds.Version);
        }
Esempio n. 4
0
        V1PodTemplateSpec GetPod(string name, IModuleIdentity identity, KubernetesModule module, IDictionary <string, string> labels)
        {
            // Convert docker labels to annotations because docker labels don't have the same restrictions as Kubernetes labels.
            Dictionary <string, string> annotations = module.Config.CreateOptions.Labels
                                                      .Map(dockerLabels => dockerLabels.ToDictionary(label => KubeUtils.SanitizeAnnotationKey(label.Key), label => label.Value))
                                                      .GetOrElse(() => new Dictionary <string, string>());

            annotations[KubernetesConstants.K8sEdgeOriginalModuleId] = ModuleIdentityHelper.GetModuleName(identity.ModuleId);

            var(proxyContainer, proxyVolumes)   = this.PrepareProxyContainer(module);
            var(moduleContainer, moduleVolumes) = this.PrepareModuleContainer(name, identity, module);

            Option <List <V1LocalObjectReference> > imageSecret = module.Config.AuthConfig
                                                                  .Map(auth => new List <V1LocalObjectReference> {
                new V1LocalObjectReference(auth.Name)
            });

            Option <IDictionary <string, string> > nodeSelector = Option.Maybe(module.Config.CreateOptions).FlatMap(options => options.NodeSelector);

            var modulePodSpec = new V1PodSpec(
                containers: new List <V1Container> {
                proxyContainer, moduleContainer
            },
                volumes: proxyVolumes.Concat(moduleVolumes).ToList(),
                imagePullSecrets: imageSecret.OrDefault(),
                serviceAccountName: name,
                nodeSelector: nodeSelector.OrDefault());

            var objectMeta = new V1ObjectMeta(name: name, labels: labels, annotations: annotations);

            return(new V1PodTemplateSpec(objectMeta, modulePodSpec));
        }
Esempio n. 5
0
 public static CreateOrUpdateCommand BuildCreate(
     IModuleManager moduleManager,
     IModule module,
     IModuleIdentity identity,
     IConfigSource configSource,
     object settings) =>
 Build(moduleManager, module, identity, configSource, settings, Operation.Create);
Esempio n. 6
0
 public static CreateOrUpdateCommand BuildUpdate(
     IModuleManager moduleManager,
     IModule module,
     IModuleIdentity identity,
     IConfigSource configSource,
     object settings,
     bool start) =>
 Build(moduleManager, module, identity, configSource, settings, start ? Operation.UpdateAndStart : Operation.Update);
Esempio n. 7
0
        public Option <V1Service> CreateService(IModuleIdentity identity, KubernetesModule module, IDictionary <string, string> labels)
        {
            Option <V1Service> service = this.PrepareService(identity, module, labels);

            service.ForEach(s => s.Metadata.Annotations[KubernetesConstants.CreationString] = JsonConvert.SerializeObject(s));

            return(service);
        }
        public V1Deployment CreateDeployment(IModuleIdentity identity, KubernetesModule module, IDictionary <string, string> labels)
        {
            var deployment = this.PrepareDeployment(identity, module, labels);

            deployment.Metadata.Annotations[KubernetesConstants.CreationString] = JsonConvert.SerializeObject(deployment);

            return(deployment);
        }
Esempio n. 9
0
 public static CreateOrUpdateCommand BuildCreate(
     IModuleManager moduleManager,
     IModule module,
     IModuleIdentity identity,
     IConfigSource configSource,
     object settings,
     string edgeDeviceHostname,
     Option <string> parentEdgeHostname) =>
 Build(moduleManager, module, identity, configSource, settings, Operation.Create, edgeDeviceHostname, parentEdgeHostname);
        List <V1EnvVar> CollectEnv(KubernetesModule module, IModuleIdentity identity)
        {
            var envList = module.Env.Select(env => new V1EnvVar(env.Key, env.Value.Value)).ToList();

            char[] envSplit = { '=' };
            if (module.Config?.CreateOptions?.Env != null)
            {
                foreach (string hostEnv in module.Config?.CreateOptions?.Env)
                {
                    string[] keyValue = hostEnv.Split(envSplit, 2);
                    if (keyValue.Length == 2)
                    {
                        envList.Add(new V1EnvVar(keyValue[0], keyValue[1]));
                    }
                }
            }

            envList.Add(new V1EnvVar(CoreConstants.IotHubHostnameVariableName, identity.IotHubHostname));
            envList.Add(new V1EnvVar(CoreConstants.EdgeletAuthSchemeVariableName, "sasToken"));
            envList.Add(new V1EnvVar(Logger.RuntimeLogLevelEnvKey, Logger.GetLogLevel().ToString()));
            envList.Add(new V1EnvVar(CoreConstants.EdgeletWorkloadUriVariableName, this.workloadUri.ToString()));
            if (identity.Credentials is IdentityProviderServiceCredentials creds)
            {
                envList.Add(new V1EnvVar(CoreConstants.EdgeletModuleGenerationIdVariableName, creds.ModuleGenerationId));
            }

            envList.Add(new V1EnvVar(CoreConstants.DeviceIdVariableName, identity.DeviceId));
            envList.Add(new V1EnvVar(CoreConstants.ModuleIdVariableName, identity.ModuleId));
            envList.Add(new V1EnvVar(CoreConstants.EdgeletApiVersionVariableName, this.workloadApiVersion));

            if (string.Equals(identity.ModuleId, CoreConstants.EdgeAgentModuleIdentityName))
            {
                envList.Add(new V1EnvVar(CoreConstants.ModeKey, CoreConstants.KubernetesMode));
                envList.Add(new V1EnvVar(CoreConstants.EdgeletManagementUriVariableName, this.managementUri.ToString()));
                envList.Add(new V1EnvVar(CoreConstants.NetworkIdKey, "azure-iot-edge"));
                envList.Add(new V1EnvVar(KubernetesConstants.ProxyImageEnvKey, this.proxyImage));
                envList.Add(new V1EnvVar(KubernetesConstants.ProxyConfigPathEnvKey, this.proxyConfigPath));
                envList.Add(new V1EnvVar(KubernetesConstants.ProxyConfigVolumeEnvKey, this.proxyConfigVolumeName));
                envList.Add(new V1EnvVar(KubernetesConstants.ProxyConfigMapNameEnvKey, this.proxyConfigMapName));
                envList.Add(new V1EnvVar(KubernetesConstants.ProxyTrustBundlePathEnvKey, this.proxyTrustBundlePath));
                envList.Add(new V1EnvVar(KubernetesConstants.ProxyTrustBundleVolumeEnvKey, this.proxyTrustBundleVolumeName));
                envList.Add(new V1EnvVar(KubernetesConstants.ProxyTrustBundleConfigMapEnvKey, this.proxyTrustBundleConfigMapName));
                envList.Add(new V1EnvVar(KubernetesConstants.K8sNamespaceKey, this.deviceNamespace));
            }

            if (string.Equals(identity.ModuleId, CoreConstants.EdgeAgentModuleIdentityName) ||
                string.Equals(identity.ModuleId, CoreConstants.EdgeHubModuleIdentityName))
            {
                envList.Add(new V1EnvVar(CoreConstants.EdgeDeviceHostNameKey, this.edgeHostname));
            }
            else
            {
                envList.Add(new V1EnvVar(CoreConstants.GatewayHostnameVariableName, EdgeHubHostname));
            }

            return(envList);
        }
        V1PodTemplateSpec GetPod(string name, IModuleIdentity identity, KubernetesModule module, IDictionary <string, string> labels)
        {
            List <V1EnvVar> envVars = this.CollectEnv(module, identity);

            // Convert docker labels to annotations because docker labels don't have the same restrictions as Kubernetes labels.
            var annotations = Option.Maybe(module.Config.CreateOptions?.Labels)
                              .Map(dockerLabels => dockerLabels.ToDictionary(label => KubeUtils.SanitizeAnnotationKey(label.Key), label => label.Value))
                              .GetOrElse(() => new Dictionary <string, string>());

            annotations[KubernetesConstants.K8sEdgeOriginalModuleId] = ModuleIdentityHelper.GetModuleName(identity.ModuleId);

            // Per container settings:
            // exposed ports
            Option <List <V1ContainerPort> > exposedPorts = Option.Maybe(module.Config?.CreateOptions?.ExposedPorts)
                                                            .Map(PortExtensions.GetContainerPorts);

            // privileged container
            Option <V1SecurityContext> securityContext = Option.Maybe(module.Config?.CreateOptions?.HostConfig?.Privileged)
                                                         .Map(config => new V1SecurityContext(privileged: true));

            // Bind mounts
            (List <V1Volume> volumes, List <V1VolumeMount> proxyMounts, List <V1VolumeMount> volumeMounts) = this.GetVolumesFromModule(module);

            var containers = new List <V1Container>
            {
                new V1Container(
                    name,
                    env: envVars,
                    image: module.Config.Image,
                    volumeMounts: volumeMounts,
                    securityContext: securityContext.OrDefault(),
                    ports: exposedPorts.OrDefault()),

                new V1Container(
                    "proxy",
                    env: envVars, // TODO: check these for validity for proxy.
                    image: this.proxyImage,
                    volumeMounts: proxyMounts)
            };

            Option <List <V1LocalObjectReference> > imageSecret = module.Config.AuthConfig.Map(
                auth =>
            {
                var secret   = new ImagePullSecret(auth);
                var authList = new List <V1LocalObjectReference>
                {
                    new V1LocalObjectReference(secret.Name)
                };
                return(authList);
            });

            var modulePodSpec = new V1PodSpec(containers, volumes: volumes, imagePullSecrets: imageSecret.OrDefault(), serviceAccountName: name);

            var objectMeta = new V1ObjectMeta(name: name, labels: labels, annotations: annotations);

            return(new V1PodTemplateSpec(objectMeta, modulePodSpec));
        }
        public V1ServiceAccount CreateServiceAccount(IModuleIdentity identity, IDictionary <string, string> labels)
        {
            string name        = identity.DeploymentName();
            var    annotations = new Dictionary <string, string>
            {
                [KubernetesConstants.K8sEdgeOriginalModuleId] = ModuleIdentityHelper.GetModuleName(identity.ModuleId)
            };
            var metadata = new V1ObjectMeta(annotations, name: name, labels: labels);

            return(new V1ServiceAccount(metadata: metadata));
        }
Esempio n. 13
0
        Option <V1Service> PrepareService(IModuleIdentity identity, KubernetesModule module, IDictionary <string, string> labels)
        {
            // Add annotations from Docker labels. This provides the customer a way to assign annotations to services if they want
            // to tie backend services to load balancers via an Ingress Controller.
            var annotations = module.Config.CreateOptions.Labels
                              .Map(dockerLabels => dockerLabels.ToDictionary(label => KubeUtils.SanitizeAnnotationKey(label.Key), label => label.Value))
                              .GetOrElse(() => new Dictionary <string, string>());

            // Entries in the Exposed Port list just tell Docker that this container wants to listen on that port.
            // We interpret this as a "ClusterIP" service type listening on that exposed port, backed by this module.
            // Users of this Module's exposed port should be able to find the service by connecting to "<module name>:<port>"
            Option <List <V1ServicePort> > exposedPorts = module.Config.CreateOptions.ExposedPorts
                                                          .Map(ports => ports.GetExposedPorts());

            // Entries in Docker portMap wants to expose a port on the host (hostPort) and map it to the container's port (port)
            // We interpret that as the pod wants the cluster to expose a port on a public IP (hostPort), and target it to the container's port (port)
            Option <List <V1ServicePort> > hostPorts = module.Config.CreateOptions.HostConfig
                                                       .FlatMap(config => Option.Maybe(config.PortBindings).Map(ports => ports.GetHostPorts()));

            bool onlyExposedPorts = !hostPorts.HasValue;

            // override exposed ports with host ports
            var servicePorts = new Dictionary <int, V1ServicePort>();

            exposedPorts.ForEach(ports => ports.ForEach(port => servicePorts[port.Port] = port));
            hostPorts.ForEach(ports => ports.ForEach(port => servicePorts[port.Port]    = port));

            if (servicePorts.Any())
            {
                // Selector: by module name and device name, also how we will label this puppy.
                string name        = identity.DeploymentName();
                var    serviceMeta = new V1ObjectMeta(
                    name: name,
                    labels: labels,
                    annotations: annotations,
                    ownerReferences: module.Owner.ToOwnerReferences());

                // How we manage this service is dependent on the port mappings user asks for.
                // If the user tells us to only use ClusterIP ports, we will always set the type to ClusterIP.
                // If all we had were exposed ports, we will assume ClusterIP. Otherwise, we use the given value as the default service type
                //
                // If the user wants to expose the ClusterIPs port externally, they should manually create a service to expose it.
                // This gives the user more control as to how they want this to work.
                var serviceType = onlyExposedPorts
                    ? PortMapServiceType.ClusterIP
                    : this.defaultMapServiceType;

                return(Option.Some(new V1Service(metadata: serviceMeta, spec: new V1ServiceSpec(type: serviceType.ToString(), ports: servicePorts.Values.ToList(), selector: labels))));
            }

            return(Option.None <V1Service>());
        }
        V1Deployment PrepareDeployment(IModuleIdentity identity, KubernetesModule module, IDictionary <string, string> labels)
        {
            string name = identity.DeploymentName();

            var podSpec = this.GetPod(name, identity, module, labels);

            var selector       = new V1LabelSelector(matchLabels: labels);
            var deploymentSpec = new V1DeploymentSpec(replicas: 1, selector: selector, template: podSpec);

            var deploymentMeta = new V1ObjectMeta(name: name, labels: labels, annotations: new Dictionary <string, string>());

            return(new V1Deployment(metadata: deploymentMeta, spec: deploymentSpec));
        }
Esempio n. 15
0
 EdgeHubConnection(IModuleIdentity edgeHubIdentity,
                   ITwinManager twinManager,
                   RouteFactory routeFactory,
                   IMessageConverter <TwinCollection> twinCollectionMessageConverter,
                   IMessageConverter <Twin> twinMessageConverter,
                   VersionInfo versionInfo)
 {
     this.edgeHubIdentity = edgeHubIdentity;
     this.twinManager     = twinManager;
     this.twinCollectionMessageConverter = twinCollectionMessageConverter;
     this.twinMessageConverter           = twinMessageConverter;
     this.routeFactory = routeFactory;
     this.versionInfo  = versionInfo ?? VersionInfo.Empty;
 }
        V1PodTemplateSpec GetPod(string name, IModuleIdentity identity, KubernetesModule module, IDictionary <string, string> labels)
        {
            // Convert docker labels to annotations because docker labels don't have the same restrictions as Kubernetes labels.
            Dictionary <string, string> annotations = module.Config.CreateOptions.Labels
                                                      .Map(dockerLabels => dockerLabels.ToDictionary(label => KubeUtils.SanitizeAnnotationKey(label.Key), label => label.Value))
                                                      .GetOrElse(() => new Dictionary <string, string>());

            annotations[KubernetesConstants.K8sEdgeOriginalModuleId] = ModuleIdentityHelper.GetModuleName(identity.ModuleId);

            var(proxyContainer, proxyVolumes)   = this.PrepareProxyContainer(module);
            var(moduleContainer, moduleVolumes) = this.PrepareModuleContainer(name, identity, module);
            bool?hostIpc = this.IsHostIpc(module.Config.CreateOptions);

            var imagePullSecrets = new List <Option <string> > {
                this.proxyImagePullSecretName, module.Config.AuthConfig.Map(auth => auth.Name)
            }
            .FilterMap()
            .Distinct()
            .Select(pullSecretName => new V1LocalObjectReference(pullSecretName))
            .ToList();

            V1PodSecurityContext securityContext = module.Config.CreateOptions.SecurityContext.GetOrElse(
                () => this.runAsNonRoot
                    ? new V1PodSecurityContext {
                RunAsNonRoot = true, RunAsUser = 1000
            }
                    : null);

            return(new V1PodTemplateSpec
            {
                Metadata = new V1ObjectMeta
                {
                    Name = name,
                    Labels = labels,
                    Annotations = annotations
                },
                Spec = new V1PodSpec
                {
                    Containers = new List <V1Container> {
                        proxyContainer, moduleContainer
                    },
                    Volumes = proxyVolumes.Concat(moduleVolumes).ToList(),
                    ImagePullSecrets = imagePullSecrets.Any() ? imagePullSecrets : null,
                    SecurityContext = securityContext,
                    ServiceAccountName = name,
                    NodeSelector = module.Config.CreateOptions.NodeSelector.OrDefault(),
                    HostIPC = hostIpc,
                }
            });
        }
Esempio n. 17
0
 internal EdgeHubConnection(IModuleIdentity edgeHubIdentity,
                            ITwinManager twinManager,
                            RouteFactory routeFactory,
                            IMessageConverter <TwinCollection> twinCollectionMessageConverter,
                            IMessageConverter <Twin> twinMessageConverter,
                            VersionInfo versionInfo,
                            IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache)
 {
     this.edgeHubIdentity = edgeHubIdentity;
     this.twinManager     = twinManager;
     this.twinCollectionMessageConverter = twinCollectionMessageConverter;
     this.twinMessageConverter           = twinMessageConverter;
     this.routeFactory = routeFactory;
     this.versionInfo  = versionInfo ?? VersionInfo.Empty;
     this.deviceScopeIdentitiesCache = deviceScopeIdentitiesCache;
 }
Esempio n. 18
0
        public static async Task <ICommand> BuildAsync(
            IDockerClient client,
            DockerModule module,
            IModuleIdentity identity,
            DockerLoggingConfig defaultDockerLoggerConfig,
            IConfigSource configSource,
            bool buildForEdgeHub
            )
        {
            // Validate parameters
            Preconditions.CheckNotNull(client, nameof(client));
            Preconditions.CheckNotNull(module, nameof(module));
            Preconditions.CheckNotNull(defaultDockerLoggerConfig, nameof(defaultDockerLoggerConfig));
            Preconditions.CheckNotNull(configSource, nameof(configSource));

            CreateContainerParameters createContainerParameters = module.Config.CreateOptions ?? new CreateContainerParameters();

            // serialize user provided create options to add as docker label, before adding other values
            string createOptionsString = JsonConvert.SerializeObject(createContainerParameters);

            // Force update parameters with indexing entries
            createContainerParameters.Name  = module.Name;
            createContainerParameters.Image = module.Config.Image;

            DeploymentConfigInfo deploymentConfigInfo = await configSource.GetDeploymentConfigInfoAsync();

            DeploymentConfig           deploymentConfig  = deploymentConfigInfo.DeploymentConfig;
            Option <DockerRuntimeInfo> dockerRuntimeInfo = deploymentConfig != DeploymentConfig.Empty && deploymentConfig.Runtime is DockerRuntimeInfo
                ? Option.Some((DockerRuntimeInfo)deploymentConfig.Runtime)
                : Option.None <DockerRuntimeInfo>();

            // Inject global parameters
            InjectCerts(createContainerParameters, configSource, buildForEdgeHub);
            InjectConfig(createContainerParameters, identity, buildForEdgeHub, configSource);
            InjectPortBindings(createContainerParameters, buildForEdgeHub);
            InjectLoggerConfig(createContainerParameters, defaultDockerLoggerConfig, dockerRuntimeInfo.Map(r => r.Config.LoggingOptions));
            InjectModuleEnvVars(createContainerParameters, module.Env);
            // Inject required Edge parameters
            InjectLabels(createContainerParameters, module, createOptionsString);

            InjectNetworkAlias(createContainerParameters, configSource, buildForEdgeHub);

            return(new CreateCommand(client, createContainerParameters));
        }
Esempio n. 19
0
        V1Deployment PrepareDeployment(IModuleIdentity identity, KubernetesModule module, IDictionary <string, string> labels)
        {
            string name = identity.DeploymentName();

            var podSpec = this.GetPod(name, identity, module, labels);

            var selector = new V1LabelSelector(matchLabels: labels);
            // Desired status in Deployment should only be Running or Stopped. Assume Running if not Stopped
            int replicas       = (module.DesiredStatus != ModuleStatus.Stopped) ? 1 : 0;
            var deploymentSpec = new V1DeploymentSpec(replicas: replicas, selector: selector, template: podSpec);

            var deploymentMeta = new V1ObjectMeta(
                name: name,
                labels: labels,
                annotations: new Dictionary <string, string>(),
                ownerReferences: module.Owner.ToOwnerReferences());

            return(new V1Deployment(metadata: deploymentMeta, spec: deploymentSpec));
        }
Esempio n. 20
0
        static CreateOrUpdateCommand Build(
            IModuleManager moduleManager,
            IModule module,
            IModuleIdentity identity,
            IConfigSource configSource,
            object settings,
            Operation operation)
        {
            Preconditions.CheckNotNull(moduleManager, nameof(moduleManager));
            Preconditions.CheckNotNull(module, nameof(module));
            Preconditions.CheckNotNull(identity, nameof(identity));
            Preconditions.CheckNotNull(configSource, nameof(configSource));
            Preconditions.CheckNotNull(settings, nameof(settings));

            IEnumerable <EnvVar> envVars    = GetEnvVars(module.Env, identity, configSource);
            ModuleSpec           moduleSpec = BuildModuleSpec(module, envVars, settings);

            return(new CreateOrUpdateCommand(moduleManager, moduleSpec, operation));
        }
Esempio n. 21
0
        public static async Task <EdgeHubConnection> Create(
            IModuleIdentity edgeHubIdentity,
            IEdgeHub edgeHub,
            ITwinManager twinManager,
            IConnectionManager connectionManager,
            ICloudProxy cloudProxy,
            RouteFactory routeFactory,
            IMessageConverter <TwinCollection> twinCollectionMessageConverter,
            IMessageConverter <Twin> twinMessageConverter,
            VersionInfo versionInfo
            )
        {
            Preconditions.CheckNotNull(edgeHubIdentity, nameof(edgeHubIdentity));
            Preconditions.CheckNotNull(edgeHub, nameof(edgeHub));
            Preconditions.CheckNotNull(connectionManager, nameof(connectionManager));
            Preconditions.CheckNotNull(cloudProxy, nameof(cloudProxy));
            Preconditions.CheckNotNull(twinCollectionMessageConverter, nameof(twinCollectionMessageConverter));
            Preconditions.CheckNotNull(twinMessageConverter, nameof(twinMessageConverter));
            Preconditions.CheckNotNull(routeFactory, nameof(routeFactory));

            var edgeHubConnection = new EdgeHubConnection(
                edgeHubIdentity, twinManager, routeFactory,
                twinCollectionMessageConverter, twinMessageConverter,
                versionInfo ?? VersionInfo.Empty
                );

            cloudProxy.BindCloudListener(new CloudListener(edgeHubConnection));

            IDeviceProxy deviceProxy = new EdgeHubDeviceProxy(edgeHubConnection);
            await connectionManager.AddDeviceConnection(edgeHubIdentity, deviceProxy);

            await edgeHub.AddSubscription(edgeHubIdentity.Id, DeviceSubscription.DesiredPropertyUpdates);

            // Clear out all the reported devices.
            await edgeHubConnection.ClearDeviceConnectionStatuses();

            connectionManager.DeviceConnected    += edgeHubConnection.DeviceConnected;
            connectionManager.DeviceDisconnected += edgeHubConnection.DeviceDisconnected;
            Events.Initialized(edgeHubIdentity);
            return(edgeHubConnection);
        }
Esempio n. 22
0
        static IEnumerable <EnvVar> GetEnvVars(
            IDictionary <string, EnvVal> moduleEnvVars,
            IModuleIdentity identity,
            IConfigSource configSource,
            string edgeDeviceHostname,
            Option <string> parentEdgeHostname)
        {
            List <EnvVar> envVars = moduleEnvVars.Select(m => new EnvVar(m.Key, m.Value.Value)).ToList();

            // Inject the connection details as an environment variable
            if (identity.Credentials is IdentityProviderServiceCredentials creds)
            {
                if (!string.IsNullOrWhiteSpace(creds.ProviderUri))
                {
                    envVars.Add(new EnvVar(Constants.EdgeletWorkloadUriVariableName, creds.ProviderUri));
                }

                if (!string.IsNullOrWhiteSpace(creds.AuthScheme))
                {
                    envVars.Add(new EnvVar(Constants.EdgeletAuthSchemeVariableName, creds.AuthScheme));
                }

                if (!string.IsNullOrWhiteSpace(creds.ModuleGenerationId))
                {
                    envVars.Add(new EnvVar(Constants.EdgeletModuleGenerationIdVariableName, creds.ModuleGenerationId));
                }
            }

            if (!string.IsNullOrWhiteSpace(identity.IotHubHostname))
            {
                envVars.Add(new EnvVar(Constants.IotHubHostnameVariableName, identity.IotHubHostname));
            }

            // In nested edge scenario, EdgeAgent and EdgeHub will use parent edge as upstream gateway,
            // Other modules use current edge hub as upstream gateway and have parent edge hostname in environment variable.
            if (identity.ModuleId.Equals(Constants.EdgeAgentModuleIdentityName) || identity.ModuleId.Equals(Constants.EdgeHubModuleIdentityName))
            {
                envVars.Add(new EnvVar(Constants.EdgeDeviceHostNameKey, edgeDeviceHostname));
                parentEdgeHostname.ForEach(value => envVars.Add(new EnvVar(Constants.GatewayHostnameVariableName, value)));
            }
            else
            {
                envVars.Add(new EnvVar(Constants.GatewayHostnameVariableName, edgeDeviceHostname));
                parentEdgeHostname.ForEach(value => envVars.Add(new EnvVar(Constants.ParentEdgeHostnameVariableName, value)));
            }

            if (!string.IsNullOrWhiteSpace(identity.DeviceId))
            {
                envVars.Add(new EnvVar(Constants.DeviceIdVariableName, identity.DeviceId));
            }

            if (!string.IsNullOrWhiteSpace(identity.ModuleId))
            {
                envVars.Add(new EnvVar(Constants.ModuleIdVariableName, identity.ModuleId));
            }

            if (!envVars.Exists(e => e.Key == Logger.RuntimeLogLevelEnvKey))
            {
                envVars.Add(new EnvVar(Logger.RuntimeLogLevelEnvKey, Logger.GetLogLevel().ToString()));
            }

            configSource.Configuration.GetValue <string>(Constants.UpstreamProtocolKey).ToUpstreamProtocol().ForEach(
                u =>
            {
                if (!envVars.Any(e => e.Key.Equals(Constants.UpstreamProtocolKey, StringComparison.OrdinalIgnoreCase)))
                {
                    envVars.Add(new EnvVar(Constants.UpstreamProtocolKey, u.ToString()));
                }
            });

            if (identity.ModuleId.Equals(Constants.EdgeAgentModuleIdentityName))
            {
                string managementUri = configSource.Configuration.GetValue <string>(Constants.EdgeletManagementUriVariableName);
                if (!string.IsNullOrEmpty(managementUri))
                {
                    envVars.Add(new EnvVar(Constants.EdgeletManagementUriVariableName, managementUri));
                }

                string networkId = configSource.Configuration.GetValue <string>(Constants.NetworkIdKey);
                if (!string.IsNullOrEmpty(networkId))
                {
                    envVars.Add(new EnvVar(Constants.NetworkIdKey, networkId));
                }

                string workloadListenMnt = configSource.Configuration.GetValue <string>(Constants.EdgeletWorkloadListenMntUriVariableName);
                if (!string.IsNullOrEmpty(workloadListenMnt))
                {
                    envVars.Add(new EnvVar(Constants.EdgeletWorkloadListenMntUriVariableName, workloadListenMnt));
                }

                envVars.Add(new EnvVar(Constants.ModeKey, Constants.IotedgedMode));
            }

            // Set the edgelet's api version
            string apiVersion = configSource.Configuration.GetValue <string>(Constants.EdgeletApiVersionVariableName);

            if (!string.IsNullOrEmpty(apiVersion))
            {
                envVars.Add(new EnvVar(Constants.EdgeletApiVersionVariableName, apiVersion));
            }

            return(envVars);
        }
 public static void AuthenticatingWithDeviceIdentity(IModuleIdentity moduleIdentity)
 {
     Log.LogInformation((int)EventIds.AuthenticatingWithDeviceIdentity, $"Unable to authenticate client {moduleIdentity.Id} with module credentials. Attempting to authenticate using device {moduleIdentity.DeviceId} credentials.");
 }
Esempio n. 24
0
        static void InjectConfig(CreateContainerParameters createContainerParameters, IModuleIdentity identity, bool injectForEdgeHub, IConfigSource configSource)
        {
            var envVars = new List <string>();

            // Inject the connection string as an environment variable
            if (identity.Credentials is ConnectionStringCredentials creds && !string.IsNullOrWhiteSpace(creds.ConnectionString))
            {
                string connectionStringKey = injectForEdgeHub ? Constants.IotHubConnectionStringKey : Constants.EdgeHubConnectionStringKey;
                envVars.Add($"{connectionStringKey}={creds.ConnectionString}");
            }

            if (injectForEdgeHub)
            {
                envVars.Add($"{Logger.RuntimeLogLevelEnvKey}={Logger.GetLogLevel()}");
            }

            configSource.Configuration.GetValue <string>(Constants.UpstreamProtocolKey).ToUpstreamProtocol().ForEach(
                u =>
            {
                if (createContainerParameters.Env?.Any(e => e.StartsWith("UpstreamProtocol=", StringComparison.OrdinalIgnoreCase)) == false)
                {
                    envVars.Add($"UpstreamProtocol={u}");
                }
            });

            InjectEnvVars(createContainerParameters, envVars);
        }
Esempio n. 25
0
 public ModuleWithIdentity(IModule module, IModuleIdentity moduleIdentity)
 {
     this.module         = Preconditions.CheckNotNull(module, nameof(module));
     this.moduleIdentity = Preconditions.CheckNotNull(moduleIdentity, nameof(moduleIdentity));
 }
Esempio n. 26
0
 public static void InvalidDeviceId(IModuleIdentity moduleIdentity, string edgeDeviceId)
 {
     Log.LogError((int)EventIds.InvalidDeviceError, Invariant($"Device Id {moduleIdentity.DeviceId} of module {moduleIdentity.ModuleId} is different from the edge device Id {edgeDeviceId}"));
 }
Esempio n. 27
0
        private Option <V1Service> GetServiceFromModule(Dictionary <string, string> labels, KubernetesModule <TConfig> module, IModuleIdentity moduleIdentity)
        {
            var portList = new List <V1ServicePort>();
            Option <Dictionary <string, string> > serviceAnnotations = Option.None <Dictionary <string, string> >();
            bool onlyExposedPorts = true;

            if (module is IModule <AgentDocker.CombinedDockerConfig> moduleWithDockerConfig)
            {
                if (moduleWithDockerConfig.Config.CreateOptions?.Labels != null)
                {
                    // Add annotations from Docker labels. This provides the customer a way to assign annotations to services if they want
                    // to tie backend services to load balancers via an Ingress Controller.
                    var annotations = new Dictionary <string, string>();
                    foreach (KeyValuePair <string, string> label in moduleWithDockerConfig.Config.CreateOptions?.Labels)
                    {
                        annotations.Add(KubeUtils.SanitizeAnnotationKey(label.Key), label.Value);
                    }

                    serviceAnnotations = Option.Some(annotations);
                }

                // Handle ExposedPorts entries
                if (moduleWithDockerConfig.Config?.CreateOptions?.ExposedPorts != null)
                {
                    // Entries in the Exposed Port list just tell Docker that this container wants to listen on that port.
                    // We interpret this as a "ClusterIP" service type listening on that exposed port, backed by this module.
                    // Users of this Module's exposed port should be able to find the service by connecting to "<module name>:<port>"
                    this.GetExposedPorts(moduleWithDockerConfig.Config.CreateOptions.ExposedPorts)
                    .ForEach(
                        exposedList =>
                        exposedList.ForEach((item) => portList.Add(new V1ServicePort(item.Port, name: $"ExposedPort-{item.Port}-{item.Protocol.ToLower()}", protocol: item.Protocol))));
                }

                // Handle HostConfig PortBindings entries
                if (moduleWithDockerConfig.Config?.CreateOptions?.HostConfig?.PortBindings != null)
                {
                    foreach (KeyValuePair <string, IList <DockerModels.PortBinding> > portBinding in moduleWithDockerConfig.Config?.CreateOptions?.HostConfig?.PortBindings)
                    {
                        string[] portProtocol = portBinding.Key.Split('/');
                        if (portProtocol.Length == 2)
                        {
                            if (int.TryParse(portProtocol[0], out int port) && this.ValidateProtocol(portProtocol[1], out string protocol))
                            {
                                // Entries in Docker portMap wants to expose a port on the host (hostPort) and map it to the container's port (port)
                                // We interpret that as the pod wants the cluster to expose a port on a public IP (hostPort), and target it to the container's port (port)
                                foreach (DockerModels.PortBinding hostBinding in portBinding.Value)
                                {
                                    if (int.TryParse(hostBinding.HostPort, out int hostPort))
                                    {
                                        // If a port entry contains the same "port", then remove it and replace with a new ServicePort that contains a target.
                                        var duplicate = portList.SingleOrDefault(a => a.Port == hostPort);
                                        if (duplicate != default(V1ServicePort))
                                        {
                                            portList.Remove(duplicate);
                                        }

                                        portList.Add(new V1ServicePort(hostPort, name: $"HostPort-{port}-{protocol.ToLower()}", protocol: protocol, targetPort: port));
                                        onlyExposedPorts = false;
                                    }
                                    else
                                    {
                                        Events.PortBindingValue(module, portBinding.Key);
                                    }
                                }
                            }
                        }
                    }
                }
            }

            if (portList.Count > 0)
            {
                // Selector: by module name and device name, also how we will label this puppy.
                var objectMeta = new V1ObjectMeta(annotations: serviceAnnotations.GetOrElse(() => null), labels: labels, name: KubeUtils.SanitizeDNSValue(moduleIdentity.ModuleId));
                // How we manage this service is dependent on the port mappings user asks for.
                // If the user tells us to only use ClusterIP ports, we will always set the type to ClusterIP.
                // If all we had were exposed ports, we will assume ClusterIP. Otherwise, we use the given value as the default service type
                //
                // If the user wants to expose the ClusterIPs port externally, they should manually create a service to expose it.
                // This gives the user more control as to how they want this to work.
                string serviceType;
                if (onlyExposedPorts)
                {
                    serviceType = "ClusterIP";
                }
                else
                {
                    serviceType = this.defaultMapServiceType;
                }

                return(Option.Some(new V1Service(metadata: objectMeta, spec: new V1ServiceSpec(type: serviceType, ports: portList, selector: labels))));
            }
            else
            {
                return(Option.None <V1Service>());
            }
        }
Esempio n. 28
0
        internal static IEnumerable <EnvVar> GetEnvVars(IDictionary <string, EnvVal> moduleEnvVars, IModuleIdentity identity, IConfigSource configSource)
        {
            List <EnvVar> envVars = moduleEnvVars.Select(m => new EnvVar {
                Key = m.Key, Value = m.Value.Value
            }).ToList();

            // Inject the connection details as an environment variable
            if (identity.Credentials is IdentityProviderServiceCredentials creds)
            {
                if (!string.IsNullOrWhiteSpace(creds.ProviderUri))
                {
                    envVars.Add(new EnvVar {
                        Key = Constants.EdgeletWorkloadUriVariableName, Value = creds.ProviderUri
                    });
                }

                if (!string.IsNullOrWhiteSpace(creds.AuthScheme))
                {
                    envVars.Add(new EnvVar {
                        Key = Constants.EdgeletAuthSchemeVariableName, Value = creds.AuthScheme
                    });
                }

                if (!string.IsNullOrWhiteSpace(creds.ModuleGenerationId))
                {
                    envVars.Add(new EnvVar {
                        Key = Constants.EdgeletModuleGenerationIdVariableName, Value = creds.ModuleGenerationId
                    });
                }
            }

            if (!string.IsNullOrWhiteSpace(identity.IotHubHostname))
            {
                envVars.Add(new EnvVar {
                    Key = Constants.IotHubHostnameVariableName, Value = identity.IotHubHostname
                });
            }

            if (!string.IsNullOrWhiteSpace(identity.GatewayHostname))
            {
                if (identity.ModuleId.Equals(Constants.EdgeAgentModuleIdentityName) || identity.ModuleId.Equals(Constants.EdgeHubModuleIdentityName))
                {
                    envVars.Add(
                        new EnvVar
                    {
                        Key   = Constants.EdgeDeviceHostNameKey,
                        Value = identity.GatewayHostname
                    });
                }
                else if (!identity.ModuleId.Equals(Constants.EdgeHubModuleIdentityName))
                {
                    envVars.Add(
                        new EnvVar
                    {
                        Key   = Constants.GatewayHostnameVariableName,
                        Value = identity.GatewayHostname
                    });
                }
            }

            if (!string.IsNullOrWhiteSpace(identity.DeviceId))
            {
                envVars.Add(new EnvVar {
                    Key = Constants.DeviceIdVariableName, Value = identity.DeviceId
                });
            }

            if (!string.IsNullOrWhiteSpace(identity.ModuleId))
            {
                envVars.Add(new EnvVar {
                    Key = Constants.ModuleIdVariableName, Value = identity.ModuleId
                });
            }

            if (!envVars.Exists(e => e.Key == Logger.RuntimeLogLevelEnvKey))
            {
                envVars.Add(new EnvVar {
                    Key = Logger.RuntimeLogLevelEnvKey, Value = Logger.GetLogLevel().ToString()
                });
            }

            configSource.Configuration.GetValue <string>(Constants.UpstreamProtocolKey).ToUpstreamProtocol().ForEach(
                u =>
            {
                if (!envVars.Any(e => e.Key.Equals(Constants.UpstreamProtocolKey, StringComparison.OrdinalIgnoreCase)))
                {
                    envVars.Add(new EnvVar {
                        Key = Constants.UpstreamProtocolKey, Value = u.ToString()
                    });
                }
            });

            if (identity.ModuleId.Equals(Constants.EdgeAgentModuleIdentityName))
            {
                string managementUri = configSource.Configuration.GetValue <string>(Constants.EdgeletManagementUriVariableName);
                if (!string.IsNullOrEmpty(managementUri))
                {
                    envVars.Add(new EnvVar {
                        Key = Constants.EdgeletManagementUriVariableName, Value = managementUri
                    });
                }

                string networkId = configSource.Configuration.GetValue <string>(Constants.NetworkIdKey);
                if (!string.IsNullOrEmpty(networkId))
                {
                    envVars.Add(new EnvVar {
                        Key = Constants.NetworkIdKey, Value = networkId
                    });
                }

                envVars.Add(new EnvVar {
                    Key = Constants.ModeKey, Value = Constants.IotedgedMode
                });
            }

            // Set the edgelet's api version
            string apiVersion = configSource.Configuration.GetValue <string>(Constants.EdgeletApiVersionVariableName);

            if (!string.IsNullOrEmpty(apiVersion))
            {
                envVars.Add(new EnvVar {
                    Key = Constants.EdgeletApiVersionVariableName, Value = apiVersion
                });
            }

            return(envVars);
        }
Esempio n. 29
0
        public static async Task <ICommand> BuildAsync(IDockerClient client, DockerModule current, DockerModule next, IModuleIdentity identity, DockerLoggingConfig dockerLoggerConfig, IConfigSource configSource)
        {
            Preconditions.CheckNotNull(client, nameof(client));
            Preconditions.CheckNotNull(current, nameof(current));
            Preconditions.CheckNotNull(next, nameof(next));
            Preconditions.CheckNotNull(dockerLoggerConfig, nameof(dockerLoggerConfig));

            var      remove = new RemoveCommand(client, current);
            ICommand create = await CreateCommand.BuildAsync(client, next, identity, dockerLoggerConfig, configSource, next is EdgeHubDockerModule);

            return(new UpdateCommand(remove, create));
        }
Esempio n. 30
0
        V1PodTemplateSpec GetPodFromModule(Dictionary <string, string> labels, KubernetesModule <TConfig> module, IModuleIdentity moduleIdentity)
        {
            if (module is IModule <AgentDocker.CombinedDockerConfig> moduleWithDockerConfig)
            {
                // pod labels
                var podLabels = new Dictionary <string, string>(labels);

                // pod annotations
                var podAnnotations = new Dictionary <string, string>();
                podAnnotations.Add(Constants.K8sEdgeOriginalModuleId, moduleIdentity.ModuleId);
                // Convert docker labels to annotations because docker labels don't have the same restrictions as
                // Kuberenetes labels.
                if (moduleWithDockerConfig.Config.CreateOptions?.Labels != null)
                {
                    foreach (KeyValuePair <string, string> label in moduleWithDockerConfig.Config.CreateOptions?.Labels)
                    {
                        podAnnotations.Add(KubeUtils.SanitizeAnnotationKey(label.Key), label.Value);
                    }
                }

                // Per container settings:
                // exposed ports
                Option <List <V1ContainerPort> > exposedPortsOption = (moduleWithDockerConfig.Config?.CreateOptions?.ExposedPorts != null)
                    ? this.GetExposedPorts(moduleWithDockerConfig.Config.CreateOptions.ExposedPorts).Map(
                    servicePorts =>
                    servicePorts.Select(tuple => new V1ContainerPort(tuple.Port, protocol: tuple.Protocol)).ToList())
                    : Option.None <List <V1ContainerPort> >();

                // privileged container
                Option <V1SecurityContext> securityContext = (moduleWithDockerConfig.Config?.CreateOptions?.HostConfig?.Privileged == true) ? Option.Some(new V1SecurityContext(privileged: true)) : Option.None <V1SecurityContext>();

                // Environment Variables.
                List <V1EnvVar> env = this.CollectEnv(moduleWithDockerConfig, (KubernetesModuleIdentity)moduleIdentity);

                // Bind mounts
                (List <V1Volume> volumeList, List <V1VolumeMount> proxyMounts, List <V1VolumeMount> volumeMountList) = this.GetVolumesFromModule(moduleWithDockerConfig).GetOrElse((null, null, null));

                // Image
                string moduleImage = moduleWithDockerConfig.Config.Image;

                var containerList = new List <V1Container>()
                {
                    new V1Container(
                        KubeUtils.SanitizeDNSValue(moduleIdentity.ModuleId),
                        env: env,
                        image: moduleImage,
                        volumeMounts: volumeMountList,
                        securityContext: securityContext.GetOrElse(() => null),
                        ports: exposedPortsOption.GetOrElse(() => null)),

                    // TODO: Add Proxy container here - configmap for proxy configuration.
                    new V1Container(
                        "proxy",
                        env: env, // TODO: check these for validity for proxy.
                        image: this.proxyImage,
                        volumeMounts: proxyMounts)
                };

                Option <List <V1LocalObjectReference> > imageSecret = moduleWithDockerConfig.Config.AuthConfig.Map(
                    auth =>
                {
                    var secret   = new ImagePullSecret(auth);
                    var authList = new List <V1LocalObjectReference>
                    {
                        new V1LocalObjectReference(secret.Name)
                    };
                    return(authList);
                });

                var modulePodSpec = new V1PodSpec(containerList, volumes: volumeList, imagePullSecrets: imageSecret.GetOrElse(() => null));
                var objectMeta    = new V1ObjectMeta(labels: podLabels, annotations: podAnnotations);
                return(new V1PodTemplateSpec(metadata: objectMeta, spec: modulePodSpec));
            }
            else
            {
                Events.InvalidModuleType(module);
            }

            return(new V1PodTemplateSpec());
        }