Le blog technique

Toutes les astuces #tech des collaborateurs de PI Services.

#openblogPI

Retrouvez les articles à la une

SCOM – SQL – Requete d’info etendue sur les agents Scom

La requete suivante affiche des infos etendues sur les agents Scom, avec le détails des Primary et Failover Servers.

 

/****** Scom Agent Extended Infos ******/   Use OperationsManager   WITH PrimaryRelation (SourceEntityId,agent,PrimaryServer,TargetEntityId) AS ( SELECT R.SourceEntityID,SourceBME.DisplayName as Agent,TargetBME.DisplayName as PrimaryServer, R.TargetEntityID FROM Relationship R WITH (NOLOCK) JOIN BaseManagedEntity SourceBME ON R.SourceEntityID = SourceBME.BaseManagedEntityID JOIN BaseManagedEntity TargetBME ON R.TargetEntityID = TargetBME.BaseManagedEntityID WHERE R.RelationshipTypeId = dbo.fn_ManagedTypeId_MicrosoftSystemCenterHealthServiceCommunication() ) , FailoverRelation (SourceEntityId,agent,FailoverServer,TargetEntityId) AS ( SELECT R.SourceEntityID,SourceBME.DisplayName as Agent,TargetBME.DisplayName as FailoverServer, R.TargetEntityID FROM Relationship R WITH (NOLOCK) JOIN BaseManagedEntity SourceBME ON R.SourceEntityID = SourceBME.BaseManagedEntityID JOIN BaseManagedEntity TargetBME ON R.TargetEntityID = TargetBME.BaseManagedEntityID WHERE R.RelationshipTypeId = dbo.fn_ManagedTypeId_MicrosoftSystemCenterHealthServiceSecondaryCommunication() )     SELECT                    MTV_HS.[DisplayName]                   ,PrimaryRelation.PrimaryServer                   ,FailoverServer                   ,Failover_State = CASE                                WHEN FailoverRelation.FailoverServer IS NULL THEN 'NO FAILOVER'                                ELSE FailoverRelation.FailoverServer                                END                   ,[Port]       ,[InstallTime]       ,[MaximumQueueSize]       ,Patch = CASE                     WHEN [PatchList] like '%UR4%' THEN 'RU4'                                WHEN [PatchList] like '%UR8%' THEN 'RU8'                                WHEN [PatchList] like '%UR11%' THEN 'RU11'                                WHEN [PatchList] = '' THEN '[NO_DATA]'                                END       ,[IsManuallyInstalled]       ,[Version]       ,[ActionAccountIdentity]       ,[ProxyingEnabled]       ,[HeartbeatInterval]       ,[NumberOfMissingHeartBeatsToMarkMachineDown_27AD2E30_EFE0_1A73_8C9D_F0A22B073227] as NumberOfMissingHeartBeatsToMarkMachineDown                   ,MTV_OS.DisplayName as OS                   ,MTV_OS.CSDVersion_AFE62B62_74FC_2F06_D8A0_DEE31F14CD33 as ServicePack                   ,MTV_OS.LogicalProcessors_5CAE4847_F75B_01D0_156E_1658D557B739 as Logic_CPU                         FROM [OperationsManager].[dbo].[MTV_HealthService] as MTV_HS   INNER JOIN  [dbo].[MTV_Microsoft$Windows$OperatingSystem] as MTV_OS on MTV_HS.DisplayName = MTV_OS.PrincipalName     INNER JOIN PrimaryRelation on PrimaryRelation.SourceEntityId = MTV_HS.BaseManagedEntityId   LEFT OUTER JOIN FailoverRelation on FailoverRelation.SourceEntityId = MTV_HS.BaseManagedEntityId       WHERE IsAgent = '1'

Utilisation de WinSCP .Net Assembly et COM library

Dans cet article nous allons apprendre l’utilisation et l’importance de WinSCP .Net Assembly et COM library.

Introduction

Nous sommes habitué à utiliser le client WinSCP pour se connecter sur un serveur SFTP,SCP ou FTP. Il existe même un module très basique appelé WinSCP.com pour envoyer ou réceptionner des données via un fichier *.bat. Cependant, beaucoup d’entre nous ignore l’existance de WinSCP .Net Assembly et COM library qui offre la possibilité de manipuler des fichiers à distance depuis un environnement supportant .NET, par exemple C#,VB. Net, PowerShell,SSIS et même depuis les sites MS AZURE.

WinSCP .Net assembly et COM library offrent beaucoup de possibilité en termes de ligne de commandes pour automatiser l’envoi et la réception de fichier depuis un serveur FTP,SCP ou sFTP. 

Prérequis

Télécharger le fichier zip indiqué ci-dessous et décompresser le.

Exemple de programmation en PoSH

  • L’initialisation d’une connexion sur un serveur
try
{
    # appel WinSCP .NET assembly
    Add-Type -Path "WinSCPnet.dll"
 
    # paramètre de connexion
    $sessionOptions = New-Object WinSCP.SessionOptions -Property @{
        Protocol = [WinSCP.Protocol]::Sftp
        HostName = "example.com"
        UserName = "user"
        Password = "mypassword"
        SshHostKeyFingerprint = "ssh-rsa 2048 xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx"
    }
 
    $session = New-Object WinSCP.Session
 
    try
    {
        # initialiser la connexion
        $session.Open($sessionOptions)
 
        Write-Host "You are now connected!!!"
    }
    finally
    {
        # Déconnecter et nettoyer
        $session.Dispose()
    }
 
    exit 0
}
catch [Exception]
{
    # Exception
    Write-Host ("Error: {0}" -f $_.Exception.Message)
    exit 1
}

Pour se connecter sur un serveur sFTP avec une clé privée et sans login et mot de passe, remplacer la ligne :

Password = "mypassword"
        SshHostKeyFingerprint = "ssh-rsa 2048 xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx"

par 

SshPrivateKeyPath = "chemin vers la clé privée"
        GiveUpSecurityAndAcceptAnySshHostKey = "true"
  • Télécharger un fichier 

Pour télécharger un fichier avec son nom, utiliser la ligne de commande ci-dessous:

<pre class="wp-block-syntaxhighlighter-code">$session.GetFiles($session.EscapeFileMask(<chemin complet du fichier>), <destination locale>).Check()</pre>
  • Pour uploader un fichier 
 # Upload files
        $transferOptions = New-Object WinSCP.TransferOptions
        $transferOptions.TransferMode = [WinSCP.TransferMode]::Binary
 
        $transferResult = $session.PutFiles("d:\toupload\*", "/home/user/", $False, $transferOptions)

 

Pour avoir plus d’informations sur les classes existantes : https://winscp.net/eng/docs/library

 

SCOM – A read operation on a large objects failed while sending data to the client

Pour cet article, nous allons nous intéresser à un cas peu commun.

Une erreur passée inaperçue pendant plusieurs mois car visée par aucune règle ou moniteur se reproduisait très régulièrement, aléatoirement sur l’un ou l’autre des Management Servers :

clip_image002

Evénement 26319, An exception was thrown while processing GetObjectsFromReader for session ID uuid:2f0f5bab-011d-4002-98d1-4c500cc449a2;id=103303.
Exception message : A transport-level error has occurred when receiving results from the server. (provider TCP Provider, error 0 – The specified network name is no longer available).

La partie “provider TCP Provider, error 0 – The specified network name is no longer available” fait immanquablement penser à une erreur SQL, et le fait que la source de l’événement soit OpsMgr SDK Service est un indice supplémentaire en ce sens.

Une verification dans le journal d’événements Applications du serveur SQL de la base OperationsManager montre qu’effectivement, un événement 7886 est présent pour chaque événement 26319 sur les Management Servers :

clip_image004

A read operation on a large objects failed while sending data to the client. A common cause for this is if the application is running in READ UNCOMMITTED isolation level. This connection will be terminated.

« Une cause courante pour cette erreur est si le niveau d’isolation est READ UNCOMMITED »… Vérifions donc cela dans la base OperationsManager, à l’aide de la commande DBCC USEROPTIONS :

clip_image006

Manifestement, ce n’est pas le cas, elle est bien en committed…

Je me tourne donc vers mon moteur de recherche préféré, qui une fois n’est pas coutume ne m’aide qu’assez peu. Un lien retient cependant mon attention : https://scomblog.wordpress.com/2012/02/29/469/.

La plupart des informations abordées dans cet article n’ont rien à voir avec le cas qui nous intéresse aujourd’hui, mais le dernier point est des plus intéressant (malgré sa syntaxe assez douloureuse) : il nous apprend que cette erreur peut se produire lorsque une lecture d’une alerte dans la base de données survient au même moment que la mise à jour de cette même alerte (cas d’une alerte dont le RepeatCount s’incrémente), ce qui provoque un conflit.
Le cas de figure le plus évident serait donc celui d’une console SCOM ouverte sur une alerte qui s’incrémente très régulièrement lorsqu’un rafraîchissement de la console survient au moment de la mise à jour de l’alerte en base. En plus, cet environnement a effectivement quelques alertes dont le RepeatCount est élevé (plusieurs dizaines de milliers).

Sauf qu’après une petite enquête auprès des utilisateurs, aucun ne semble avoir de problème récurrent avec la console (popup d’erreur, déconnexions…) qui devraient pourtant se produire lorsque l’incident survient.

Pour en avoir le cœur net, une trace SQL est prise avec l’aide du support Microsoft. Elle révèle que les requêtes qui provoquent le problème sont toutes semblables à ceci :

clip_image008

Cette requête récupère les détails d’une alerte (source, description etc) ; elle est donc parfaitement légitime et il est normal d’en rencontrer un grand nombre. Elle cadre d’ailleurs avec l’explication préalablement analysée.
Un détail attire cependant mon attention : ici, la requête est effectuée pour TOUTES les alertes présentes dans l’environnement, puisque la variable @Id0, supposée contenir l’ID de l’alerte à récupérer, contient ici le caractère %, autrement dit le « joker » du langage SQL !
Il s’agit donc d’une requête particulièrement lourde, et qui n’a pas réellement de raison d’être effectuée par une utilisation normale de la console.

Peut-être est-il alors possible de retrouver par quel compte utilisateur cette requête est déclenchée ? Cela nous aiderait à comprendre comment elle survient…

Revenons donc à notre événement sur le Management Server SCOM. Ce n’est pas très lisible, mais il nous indique quelle session a rencontré le problème via l’information id=. Il s’agit donc ici de la session 103303.

clip_image010

En descendant un peu dans le journal d’événement, il doit normalement exister un événement 26328 qui correspond à la création de cette session et qui contient le compte l’ayant créé :

clip_image012

Voilà qui est intéressant ! Dans cet environnement, tous les utilisateurs se connectent avec leur compte nominal personnel. Le compte « SCOM2012_admin » n’est utilisé que pour l’exécution de scripts qui font appel à SCOM.

Il n’y a ici pas de moyen technique permettant de savoir quel est ce script ni à partir d’où il est exécuté, mais une bonne connaissance de l’environnement m’a permis d’avoir des soupçons sur un script en particulier qui s’exécutait très régulièrement et effectuait des traitements sur les alertes.

Une analyse du script a révélé qu’il exécutait le cmdlet Get-SCOMAlert | Where {blabla}, c’est-à-dire qu’il récupérait l’intégralité des alertes avec toutes leurs propriétés puis les filtrait à l’aide de la clause Where ; ce qui correspond parfaitement à ce qu’indiquait la trace SQL : nous tenons manifestement notre coupable !

Et la correction est en plus assez simple : il suffit de réaliser le filtrage dans la requête, ce qui a pour conséquence de l’alléger considérablement, en modifiant le cmdlet de la sorte : Get-SCOMAlert –Criteria {blablabla}.

Suite à cette modification, l’événement ne s’est plus reproduit et, pour ne rien gâcher, le serveur qui exécutait le script a vu son occupation CPU et RAM diminuer fortement 🙂