Beispiel #1
0
        async Task ReportDeploymentFailure(Exception ex, EdgeDeploymentDefinition item)
        {
            var status = EdgeDeploymentStatus.Failure(ex);

            await this.ReportEdgeDeploymentStatus(item, status);

            this.currentStatus = status;
        }
        public EdgeDeploymentOperator(
            ResourceName resourceName,
            string deviceNamespace,
            IKubernetes client,
            IEdgeDeploymentController controller)
        {
            this.deviceNamespace = Preconditions.CheckNonWhiteSpace(deviceNamespace, nameof(deviceNamespace));
            this.resourceName    = Preconditions.CheckNotNull(resourceName, nameof(resourceName));

            this.client        = Preconditions.CheckNotNull(client, nameof(client));
            this.operatorWatch = Option.None <Watcher <EdgeDeploymentDefinition> >();
            this.controller    = Preconditions.CheckNotNull(controller, nameof(controller));

            this.serializerSettings = EdgeDeploymentSerialization.SerializerSettings;
            this.currentModules     = ModuleSet.Empty;
            this.currentStatus      = DefaultStatus;
        }
        async Task HandleEdgeDeploymentChangedAsync(WatchEventType type, EdgeDeploymentDefinition edgeDeploymentDefinition)
        {
            // only operate on the device that matches this operator.
            if (!this.resourceName.Equals(edgeDeploymentDefinition.Metadata.Name))
            {
                Events.DeploymentNameMismatch(edgeDeploymentDefinition.Metadata.Name, this.resourceName);
                return;
            }

            Events.DeploymentStatus(type, this.resourceName);
            switch (type)
            {
            case WatchEventType.Added:
            case WatchEventType.Modified:
                var desiredModules = ModuleSet.Create(edgeDeploymentDefinition.Spec.ToArray());
                var status         = await this.controller.DeployModulesAsync(desiredModules, this.currentModules);

                await this.ReportEdgeDeploymentStatus(edgeDeploymentDefinition, status);

                this.currentModules = desiredModules;
                this.currentStatus  = status;
                break;

            case WatchEventType.Deleted:
                await this.controller.PurgeModulesAsync();

                this.currentModules = ModuleSet.Empty;
                this.currentStatus  = DefaultStatus;
                break;

            case WatchEventType.Error:
                Events.DeploymentError();
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(type), type, null);
            }
        }
Beispiel #4
0
 public EdgeDeploymentDefinition(string apiVersion, string kind, V1ObjectMeta metadata, IReadOnlyList <KubernetesModule> spec, EdgeDeploymentStatus status = null)
 {
     this.ApiVersion = Preconditions.CheckNonWhiteSpace(apiVersion, nameof(apiVersion));
     this.Kind       = Preconditions.CheckNonWhiteSpace(kind, nameof(kind));
     this.Metadata   = Preconditions.CheckNotNull(metadata, nameof(metadata));
     this.Spec       = Preconditions.CheckNotNull(spec, nameof(spec));
     this.Status     = Option.Maybe(status);
 }
Beispiel #5
0
        async Task ReportEdgeDeploymentStatus(EdgeDeploymentDefinition edgeDeploymentDefinition, EdgeDeploymentStatus status)
        {
            if (!status.Equals(this.currentStatus))
            {
                var edgeDeploymentStatus = new EdgeDeploymentDefinition(
                    edgeDeploymentDefinition.ApiVersion,
                    edgeDeploymentDefinition.Kind,
                    edgeDeploymentDefinition.Metadata,
                    edgeDeploymentDefinition.Spec,
                    status);

                var crdObject = JObject.FromObject(edgeDeploymentStatus, JsonSerializer.Create(this.serializerSettings));

                try
                {
                    await this.client.ReplaceNamespacedCustomObjectStatusWithHttpMessagesAsync(
                        crdObject,
                        KubernetesConstants.EdgeDeployment.Group,
                        KubernetesConstants.EdgeDeployment.Version,
                        this.deviceNamespace,
                        KubernetesConstants.EdgeDeployment.Plural,
                        this.resourceName);
                }
                catch (HttpOperationException e)
                {
                    Events.DeploymentStatusFailed(e);
                }
            }
        }
Beispiel #6
0
        public async Task <EdgeDeploymentStatus> DeployModulesAsync(ModuleSet desiredModules, ModuleSet currentModules)
        {
            try
            {
                var moduleIdentities = await this.moduleIdentityLifecycleManager.GetModuleIdentitiesAsync(desiredModules, currentModules);

                var labels = desiredModules.Modules
                             .ToDictionary(
                    module => module.Key,
                    module => new Dictionary <string, string>
                {
                    [KubernetesConstants.K8sEdgeModuleLabel]  = moduleIdentities[module.Key].DeploymentName(),
                    [KubernetesConstants.K8sEdgeDeviceLabel]  = KubeUtils.SanitizeLabelValue(this.resourceName.DeviceId),
                    [KubernetesConstants.K8sEdgeHubNameLabel] = KubeUtils.SanitizeLabelValue(this.resourceName.Hostname)
                });
                var deviceOnlyLabels = new Dictionary <string, string>
                {
                    [KubernetesConstants.K8sEdgeDeviceLabel]  = KubeUtils.SanitizeLabelValue(this.resourceName.DeviceId),
                    [KubernetesConstants.K8sEdgeHubNameLabel] = KubeUtils.SanitizeLabelValue(this.resourceName.Hostname)
                };

                var desiredServices = desiredModules.Modules
                                      .Select(module => this.serviceMapper.CreateService(moduleIdentities[module.Key], module.Value as KubernetesModule, labels[module.Key]))
                                      .FilterMap()
                                      .ToList();

                V1ServiceList currentServices = await this.client.ListNamespacedServiceAsync(this.deviceNamespace, labelSelector : this.deploymentSelector);

                await this.ManageServices(currentServices, desiredServices);

                var desiredDeployments = desiredModules.Modules
                                         .Select(module => this.deploymentMapper.CreateDeployment(moduleIdentities[module.Key], module.Value as KubernetesModule, labels[module.Key]))
                                         .ToList();

                V1DeploymentList currentDeployments = await this.client.ListNamespacedDeploymentAsync(this.deviceNamespace, labelSelector : this.deploymentSelector);

                await this.ManageDeployments(currentDeployments, desiredDeployments);

                var desiredPvcs = desiredModules.Modules
                                  .Select(module => this.pvcMapper.CreatePersistentVolumeClaims(module.Value as KubernetesModule, deviceOnlyLabels))
                                  .FilterMap()
                                  .SelectMany(x => x)
                                  .Distinct(KubernetesPvcByValueEqualityComparer);

                // Modules may use PVCs created by the user, we get all PVCs and then work on ours.
                V1PersistentVolumeClaimList currentPvcList = await this.client.ListNamespacedPersistentVolumeClaimAsync(this.deviceNamespace);

                await this.ManagePvcs(currentPvcList, desiredPvcs);

                var desiredServiceAccounts = desiredModules.Modules
                                             .Select(module => this.serviceAccountMapper.CreateServiceAccount(moduleIdentities[module.Key], labels[module.Key]))
                                             .ToList();

                V1ServiceAccountList currentServiceAccounts = await this.client.ListNamespacedServiceAccountAsync(this.deviceNamespace, labelSelector : this.deploymentSelector);

                await this.ManageServiceAccounts(currentServiceAccounts, desiredServiceAccounts);

                return(EdgeDeploymentStatus.Success("Successfully deployed"));
            }
            catch (HttpOperationException e)
            {
                return(EdgeDeploymentStatus.Failure(e));
            }
        }
        public async Task <EdgeDeploymentStatus> DeployModulesAsync(ModuleSet desiredModules, ModuleSet currentModules)
        {
            try
            {
                var moduleIdentities = await this.moduleIdentityLifecycleManager.GetModuleIdentitiesAsync(desiredModules, currentModules);

                // having desired modules an no module identities means that we are unable to obtain a list of module identities
                if (desiredModules.Modules.Any() && !moduleIdentities.Any())
                {
                    Events.NoModuleIdentities();
                    return(EdgeDeploymentStatus.Failure("Unable to obtain identities for desired modules"));
                }

                var labels = desiredModules.Modules
                             .ToDictionary(
                    module => module.Key,
                    module => new Dictionary <string, string>
                {
                    [KubernetesConstants.K8sEdgeModuleLabel]  = moduleIdentities[module.Key].DeploymentName(),
                    [KubernetesConstants.K8sEdgeDeviceLabel]  = KubeUtils.SanitizeLabelValue(this.resourceName.DeviceId),
                    [KubernetesConstants.K8sEdgeHubNameLabel] = KubeUtils.SanitizeLabelValue(this.resourceName.Hostname)
                });
                var deviceOnlyLabels = new Dictionary <string, string>
                {
                    [KubernetesConstants.K8sEdgeDeviceLabel]  = KubeUtils.SanitizeLabelValue(this.resourceName.DeviceId),
                    [KubernetesConstants.K8sEdgeHubNameLabel] = KubeUtils.SanitizeLabelValue(this.resourceName.Hostname)
                };

                var desiredServiceAccounts = desiredModules.Modules
                                             .Select(module => this.serviceAccountMapper.CreateServiceAccount((KubernetesModule)module.Value, moduleIdentities[module.Key], labels[module.Key]))
                                             .ToList();

                V1ServiceAccountList currentServiceAccounts = await this.client.ListNamespacedServiceAccountAsync(this.deviceNamespace, labelSelector : this.deviceSelector);

                await this.ManageServiceAccounts(currentServiceAccounts, desiredServiceAccounts);

                var desiredServices = desiredModules.Modules
                                      .Select(module => this.serviceMapper.CreateService(moduleIdentities[module.Key], (KubernetesModule)module.Value, labels[module.Key]))
                                      .FilterMap()
                                      .ToList();

                V1ServiceList currentServices = await this.client.ListNamespacedServiceAsync(this.deviceNamespace, labelSelector : this.deviceSelector);

                await this.ManageServices(currentServices, desiredServices);

                var desiredDeployments = desiredModules.Modules
                                         .Select(module => this.deploymentMapper.CreateDeployment(moduleIdentities[module.Key], (KubernetesModule)module.Value, labels[module.Key]))
                                         .ToList();

                V1DeploymentList currentDeployments = await this.client.ListNamespacedDeploymentAsync(this.deviceNamespace, labelSelector : this.deviceSelector);

                await this.ManageDeployments(currentDeployments, desiredDeployments);

                var desiredPvcs = desiredModules.Modules
                                  .Select(module => this.pvcMapper.CreatePersistentVolumeClaims((KubernetesModule)module.Value, deviceOnlyLabels))
                                  .FilterMap()
                                  .SelectMany(x => x)
                                  .GroupBy(x => x.Metadata.Name)
                                  .Select(x => x.First());

                // Modules may use PVCs created by the user, we get all PVCs and then work on ours.
                V1PersistentVolumeClaimList currentPvcList = await this.client.ListNamespacedPersistentVolumeClaimAsync(this.deviceNamespace);

                await this.ManagePvcs(currentPvcList, desiredPvcs);

                return(EdgeDeploymentStatus.Success("Successfully deployed"));
            }
            catch (HttpOperationException e)
            {
                Events.DeployModulesException(e);
                return(EdgeDeploymentStatus.Failure(e));
            }
        }