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