Seite wählen

NETWAYS Blog

ServiceNow Data Asset Import mit dem Director

Hallo Liebe Leser dieses Blogs,

nach einer weile der Abwesenheit hab ich heute die Freude ihnen etwas näher bringen zu dürfen.
Da viele unserer Kunden inzwischen auch ServiceNow verwenden und diese auch als Assetmanagement / CMDB verwenden.

Kommt doch die Frage auf wie man gegebenenfalls hier die Daten abfragen kann um Sie in den Director zu importieren um daraus dann Hosts/Services zur Überwachung zu formen.Ich versuche in diesem kleinen Blogpost zumindest einen Ansatzpunkt hierzu aufzuzeigen. Viele verwenden in diesem Fall ja ServiceNow als SaaS, aber es gibt auch Kunden welche es als On Prem einsetzen.
Aber fangen wir an 🙂 in diesem Fall ist der Anlaufpunkt hier die ServiceNow API, wer hätte es gedacht.
In diesem Fall ziehe ich mal die folgende API (Link) zur rate:

Hier wird die ‚cmdb-instance‘ in welcher die CMDB Daten landen dokumentiert. Es ist aber zu bedenken, dass die Instanz natürlich abweichen kann daher ist dies bitte nicht direkt 1:1 zu übernehmen.
Wir feuern per curl gegen die ServiceNow API, die folgende Abfrage… in Hoffnung, dass wir valides JSON zurückerhalten mit all unseren Objekten.


curl -k -s -S -i -u 'servicenow_apiuser:servicenow_apiuserpassword' -H 'Accept: application/json' -H 'X-HTTP-Method-Override: GET' -X POST 'https://instance.servicenow.com/api/now/cmdb/instance/cmdb_ci_linux_server'

und wir erhalten als Antwort das folgende JSON:


{
"result": {
...
"attributes": {
"firewall_status": "Intranet",
"os_address_width": "",
"sys_updated_on": "2020-07-08 11:16:51",
"sys_created_by": "glide.maint",
"warranty_expiration": "",
"ram": "2048",
"cpu_name": "",
"cpu_speed": "2800",
"classification": "Production",
"disk_space": "40",
"dns_domain": "",
"assigned": "2020-01-04 07:00:00",
"floppy": "",
...
"sys_class_name": "cmdb_ci_linux_server",
...
"cpu_count": "1",
...
"os_version": "2.6.9-22.0.1.ELsmp",
"serial_number": "",
"attributes": "",
...
"form_factor": "",
"cpu_core_count": "",
"sys_updated_by": "system",
"sys_created_on": "2008-10-26 17:17:28",
...
"name": "PS LinuxApp01",
"default_gateway": "",
"chassis_type": "",
"sys_id": "3a290cc60a0a0bb400000bdb386af1cf",
"po_number": "",
"checked_in": "",
...
"comments": "",
"os": "Linux Red Hat",
"sys_mod_count": "24",
"monitor": "false",
"model_id": {
"display_value": "Iris 5875",
"link": "https://instance.servicenow.com/api/now/table/cmdb_model/5f5fbcc3c0a8010e00f3b27814f3b96b",
"value": "5f5fbcc3c0a8010e00f3b27814f3b96b"
},
"ip_address": "192.168.178.1",
"duplicate_of": "",
"location": {
"display_value": "Somewhere Street, Someplace, State",
},
"category": "Do not migrate to asset",
"fault_count": "0",
"host_name": "",
"lease_id": ""
},
}

Den Output schreiben wir als Datei raus, so dass wir hier als Beipiel eine Datei haben, mit der wir weiterarbeiten können. Als Beispiel nennen wir diese servicenow.json
(Exclaimer) Ich habe das JSON hier als Beispiel mal extrem zusammengekürzt, damit wir thementechnisch nicht zu weit Abdriften.
Anyway, aber damit lässt sich arbeiten.
Damit wir mit diesem JSON arbeiten können, verwenden wir das Tool ‚jq‘, um relevante key/value Paare herauszufiltern.
Ich habe hier mal den folgenden ‚jq‘ Aufruf verwendet:


jq -j '.result.attributes.os,",",.result.attributes.ip_address,",",.result.attributes.classification,",",.result.attributes.sys_class_name,",",.result.attributes.name,",",.result.attributes.location.display_value,","' servicenow.json

Der somit gewonnene Output ist der folgende, bitte beachtet die ‚,‘ Kommata. Die meisten werden schon ahnen worauf ich gleich hinaus will.
Zurück zu dem nun mit ‚jq‘ aufbereiteteb Output, dieser ist der folgende:


Linux Red Hat,192.168.178.1,Production,cmdb_ci_linux_server,PS LinuxApp01,Somewhere Street, Someplace, State,

Mit etwas Bash Scripting kann man das schön automatisieren und hat am Ende dieses Vorgangs eine CSV Datei, die man hervorragend im Director per Fileshipper weiterverarbeiten kann.
Das mit dem CSV ist eine Geschmacksfrage, denn man kann auch direkt JSON per Fileshipper importieren … ich würde aber dazu tendieren, die Datenmenge durch etwas vorfiltern zu verkleinern. So eine Filterung, wie gesehen, kann auch per ‚jq‘ erfolgen, so dass man ein kleineres JSON File erhält.
Wer wissen möchte, wie man mit dem Director einen Fileshipper-Import durchführt, dem sei der Blogpost meines Kollegen Johannes empfohlen.

Blogpost Director Fileshipper Import

Das war schon mein kleines Intermezzo wie ServiceNow-Data-Assets per Fileshipper in den Director zu importiert sind.
Bis zum nächsten Mal

Mit freundlichem Gruß
David

David Okon
David Okon
Senior Systems Engineer

Weltenbummler David hat aus Berlin fast den direkten Weg zu uns nach Nürnberg genommen. Bevor er hier anheuerte, gab es einen kleinen Schlenker nach Irland, England, Frankreich und in die Niederlande. Alles nur, damit er sein Know How als IHK Geprüfter DOSenöffner so sehr vertiefen konnte, dass er vom Apple Consultant den Sprung in unser Professional Services-Team wagen konnte. Er ist stolzer Papa eines Sohnemanns und bei uns mit der Mission unterwegs, unsere Kunden zu glücklichen Menschen zu machen.

Ansible – Loop over multiple tasks

ansible logo

The last time I wrote about Ansible and the possibility to use blocks to group multiple tasks. Which you can read here. Sadly this feature does not work with loop, so there is no clean way to loop over multiple tasks in a play without writing the same loop statement at tasks over and over.

But when we come across the need of tasks which depend on each other, for example, we execute a script with a certain parameter and its result is necessary for the upcoming tasks.

Let’s go through a common example, creating a site consists of a few steps. Creating the directory, creating the vhost and then enabling the site.


- name: "create {{ site }} directory"
  file:
    ensure: directory
    dest: "/var/www/{{ site }}"
    
- name: "create {{ site }}"
  template:
    src: vhost.j2
    dest: "/etc/apache2/sites-available/{{ site }}"
  register: vhost

- name: "enable {{ site }}"
  command: /usr/sbin/a2ensite "{{ site }}"
  register: result
  when: vhost.changed
  changed_when: "'Enabling site' in result.stdout"
  notify: apache_reload

We could use a loop for each tasks and afterwards find the right result for the next task to depend on. But the styleguide will warn you if you try to use Jinja2 syntax in when statements.

So the best solution to this is to use include_tasks, which can include a file with tasks. This task is allowed to have a loop directive and so we can include it multiple times.
Lets see how this would apply to our scenario:


- set_fact:
    sites:
      - default
      - icingaweb2

- name: create vhosts
  include_tasks: create-vhosts.yml
  loop: "{{ sites }}"
  loop_control:
    loop_var: site


In the Result we can see clearly that all tasks are applied for each element in the sites variable.


TASK [set_fact] *********************************************
ok: [localhost]

TASK [create vhosts] ****************************************
included: /Users/twening/Documents/netways/ansible_test20/create-vhosts.yml for localhost => (item=default)
included: /Users/twening/Documents/netways/ansible_test20/create-vhosts.yml for localhost => (item=icingaweb2)

TASK [create default directory] *****************************
ok: [localhost]

TASK [create default] ***************************************
ok: [localhost]

TASK [enable default] ***************************************
ok: [localhost]

TASK [create icingaweb2 directory] **************************
ok: [localhost]

TASK [create icingaweb2] ************************************
ok: [localhost]

TASK [enable icingaweb2] ************************************
ok: [localhost]

PLAY RECAP **************************************************
localhost                  : ok=10   changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0


Check out our Blog for more awesome posts and if you need help with Ansible send us a message or sign up for one of our trainings!

Thilo Wening
Thilo Wening
Manager Consulting

Thilo hat bei NETWAYS mit der Ausbildung zum Fachinformatiker, Schwerpunkt Systemadministration begonnen und unterstützt nun nach erfolgreich bestandener Prüfung tatkräftig die Kollegen im Consulting. In seiner Freizeit ist er athletisch in der Senkrechten unterwegs und stählt seine Muskeln beim Bouldern. Als richtiger Profi macht er das natürlich am liebsten in der Natur und geht nur noch in Ausnahmefällen in die Kletterhalle.

Trick 42 mit dem Director – Jobs in Reihenfolge

Nachdem wir unseren Trick 17 mit dem Director veröffentlichten, schiebe ich Trick 42 direkt hinterher. Wie im Blogpost von Markus beschrieben, sind Schnittmengen aus mehreren Importquellen eine geniale Lösung um beispielsweise Hosts aus mehreren Quellen mit Informationen anzureichern. Konfiguriert man nun eine Vielzahl solcher Importquellen die für die Schnittmenge dienen sollen, bekommt man evtl. im Ablauf gewisse Probleme mit der Reihenfolge.
Zur genauen Erklärung unser Ausgangsszenario:

  • CMDB 1: Quelle für die Basisdaten des Hosts (Name, IP, FQDN, …)
  • CMDB 2: Quelle für den OS-Type (CentOS, OpenSuSE, Debian, …)
  • CMDB 3: Quelle für den Ansprechpartner (Hr. Müller, Hr. Maier, …)

Damit die Hosts aus CMDB 1 angereichert erstellt (Import + Sync) werden können müssen zuerst CMDB 2 und CMDB 3 abgearbeitet werden. Logisch – wenn der OS-Type und der Ansprechpartner des Hosts dem Director nicht bekannt sind wird es mit Hilfe von Trick 17 auch nicht möglich sein den Host aus CMDB 1 mit Daten anzureichern.
Hauptsächlich fällt dieses Problem beim initialen Import + Sync der Daten auf. Je nachdem wie oft sich eure Importquellen ändern kann dies „gar nicht schlimm“ (Hr. Müller ist für den Server 3 Jahre zuständig) oder auch „sehr unglücklich“ (Ihr importiert die Kontaktdaten einer ständig wechselnden Rufbereitschaft) sein.
Für den Fall das die Reihenfolge der Importquellen wichtig ist gibt es eine denkbar simple Lösung.
Ihr legt für jeden Import und Sync einen Job im Director an…

 

…und notiert euch jeweils die ID des Director Jobs (die Zahl an der letzten Stelle der URL).

Mit Hilfe dieser ID könnt ihr nun die im Director konfigurierten Jobs von der Kommandozeile aus ausführen. Der Job mit der ID 1 (Import Job für CMDB1) kann mit dem Kommando „icingacli director jobs run 1“ gestartet werden.
Am Ende bauen wir uns dazu noch ein kleines Skript:
[code]
#!/bin/bash
# set paths and vars
ICINGA_CLI=`which icingacli`
JOB_CMD=${ICINGA_CLI}" director jobs run"
# execute jobs
echo "import and sync…"
echo -e "\tcmdb1"
${JOB_CMD} 1
${JOB_CMD} 2
echo -e "\tcmdb2";
${JOB_CMD} 3
${JOB_CMD} 4
echo -e "\tcmdb3";
${JOB_CMD} 5
${JOB_CMD} 6
[/code]
Und voilà – wir haben die Imports und Syncs in einer Reihenfolge 🙂

Tobias Redel
Tobias Redel
Head of Professional Services

Tobias hat nach seiner Ausbildung als Fachinformatiker bei der Deutschen Telekom bei T-Systems gearbeitet. Seit August 2008 ist er bei NETWAYS, wo er in der Consulting-Truppe unsere Kunden in Sachen Open Source, Monitoring und Systems Management unterstützt. Insgeheim führt er jedoch ein Doppelleben als Travel-Hacker und renoviert, baut und bastelt als Heimwerker an allem was er finden kann.

Trick 17 mit dem Director

Möchte man die Schnittmenge aus mehreren Importquellen im Icinga Director vereinen, so gibt es dafür einen Lösungsweg der bislang vielen noch nicht bekannt ist.
Beispielhaft dienen folgende zwei SQL-Tabellen als Ausgangslage, testhost03 ist dabei nur in der Tabelle „hosts01“ enthalten:
MariaDB [cmdb]> SELECT * FROM cmdb.hosts01;
+----+------------+----------+---------+
| id | hostname   | address  | os      |
+----+------------+----------+---------+
|  1 | testhost01 | 10.0.0.1 | Windows |
|  2 | testhost02 | 10.0.0.2 | Linux   |
|  3 | testhost03 | 10.0.0.3 | Windows |
+----+------------+----------+---------+

MariaDB [cmdb]> SELECT * FROM cmdb.hosts02;
+----+------------+----------+---------+
| id | hostname   | address  | os      |
+----+------------+----------+---------+
|  1 | testhost01 | 10.0.0.1 | Windows |
|  2 | testhost02 | 10.0.0.2 | Linux   |
+----+------------+----------+---------+

Um nun die Daten aus beiden Quellen abzugleichen ohne gleich Objekte im Director zu erzeugen, behilft man sich mit einer Datenliste als Zwischenschritt. Die ID der neu erstellten Datenliste wird später benötigt und kann über die Director-Datenbank herausgefunden werden:
MariaDB [director]> SELECT * FROM director.director_datalist WHERE list_name = "Hosts from 2nd import source";
+----+------------------------------+-------------+
| id | list_name                    | owner       |
+----+------------------------------+-------------+
|  2 | Hosts from 2nd import source | icingaadmin |
+----+------------------------------+-------------+

Wie dem Namen der Liste unschwer zu entnehmen ist sollen dort die Hosts aus der 2ten Importquelle, also von „hosts02“, zwischengespeichert werden.
Mit diesen Informationen kann die entsprechende Sync Rule für die Synchronisation der Hosts aus der 2ten Quelle in die Datenliste erstellt werden. Neben der ID als jeweilige „list_id“ (hier „2“) werden die Felder „entry_name“ und „entry_value“ definiert:

Nach dem Syncvorgang erhält die Datenliste die entsprechenden Einträge. Im Beispiel sind das testhost01 und testhost02. In der Import Source für die erste Datenquelle werden deren Einträge nun anhand des „Map“-Modifiers mit den Einträgen aus der Datenliste abgeglichen:

Damit ergibt sich folgende Vorschau der Import Source:

In der darauf aufbauenden Sync Rule ist es wichtig eine entsprechende Filter expression zu setzen:

Ist sie negiert, wie im vorangegangenen Beispiel, werden die Hosts die in beiden Datenquellen vorkommen erzeugt. Im Beispiel wären das testhost01 und testhost02. Liegt keine Negierung vor (z.B. „map=“), so werden nur die Hosts erzeugt die in der zweiten Datenquelle nicht vorkommen. Also beispielhaft testhost03. Damit der Filter greift, muss der Bezeichner (hier „map“) allerdings auch als Eigenschaft der Sync Rule vorkommen.
Der Icinga Director hält noch wesentlich mehr Funktionen für verschiedenste Anwendungsbereiche bereit. Das vorangegangene Beispiel dient lediglich dazu die Fähigkeiten dieses mächtigen Tools etwas zu veranschaulichen. Bei weiteren Fragen rund um den Director oder auch Icinga 2 stehen wir bei NETWAYS natürlich gerne zur Verfügung.

Markus Waldmüller
Markus Waldmüller
Head of Strategic Projects

Markus war bereits mehrere Jahre als Sysadmin in Neumarkt i.d.OPf. und Regensburg tätig. Nach Technikerschule und Selbständigkeit ist er nun Anfang 2013 bei NETWAYS als Senior Manager Services gelandet. Seit September 2023 kümmert er sich bei der NETWAYS Gruppe um strategische Projekte. Wenn er nicht gerade die Welt bereist, ist der sportbegeisterte Neumarkter mit an Sicherheit grenzender Wahrscheinlichkeit auf dem Mountainbike oder am Baggersee zu finden.

Platz da LConf, der Director kommt!

Lange Zeit war das von NETWAYS entwickelte Tool LConf das Mittel der Wahl wenn ein grafisches Konfigurationsfrontend für Icinga gesucht wurde. Mit Icinga 2 und dem damit einhergehenden geänderten Konfigurationsformat litt jedoch die Kompatibilität, außerdem ist das ursprüngliche Konzept von LConf mit der Zuweisung von Services über Vererbungen eines OpenLDAP-Baumes spätestens mit den vielen Möglichkeiten der Apply Rules von Icinga 2 überholt.
Als eigenes Modul in Icinga Web 2 integriert, ist der Director das einzige Konfigurationstool das eine vollständige Unterstützung für Icinga 2 bietet. Die Kommunikation erfolgt dabei direkt mit der API des Icinga 2 Cores (seit Icinga 2.4). Daher stellt sich also die Frage: Wie lässt sich die Icinga Konfiguration von LConf am Besten auf den Director, respektive von Icinga 1.x auf Icinga 2.x migrieren?
Icinga Web 2 bietet bereits nativ eine Unterstützung für LDAP, diese steht auch den Modulen zur Verfügung. Um LConf nun als Import Source im Director zu verwenden, muss dafür in Web 2 noch eine entsprechende Resource eingerichtet werden.

Host in LConf


Bei der Import Source reicht es dann i.d.R. aus die Objektklasse auf lconfHost einzuschränken, denn mehr als nur Hosts zu importieren, macht in den wenigsten Fällen sind. Services sollten aufgrund von CheckCommands aus der Icinga Template Library (= ITL) sowieso neu gemacht und in dem Zuge auch gleich überdacht werden. Durch die Apply Rules liegt der Fokus auf Host Eigenschaften anhand deren später Services zugewiesen werden können. Neben Standardattributen stehen hier auch sog. Custom Attribute oder Custom Variablen (CustomVars) zur Verfügung, mit denen weitere individuelle Informationen wie beispielsweise Betriebssystem, Rolle oder Standort hinterlegt werden können.
Normalerweise ist es bei Hosts ausreichend cn, lconfAddress, lconfAlias und lconfHostCustomvar zu importieren. Da CustomVars in LConf mit Unterstrich vorm Bezeichner und einem Leerzeichen vor dem eigentlichen Wert angegeben werden müssen, sieht das in der Vorschau der Import Source beispielhaft so aus:

[
„_operatingsystem Linux“,
„_role Webserver“,
„_rack Rack01“
]

Diese Syntax kann vom Director nur schwer weiter verarbeitet werden, daher gibt es dort seit kurzem den Modifier „Transform LConf CustomVars to Hash„, mit dem das Ganze wie folgt transformiert wird:

{
operatingsystem: „Linux“,
rack: „Rack01“,
role: „Webserver“
}

Host im Director


Bei der darauf aufbauenden Sync Rule können dann alle CustomVars mit „All custom variables (vars)“ automatisch umgesetzt werden, dabei spielt es keine Rolle ob die Hosts eine, keine oder mehrere Custom Attribute definiert haben.
Damit ist es sehr einfach die Hosts aus dem bestehenden LConf-Baum bereits im Produktivbetrieb schon auf die künftige Verwendung mit Icinga 2 vorzubereiten und sie dann mit dem Director einmalig oder regelmäßig zu importieren, sodass zumindest ein paar Andenken an den „geliebten“ LConf bleiben…
Wer hier oder auch bei anderen Aufgaben mit Icinga und dem Director noch Unterstützung benötigt, kann aber natürlich auch gerne auf uns zukommen.

Markus Waldmüller
Markus Waldmüller
Head of Strategic Projects

Markus war bereits mehrere Jahre als Sysadmin in Neumarkt i.d.OPf. und Regensburg tätig. Nach Technikerschule und Selbständigkeit ist er nun Anfang 2013 bei NETWAYS als Senior Manager Services gelandet. Seit September 2023 kümmert er sich bei der NETWAYS Gruppe um strategische Projekte. Wenn er nicht gerade die Welt bereist, ist der sportbegeisterte Neumarkter mit an Sicherheit grenzender Wahrscheinlichkeit auf dem Mountainbike oder am Baggersee zu finden.