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); } }
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); }
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); } } }
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)); } }