Beispiel #1
0
 public void Create_AlwaysTrue_ReturnsNull()
 {
     Assert.Null(LabelSelector.Create <V1Pod>(s => true));
 }
Beispiel #2
0
 public void FromDictionary_EmptyDictionary_ReturnsEmptySelector()
 {
     Assert.Equal(string.Empty, LabelSelector.Create(new Dictionary <string, string>()));
 }
Beispiel #3
0
 public void Create_Null_ReturnsNull()
 {
     Assert.Null(LabelSelector.Create <V1Pod>(null));
 }
Beispiel #4
0
 public void NotAKubeType_ReturnsNull()
 {
     Assert.Null(LabelSelector.Create <CustomObject>(s => s.Child.Metadata.Labels[Annotations.ManagedBy] == "test"));
 }
Beispiel #5
0
 public void FromDictionary_ValidatesArgument()
 {
     Assert.Throws <ArgumentNullException>("values", () => LabelSelector.Create((Dictionary <string, string>)null));
 }
Beispiel #6
0
 public void Create_LabelNameNotConstant_ReturnsNull()
 {
     Assert.Null(LabelSelector.Create <V1Pod>(p => p.Metadata.Labels["a".ToString()] == "b"));
 }
Beispiel #7
0
 public void Create_CustomType_Works()
 {
     Assert.Equal("app.kubernetes.io/managed-by=test", LabelSelector.Create <WebDriverSession>(s => s.Metadata.Labels[Annotations.ManagedBy] == "test"));
 }
Beispiel #8
0
 public void Create_LabelOnNonParam_ReturnsNull()
 {
     Assert.Null(LabelSelector.Create <V1Pod>(p => new V1Pod().Metadata.Labels["a"] == "b"));
 }
Beispiel #9
0
 public void Create_MethodCallOnWrongProperty2_ReturnsNull()
 {
     Assert.Null(LabelSelector.Create <V1Pod>(p => p.Metadata.ManagedFields.ToString() == "b"));
 }
Beispiel #10
0
 public void Create_MethodCallOnWrongProperty_ReturnsNull()
 {
     Assert.Null(LabelSelector.Create <V1Pod>(p => p.Spec.NodeSelector["a"] == "a"));
 }
Beispiel #11
0
 public void Create_MethodCallOnWrongType_ReturnsNull()
 {
     Assert.Null(LabelSelector.Create <V1Pod>(p => p.Metadata.Labels.ToString() == "a"));
 }
Beispiel #12
0
 public void Create_ValueNotConstant_Throws()
 {
     Assert.Throws <ArgumentOutOfRangeException>(
         () => LabelSelector.Create <V1Pod>(
             p => p.Metadata.Labels[Annotations.Os] == p.ToString()));
 }
Beispiel #13
0
        /// <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;
            }
        }
Beispiel #14
0
 /// <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)));
 }