benötige Hilfe bei Script anpassung.

Code-Stücke können hier veröffentlicht werden.
Antworten
thomasritter
User
Beiträge: 3
Registriert: Donnerstag 9. Juli 2020, 10:26

Donnerstag 9. Juli 2020, 13:06

Hallo zusammen,

ich bin gerade dabei zu versuchen einige Daten aus der CMDB zu bekommen. Mit dem ersten Teil hat das auch soweit ganz gut funktioniert.
Ich habe die Informationen (name, aliases und customer) erfolgreich durch die Dokumentation https://api.device42.com/#resource_Devices in eine JSON laden können.

Da ich nun auch noch die Informationen aus dem Feld cost_center benötige, stehe ich nun vor einem Rätsel, da die Abfrage nach dem Vorbild der hier stehenden Version nicht durch weitere Abfrage
erweitert werden kann. Ich schätze das ich den Path irgendwie noch einbinden müsste um auch die Felder unter Purchasing abfragen zu können.

https://api.device42.com/#resource_Purchasing

Kann hier jemand weiterhelfen ?

Code: Alles auswählen

#! /bin/python

import requests
import base64
import json


#filepath = "/tmp/"
filepath = ""
filename = "data.json"




def getAllDevFromCMDB():
    D42_URL = your_d42_fqdn_or_ip  #no / in the end
    D42_USERNAME = your_d42_username_here
    D42_PASSWORD = your_d42_password_her
    path = '/api/1.0/devices/all?include_cols=name,customer'

    headers = {
        'Authorization': 'Basic ' + base64.b64encode((D42_USERNAME + ':' + D42_PASSWORD).encode()).decode(),
        'Content-Type': 'application/x-www-form-urlencoded'
    }
    res = requests.get(D42_URL + path, headers=headers, verify=False)
    res = res.json()
    i = res['total_count'] / 1000
    i = int(round(i+1))
    offset = 0
    allD = []
    for e in range(0, i):
        #All VMS
        path = '/api/1.0/devices/all?include_cols=name,customer,aliases&offset='
        path += str(offset)
        offset += 1000
        test = requests.get(D42_URL + path, headers=headers, verify=False)
        test = test.json()
        print(test)
        allD += test['Devices']


    return allD



res = []
for device in getAllDevFromCMDB():
    tempJSON = {}
    tempJSON.update({'name': device['name']})
    tempJSON.update({'aliases': device['aliases']})
    tempJSON.update({'customer': device['customer']})
    res.append(tempJSON)


with open(filepath + filename, 'w') as outfile:
    json.dump(res, outfile)
Sirius3
User
Beiträge: 12423
Registriert: Sonntag 21. Oktober 2012, 17:20

Donnerstag 9. Juli 2020, 15:07

Konstanten werden am Anfang der Datei definiert, nicht innerhalb von Funktionen.
Username und Passwort müssen URL-quote-iert werden.
i ist ein schlechter Name für einen total_count.
Strings stückelt man nicht mit + zusammen und für URL-Paremter benutzt man den passenden Parameter bei requests.get.
Listen werden mit extend erweitert.
Benutze keine Abkürzungen, wenn Du all_devices meinst, schreibe nicht allD.
Was hat die temperatur mit Devices zu tun, oder was soll tempJSON denn heißen?
Wörterbücher werden gleich richtig erzeugt, oder man benutzt [] für einzelne Schlüssel, nicht update.

Code: Alles auswählen

result = []
for device in get_all_devices_from_cmdb():
    result.append({
        'name': device['name'],
        'aliases': device['aliases'],
        'customer': device['customer']
    })
Pfade werden nicht mit + zusammengestückelt, sondern man benutzt das pathlib-Modul.
Benutzeravatar
__blackjack__
User
Beiträge: 6559
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Donnerstag 9. Juli 2020, 20:27

Ergänzend: Man möchte vielleicht auch prüfen ob die HTTP-Antwort Ok war.

Um Basic-Auth muss man sich nicht selbst kümmern, das gibt's viel einfacher von `requests`. Und der "Content-Type"-Header ist bei dem GET auch nicht wirklich sinnvoll, denn es wird da ja gar kein Inhalt mitgeschickt.

Dafür sollte man aber dringent "limit=1000" mitschicken, denn sonst funktioniert das ja nur wenn das implizite Limit zufällig 1000 ist. Und bei der ersten Abfrage die ja nur zum ermitteln der Gesamtanzahl dient, könnte man als Limit 1 setzen.

Die Anzahl der 1000er-Päckchen würde ich ja lieber ohne Gleitkommaarithmetik und `round()` ermitteln. Ich bin mir nämlich nicht sicher, dass da keine Fehler entstehen können bei ungünstigen Werten wegen der Ungenauigkeit von Gleitkommazahlen und der ”komischen” Semantik von `round()`.

Wobei ich mich gerade frage warum man da nicht gleich `range()` mit einer Schrittweite verwenden sollte‽

Beziehungsweise ob das überhaupt sinnvoll ist die erste Abfrage zu machen und das Ergebnis letztlich einfach wegzuwerfen nur um die Anzahl zu bekommen‽

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
import json
from itertools import count
from pathlib import Path

import requests

# FILE_PATH = Path("/tmp/")
FILE_PATH = Path()
FILENAME = "data.json"

D42_URL = "your_d42_fqdn_or_ip"  # no / in the end
D42_USERNAME = "your_d42_username_here"
D42_PASSWORD = "your_d42_password_her"


def get_all_devices_from_cmdb():
    limit = 1000
    all_devices = []
    for offset in count(0, limit):
        response = requests.get(
            D42_URL + "/api/1.0/devices/all",
            params={
                "include_cols": "name,customer,aliases",
                "limit": limit,
                "offset": offset,
            },
            auth=(D42_USERNAME, D42_PASSWORD),
            verify=False,
        )
        response.raise_for_status()
        devices = response.json()["Devices"]
        if not devices:
            return all_devices
        all_devices.extend(devices)

    raise AssertionError("unreachable")


def main():
    result = [
        {key: device[key] for key in ["name", "aliases", "customer"]}
        for device in get_all_devices_from_cmdb()
    ]
    with open(FILE_PATH / FILENAME, "w", encoding="utf-8") as outfile:
        json.dump(result, outfile)


if __name__ == "__main__":
    main()
long long ago; /* in a galaxy far far away */
thomasritter
User
Beiträge: 3
Registriert: Donnerstag 9. Juli 2020, 10:26

Freitag 10. Juli 2020, 13:19

Hallo,
erstmal vielen Dank für die Rückmeldungen.
Ich bin auf diesem Gebiet nicht wirklich drin und versuche diese Anforderung erstmal zu erfüllen.
Ich versuche aber dennoch im Bereich Python etwas Fuß zu fassen, da dies auch in Zukunft immer mehr gefordert wird.
@blackjack Am Montag werde ich mich mal mit deinem Code beschäftigen und testen wie weit ich damit komme und werde danach nochmal eine Rückmeldung
geben.

Grüße

Thomas
thomasritter
User
Beiträge: 3
Registriert: Donnerstag 9. Juli 2020, 10:26

Montag 13. Juli 2020, 12:49

Hallo,

ich habe das Script jetzt mal übernommen und getestet. Ich verstehe nur diese api abfrage nicht für das Feld
mit der Kostenstelle (cost_center). Ich glaube nicht das ich das in einem Script mit einfließen lassen kann
in das json file. Aktuell gibt er in der Datei das Feld cost_center mit aber kann ich werte nicht übernehmen.

Grüße

Thomas
Antworten