public void Create_AlwaysTrue_ReturnsNull() { Assert.Null(LabelSelector.Create <V1Pod>(s => true)); }
public void FromDictionary_EmptyDictionary_ReturnsEmptySelector() { Assert.Equal(string.Empty, LabelSelector.Create(new Dictionary <string, string>())); }
public void Create_Null_ReturnsNull() { Assert.Null(LabelSelector.Create <V1Pod>(null)); }
public void NotAKubeType_ReturnsNull() { Assert.Null(LabelSelector.Create <CustomObject>(s => s.Child.Metadata.Labels[Annotations.ManagedBy] == "test")); }
public void FromDictionary_ValidatesArgument() { Assert.Throws <ArgumentNullException>("values", () => LabelSelector.Create((Dictionary <string, string>)null)); }
public void Create_LabelNameNotConstant_ReturnsNull() { Assert.Null(LabelSelector.Create <V1Pod>(p => p.Metadata.Labels["a".ToString()] == "b")); }
public void Create_CustomType_Works() { Assert.Equal("app.kubernetes.io/managed-by=test", LabelSelector.Create <WebDriverSession>(s => s.Metadata.Labels[Annotations.ManagedBy] == "test")); }
public void Create_LabelOnNonParam_ReturnsNull() { Assert.Null(LabelSelector.Create <V1Pod>(p => new V1Pod().Metadata.Labels["a"] == "b")); }
public void Create_MethodCallOnWrongProperty2_ReturnsNull() { Assert.Null(LabelSelector.Create <V1Pod>(p => p.Metadata.ManagedFields.ToString() == "b")); }
public void Create_MethodCallOnWrongProperty_ReturnsNull() { Assert.Null(LabelSelector.Create <V1Pod>(p => p.Spec.NodeSelector["a"] == "a")); }
public void Create_MethodCallOnWrongType_ReturnsNull() { Assert.Null(LabelSelector.Create <V1Pod>(p => p.Metadata.Labels.ToString() == "a")); }
public void Create_ValueNotConstant_Throws() { Assert.Throws <ArgumentOutOfRangeException>( () => LabelSelector.Create <V1Pod>( p => p.Metadata.Labels[Annotations.Os] == p.ToString())); }
/// <summary> /// Asynchronously reconciles the devices returned by the iOS device multiplexor with the devices available in the cluster. /// </summary> /// <param name="cancellationToken"> /// A <see cref="CancellationToken"/> which can be used to cancel the asynchronous operation. /// </param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public virtual async Task ReconcileAsync(CancellationToken cancellationToken) { // We list: // - Only devices which are managed by _this_ usbmuxd instance. All those devices should have this pod // set at their owner, but there isn't a straightforward way to filter on owner. // Hence, we use a label selector for that. // - Only usbmuxd devices try { this.logger.LogInformation("Running an reconcilation loop for pod {podName}", this.configuration.PodName); var parent = await this.kubernetesClient.GetClient <V1Pod>().TryReadAsync(this.configuration.PodName, cancellationToken).ConfigureAwait(false); if (parent == null) { throw new InvalidOperationException($"Could not find the parent pod {this.configuration.PodName}"); } this.logger.LogInformation("Listing all devices in the Kubernetes cluster."); var kubernetesDevices = await this.deviceClient.ListAsync( labelSelector : LabelSelector.Create( new Dictionary <string, string>() { // Do not filter on 'instance': devices may move from one host to another, // and the instance ID will change for the same host if the pod is recreated. { Annotations.Os, Annotations.OperatingSystem.iOS }, { Annotations.ManagedBy, nameof(UsbmuxdSidecar) }, }), cancellationToken : cancellationToken); this.logger.LogInformation("Found {count} Kubernetes devices", kubernetesDevices.Items.Count); this.logger.LogInformation("Listing all usbmuxd devices"); var muxerDevices = await this.muxerClient.ListDevicesAsync(cancellationToken).ConfigureAwait(false); this.logger.LogInformation("Found {count} usbmuxd devices", muxerDevices.Count); foreach (var muxerDevice in muxerDevices) { this.logger.LogInformation("Processing device {device}", muxerDevice.Udid); var kubernetesDevice = kubernetesDevices.Items.SingleOrDefault(d => string.Equals(d.Metadata.Name, muxerDevice.Udid, StringComparison.OrdinalIgnoreCase)); if (kubernetesDevice == null) { this.logger.LogInformation("Creating a new device {device}", muxerDevice.Udid); // Register the device kubernetesDevice = new MobileDevice() { Metadata = new V1ObjectMeta() { Labels = new Dictionary <string, string>() { { Annotations.Os, Annotations.OperatingSystem.iOS }, { Annotations.ManagedBy, nameof(UsbmuxdSidecar) }, { Annotations.Instance, this.configuration.PodName }, }, Name = muxerDevice.Udid, NamespaceProperty = this.kubernetesClient.Options.Namespace, OwnerReferences = parent == null ? null : new V1OwnerReference[] { parent.AsOwnerReference(blockOwnerDeletion: false, controller: false), }, }, Spec = new MobileDeviceSpec() { Owner = this.configuration.PodName, }, Status = new MobileDeviceStatus() { Conditions = new List <MobileDeviceCondition>() { new MobileDeviceCondition() { Type = "Ready", Status = ConditionStatus.False, LastHeartbeatTime = DateTimeOffset.Now, LastTransitionTime = DateTimeOffset.Now, Message = "New", Reason = "Newly discovered device", }, }, }, }; kubernetesDevice = await this.deviceClient.CreateAsync(kubernetesDevice, cancellationToken).ConfigureAwait(false); } else { this.logger.LogInformation("The device {device} already exists; no action needed.", muxerDevice.Udid); // Nothing to do; though we could verify the properties. kubernetesDevices.Items.Remove(kubernetesDevice); } var pairingRecord = await this.pairingRecordProvisioner.ProvisionPairingRecordAsync(muxerDevice.Udid, cancellationToken).ConfigureAwait(false); if (pairingRecord == null) { this.logger.LogWarning("The host has not paired with device {device}.", muxerDevice.Udid); await this.deviceClient.SetDeviceConditionAsync(kubernetesDevice, MobileDeviceConditions.Paired, ConditionStatus.False, "NotTrusted", "The device has not trusted the host.", cancellationToken); } else { this.logger.LogInformation("The host has paired with device {device}.", muxerDevice.Udid); await this.deviceClient.SetDeviceConditionAsync(kubernetesDevice, MobileDeviceConditions.Paired, ConditionStatus.True, "Trusted", "The device has trusted the host.", cancellationToken); } if (await this.developerDiskProvisioner.ProvisionDeveloperDiskAsync(muxerDevice, cancellationToken).ConfigureAwait(false)) { this.logger.LogInformation("The developer disk was mounted on device {device}.", muxerDevice.Udid); await this.deviceClient.SetDeviceConditionAsync(kubernetesDevice, MobileDeviceConditions.DeveloperDiskMounted, ConditionStatus.True, "Mounted", "The developer disk was mounted on the device.", cancellationToken); } else { this.logger.LogWarning("The developer disk was not mounted on device {device}.", muxerDevice.Udid); await this.deviceClient.SetDeviceConditionAsync(kubernetesDevice, MobileDeviceConditions.DeveloperDiskMounted, ConditionStatus.False, "NotMounted", "The developer disk was not mounted on the device.", cancellationToken); } } // All live usbmuxd devices have been removed from muxerDevice.Items by the loop above. The remaining // devices are stale; remove them. foreach (var kubernetesDevice in kubernetesDevices.Items) { this.logger.LogInformation("Removing stale device {device}.", kubernetesDevice.Metadata.Name); await this.deviceClient.DeleteAsync(kubernetesDevice, TimeSpan.FromMinutes(1), cancellationToken).ConfigureAwait(false); } } catch (Exception ex) { this.logger.LogError(ex, "An error occurred while running the reconciliation loop. {message}", ex.Message); throw; } }
/// <summary> /// Configures the operator to only consider parent items which have certain labels applied to them. /// </summary> /// <param name="labelSelector"> /// An expression which represents the label selector. /// </param> /// <returns> /// A builder which can be used to further configure the operator. /// </returns> public ChildOperatorBuilder <TParent> WithLabels( Expression <Func <TParent, bool> > labelSelector) { return(this.WithLabels(LabelSelector.Create(labelSelector))); }