예제 #1
0
        /// <summary>
        ///     Ensure that an externally-facing Service resource does not exist for the specified database server.
        /// </summary>
        public async Task EnsureExternalServiceAbsent()
        {
            RequireCurrentState();

            ServiceV1 existingExternalService = await FindExternalService();

            if (existingExternalService != null)
            {
                Log.LogInformation("Deleting external service {ServiceName} for server {ServerId}...",
                                   existingExternalService.Metadata.Name,
                                   State.Id
                                   );

                StatusV1 result = await KubeClient.ServicesV1().Delete(
                    name: existingExternalService.Metadata.Name,
                    kubeNamespace: KubeOptions.KubeNamespace
                    );

                if (result.Status != "Success" && result.Reason != "NotFound")
                {
                    Log.LogError("Failed to delete external service {ServiceName} for server {ServerId} (Message:{FailureMessage}, Reason:{FailureReason}).",
                                 existingExternalService.Metadata.Name,
                                 State.Id,
                                 result.Message,
                                 result.Reason
                                 );
                }

                Log.LogInformation("Deleted external service {ServiceName} for server {ServerId}.",
                                   existingExternalService.Metadata.Name,
                                   State.Id
                                   );
            }
        }
예제 #2
0
        /// <summary>
        ///     Get a single resource, returning <c>null</c> if it does not exist.
        /// </summary>
        /// <typeparam name="TResource">
        ///     The type of resource to retrieve.
        /// </typeparam>
        /// <param name="request">
        ///     An <see cref="HttpRequest"/> representing the resource to retrieve.
        /// </param>
        /// <param name="cancellationToken">
        ///     An optional <see cref="CancellationToken"/> that can be used to cancel the request.
        /// </param>
        /// <returns>
        ///     A <typeparamref name="TResource"/> representing the current state for the resource, or <c>null</c> if no resource was found with the specified name and namespace.
        /// </returns>
        protected async Task <TResource> GetSingleResource <TResource>(HttpRequest request, CancellationToken cancellationToken = default)
            where TResource : class
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            using (HttpResponseMessage responseMessage = await Http.GetAsync(request, cancellationToken))
            {
                if (responseMessage.IsSuccessStatusCode)
                {
                    return(await responseMessage.ReadContentAsAsync <TResource>());
                }

                // Ensure that HttpStatusCode.NotFound actually refers to the ReplicationController.
                StatusV1 status = await responseMessage.ReadContentAsAsync <StatusV1, StatusV1>(HttpStatusCode.NotFound);

                if (status.Reason != "NotFound")
                {
                    throw new HttpRequestException <StatusV1>(responseMessage.StatusCode, status);
                }

                return(null);
            }
        }
예제 #3
0
        /// <summary>
        ///     Create a new <see cref="KubeApiException"/> using the information contained in a Kubernetes status model.
        /// </summary>
        /// <param name="status">
        ///     The Kubernetes <see ref="StatusV1"/> model.
        /// </param>
        /// <param name="innerException">
        ///     The exception that caused the current exception to be raised.
        /// </param>
        public KubeApiException(StatusV1 status, Exception innerException)
            : base(GetExceptionMessage(status), innerException)
        {
            if (innerException == null)
            {
                throw new ArgumentNullException(nameof(innerException));
            }

            Status = status;
        }
예제 #4
0
        /// <summary>
        ///     Check if an error was encountered in an event stream.
        /// </summary>
        /// <param name="line">
        ///     The current line in the event stream.
        /// </param>
        /// <param name="operationDescription">
        ///     A short description of the operation being performed (used in exception message if an error is encountered).
        /// </param>
        static void CheckForEventError(string line, string operationDescription)
        {
            JToken watchEvent = JToken.Parse(line);

            if (!watchEvent.SelectToken("type").Value <string>().Equals("error", StringComparison.OrdinalIgnoreCase))
            {
                return;
            }

            StatusV1 status = watchEvent.SelectToken("object").ToObject <StatusV1>();

            throw new KubeApiException($"Unable to {operationDescription}.", status);
        }
        public void PodV1Result_From_FailureStatus_ImplicitCast_Status()
        {
            var result = new KubeResourceResultV1 <PodV1>(new StatusV1
            {
                Status  = "Failure",
                Message = "Most definitely not a success."
            });

            StatusV1 status = result;

            Assert.NotNull(status);
            Assert.Equal("Failure", status.Status);
            Assert.Equal("Most definitely not a success.", status.Message);
        }
예제 #6
0
        /// <summary>
        ///     Generate an exception message from a Kubernetes status model.
        /// </summary>
        /// <param name="status">
        ///     The Kubernetes <see cref="StatusV1"/> model.
        /// </param>
        /// <returns>
        ///     The exception message.
        /// </returns>
        protected static string GetExceptionMessage(StatusV1 status)
        {
            if (status == null)
            {
                return(DefaultMessage);
            }

            if (!String.IsNullOrWhiteSpace(status.Reason))
            {
                return($"{status.Reason}: {status.Message}");
            }

            if (!String.IsNullOrWhiteSpace(status.Message))
            {
                return(status.Message);
            }

            return(DefaultMessage);
        }
예제 #7
0
        /// <summary>
        ///     Ensure that a ServiceMonitor resource does not exist for the specified database server.
        /// </summary>
        public async Task EnsureServiceMonitorAbsent()
        {
            RequireCurrentState();

            if (State.Kind != DatabaseServerKind.SqlServer)
            {
                Log.LogInformation("Skipping monitoring configuration for server {ServerId} (not SQL Server).", State.Id);

                return;
            }

            PrometheusServiceMonitorV1 existingServiceMonitor = await FindServiceMonitor();

            if (existingServiceMonitor != null)
            {
                Log.LogInformation("Deleting service monitor {ServiceName} for server {ServerId}...",
                                   existingServiceMonitor.Metadata.Name,
                                   State.Id
                                   );

                StatusV1 result = await KubeClient.PrometheusServiceMonitorsV1().Delete(
                    name: existingServiceMonitor.Metadata.Name,
                    kubeNamespace: KubeOptions.KubeNamespace
                    );

                if (result.Status != "Success" && result.Reason != "NotFound")
                {
                    Log.LogError("Failed to delete service monitor {ServiceName} for server {ServerId} (Message:{FailureMessage}, Reason:{FailureReason}).",
                                 existingServiceMonitor.Metadata.Name,
                                 State.Id,
                                 result.Message,
                                 result.Reason
                                 );
                }

                Log.LogInformation("Deleted service monitor {ServiceName} for server {ServerId}.",
                                   existingServiceMonitor.Metadata.Name,
                                   State.Id
                                   );
            }
        }
예제 #8
0
        /// <summary>
        ///     Get a single resource, returning <c>null</c> if it does not exist.
        /// </summary>
        /// <typeparam name="TResource">
        ///     The type of resource to retrieve.
        /// </typeparam>
        /// <param name="request">
        ///     An <see cref="HttpRequest"/> representing the resource to retrieve.
        /// </param>
        /// <param name="cancellationToken">
        ///     An optional <see cref="CancellationToken"/> that can be used to cancel the request.
        /// </param>
        /// <returns>
        ///     A <typeparamref name="TResource"/> representing the current state for the resource, or <c>null</c> if no resource was found with the specified name and namespace.
        /// </returns>
        protected async Task <TResource> GetSingleResource <TResource>(HttpRequest request, CancellationToken cancellationToken = default)
            where TResource : KubeResourceV1
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            using (HttpResponseMessage responseMessage = await Http.GetAsync(request, cancellationToken).ConfigureAwait(false))
            {
                if (responseMessage.IsSuccessStatusCode)
                {
                    return(await responseMessage.ReadContentAsAsync <TResource>().ConfigureAwait(false));
                }

                // Ensure that HttpStatusCode.NotFound actually refers to the target resource.
                StatusV1 status = await responseMessage.ReadContentAsStatusV1Async(HttpStatusCode.NotFound).ConfigureAwait(false);

                if (status.Reason == "NotFound")
                {
                    return(null);
                }

                // If possible, tell the consumer which resource type we had a problem with (helpful when all you find is the error message in the log).
                (string itemKind, string itemApiVersion) = KubeObjectV1.GetKubeKind <TResource>();
                string resourceTypeDescription =
                    !String.IsNullOrWhiteSpace(itemKind)
                        ? $"{itemKind} ({itemApiVersion}) resource"
                        : typeof(TResource).Name;

                throw new KubeApiException($"Unable to retrieve {resourceTypeDescription} (HTTP status {responseMessage.StatusCode}).",
                                           innerException: new HttpRequestException <StatusV1>(responseMessage.StatusCode,
                                                                                               response: await responseMessage.ReadContentAsStatusV1Async(responseMessage.StatusCode).ConfigureAwait(false)
                                                                                               )
                                           );
            }
        }
예제 #9
0
 /// <summary>
 ///     Create a new <see cref="KubeClientException"/> using the information contained in a Kubernetes status model.
 /// </summary>
 /// <param name="status">
 ///     The Kubernetes <see ref="StatusV1"/> model.
 /// </param>
 public KubeClientException(StatusV1 status)
     : base(GetExceptionMessage(status))
 {
     Status = status;
 }
예제 #10
0
 /// <summary>
 ///     Create a new <see cref="KubeApiException"/> using the information contained in a Kubernetes status model.
 /// </summary>
 /// <param name="message">
 ///     The exception message.
 /// </param>
 /// <param name="status">
 ///     The Kubernetes <see ref="StatusV1"/> model.
 /// </param>
 public KubeApiException(string message, StatusV1 status)
     : base(message + Environment.NewLine + GetExceptionMessage(status))
 {
     Status = status;
 }
예제 #11
0
        public unsafe CombatantV1 GetCombatantFromByteArray(byte[] source, int combatantsListNumber)
        {
            int         offset    = 0;
            CombatantV1 combatant = new CombatantV1();

            fixed(byte *p = source)
            {
                combatant.Name    = GetStringFromBytes(source, 48);
                combatant.ID      = *(uint *)&p[116];
                combatant.OwnerID = *(uint *)&p[132];
                if (combatant.OwnerID == 3758096384u)
                {
                    combatant.OwnerID = 0u;
                }
                combatant.type = (ObjectType)p[140];
                combatant.EffectiveDistance = p[146];

                offset            = 160;
                combatant.PosX    = *(Single *)&p[offset];
                combatant.PosZ    = *(Single *)&p[offset + 4];
                combatant.PosY    = *(Single *)&p[offset + 8];
                combatant.Heading = *(Single *)&p[offset + 16];

                /*
                 * combatantsListNumber == 0 の場合、すなわち自分自身のとき
                 * TargetID が取れないので、Targetのシグネチャから直接探して置き換える。
                 *
                 */
                if (combatantsListNumber == 0)
                {
                    CombatantV1 currentTargetCombatant              = null;
                    IntPtr      currentTargetCombatantAddress       = IntPtr.Zero;
                    byte[]      currentTargetCombatantAddressSource = GetByteArray(Pointers[PointerType.Target].Address, 128);
                    unsafe
                    {
                        fixed(byte *p2 = currentTargetCombatantAddressSource) currentTargetCombatantAddress = new IntPtr(*(Int64 *)p2);
                    }
                    if (currentTargetCombatantAddress.ToInt64() <= 0)
                    {
                        combatant.TargetID = 0;
                    }
                    byte[] currentTargetCombatantSource = GetByteArray(currentTargetCombatantAddress, combatantDataSize);
                    currentTargetCombatant = GetCombatantFromByteArray(currentTargetCombatantSource, -1);
                    combatant.TargetID     = currentTargetCombatant.ID;
                }
                else
                {
                    combatant.TargetID = *(uint *)&p[5832];
                    if (combatant.TargetID == 3758096384)
                    {
                        combatant.TargetID = 0;
                    }
                }

                offset = 5960;
                if (combatant.type == ObjectType.PC || combatant.type == ObjectType.Monster)
                {
                    combatant.CurrentHP = *(int *)&p[offset + 8];
                    combatant.MaxHP     = *(int *)&p[offset + 12];
                    combatant.CurrentMP = *(int *)&p[offset + 16];
                    combatant.MaxMP     = *(int *)&p[offset + 20];
                    combatant.CurrentTP = *(short *)&p[offset + 24];
                    combatant.MaxTP     = 1000;
                    combatant.Job       = p[offset + 64];
                    combatant.Level     = p[offset + 66];

                    // Status aka Buff,Debuff
                    combatant.Statuses = new List <StatusV1>();
                    const int StatusEffectOffset = 6152;
                    const int statusSize         = 12;

                    int statusCountLimit = 60;
                    if (combatant.type == ObjectType.PC)
                    {
                        statusCountLimit = 30;
                    }

                    var statusesSource = new byte[statusCountLimit * statusSize];
                    Buffer.BlockCopy(source, StatusEffectOffset, statusesSource, 0, statusCountLimit * statusSize);
                    for (var i = 0; i < statusCountLimit; i++)
                    {
                        var statusBytes = new byte[statusSize];
                        Buffer.BlockCopy(statusesSource, i * statusSize, statusBytes, 0, statusSize);
                        var status = new StatusV1
                        {
                            StatusID = BitConverter.ToInt16(statusBytes, 0),
                            Stacks   = statusBytes[2],
                            Duration = BitConverter.ToSingle(statusBytes, 4),
                            CasterID = BitConverter.ToUInt32(statusBytes, 8),
                            IsOwner  = false,
                        };

                        if (status.IsValid())
                        {
                            combatant.Statuses.Add(status);
                        }
                    }

                    // Cast
                    combatant.Casting = new CastV1
                    {
                        ID       = *(short *)&p[6900],
                        TargetID = *(uint *)&p[6912],
                        Progress = *(Single *)&p[6948],
                        Time     = *(Single *)&p[6952],
                    };
                }
                else
                {
                    combatant.CurrentHP                     =
                        combatant.MaxHP                     =
                            combatant.CurrentMP             =
                                combatant.MaxMP             =
                                    combatant.MaxTP         =
                                        combatant.CurrentTP = 0;
                    combatant.Statuses = new List <StatusV1>();
                    combatant.Casting  = new CastV1();
                }
            }

            return(combatant);
        }
예제 #12
0
        public unsafe CombatantV1 GetCombatantFromByteArray(byte[] source)
        {
            int         offset    = 0;
            CombatantV1 combatant = new CombatantV1();

            fixed(byte *p = source)
            {
                combatant.Name    = GetStringFromBytes(source, 48);
                combatant.ID      = *(uint *)&p[116];
                combatant.OwnerID = *(uint *)&p[132];
                if (combatant.OwnerID == 3758096384u)
                {
                    combatant.OwnerID = 0u;
                }
                combatant.type = (ObjectType)p[140];
                combatant.EffectiveDistance = p[146];

                offset            = 160;
                combatant.PosX    = *(Single *)&p[offset];
                combatant.PosZ    = *(Single *)&p[offset + 4];
                combatant.PosY    = *(Single *)&p[offset + 8];
                combatant.Heading = *(Single *)&p[offset + 16];

                combatant.TargetID = *(uint *)&p[5680];

                offset = 5808;
                if (combatant.type == ObjectType.PC || combatant.type == ObjectType.Monster)
                {
                    combatant.CurrentHP = *(int *)&p[offset + 8];
                    combatant.MaxHP     = *(int *)&p[offset + 12];
                    combatant.CurrentMP = *(int *)&p[offset + 16];
                    combatant.MaxMP     = *(int *)&p[offset + 20];
                    combatant.CurrentTP = *(short *)&p[offset + 24];
                    combatant.MaxTP     = 1000;
                    combatant.Job       = p[offset + 62];
                    combatant.Level     = p[offset + 64];

                    // Status aka Buff,Debuff
                    combatant.Statuses = new List <StatusV1>();
                    const int StatusEffectOffset = 5992;
                    const int statusSize         = 12;

                    int statusCountLimit = 60;
                    if (combatant.type == ObjectType.PC)
                    {
                        statusCountLimit = 30;
                    }

                    var statusesSource = new byte[statusCountLimit * statusSize];
                    Buffer.BlockCopy(source, StatusEffectOffset, statusesSource, 0, statusCountLimit * statusSize);
                    for (var i = 0; i < statusCountLimit; i++)
                    {
                        var statusBytes = new byte[statusSize];
                        Buffer.BlockCopy(statusesSource, i * statusSize, statusBytes, 0, statusSize);
                        var status = new StatusV1
                        {
                            StatusID = BitConverter.ToInt16(statusBytes, 0),
                            Stacks   = statusBytes[2],
                            Duration = BitConverter.ToSingle(statusBytes, 4),
                            CasterID = BitConverter.ToUInt32(statusBytes, 8),
                            IsOwner  = false,
                        };

                        if (status.IsValid())
                        {
                            combatant.Statuses.Add(status);
                        }
                    }

                    // Cast
                    combatant.Casting = new CastV1
                    {
                        ID       = *(short *)&p[6372],
                        TargetID = *(uint *)&p[6384],
                        Progress = *(Single *)&p[6420],
                        Time     = *(Single *)&p[6424],
                    };
                }
                else
                {
                    combatant.CurrentHP                     =
                        combatant.MaxHP                     =
                            combatant.CurrentMP             =
                                combatant.MaxMP             =
                                    combatant.MaxTP         =
                                        combatant.CurrentTP = 0;
                    combatant.Statuses = new List <StatusV1>();
                    combatant.Casting  = new CastV1();
                }
            }

            return(combatant);
        }