Automatisieren mit Jenkins das Erstellen und Rollen von Artefakten von Metadatenmodellartefakten für Tabellen im Repository

Alles begann mit der Tatsache, dass wir schnell und korrekt EDWEX-, JSON- und DDL-Strukturen bilden und diese dann auf verschiedenen Konturen relationaler Datenbanken rollen mussten. Mit Konturen meine ich Abkürzungen, die jeder kennt - DEV, TST, UAT, PRD.



Zu dieser Zeit haben wir fast alles manuell erledigt: Wir haben DDL generiert und edwex und json basierend auf Metadaten aus der Oracle-Datenbank gesammelt. Es gibt viele Eingabeparameter. Wenn Sie eine verpassen, werden Sie eine Entität falsch bilden. Und da der gesamte Bildungsprozess konsistent und kontinuierlich war, wird der Fehler erst ganz am Ende erkannt. Lesen Sie unter dem Schnitt, wie wir alle Fehler automatisiert und überwunden haben.

Ein bisschen über Infrastruktur


Bevor wir die Daten in die Tabellen relationaler Datenbanken eintragen, müssen wir sie aus der Quelle akzeptieren - in einem beliebigen Format, beispielsweise in Excel. Daten von der Quelle, die den internen Mechanismus verwenden, werden nach Hadoop (Data Lake) transportiert. In Hive ist das Hive-Add-On installiert. Mithilfe dieser Funktion können wir den Inhalt von Dateien mithilfe einer SQL-ähnlichen Syntax anzeigen.

Um die Daten in Data Lake in Form von Tabellen zu übertragen, benötigen wir json's, die auf Basis von Metadaten gebildet werden. Um Daten im Excel-Format zu analysieren, müssen wir EDWEX-Dateien erstellen. EDWEX-Dateien (EDW_EXTRACTOR) sind bestimmte Artefakte, die Tabellensätze mit dem Namen sowie Feldsätze für jede dieser Tabellen enthalten, die auf der Grundlage von Metadaten erstellt werden. Abhängig von der Modellversion und der Quell-ID variieren die Felder. Die Bildung von DDL ist erforderlich, um die Tabellen selbst in der Hive-Datenbank auf der Ebene der Betriebsdaten und in der Greenplum-Datenbank auf der Ebene der detaillierten und aggregierten Daten zu erstellen. Das heißt, die Daten werden in erster Linie an Hive übertragen, bei Bedarf gefiltert und an Greenplum übertragen, um anschließend Daten zu bearbeiten und darauf basierend Storefronts zu erstellen.

Beispiel für ein Edwex-Artefakt
pack - enthält eine Reihe von Tabellen
Daten - enthält eine Reihe von Feldern

pack.edwex:

1 Table_1 User Table_1 bid between to_char($fromdt,'yyyymm') and to_char($actualdt,'yyyymm') 2 Table_2 User Table_2 curbid between to_char($fromdt,'yyyymm') and to_char($actualdt,'yyyymm') 3 Table_3 User Table_3 bid between to_char($fromdt,'yyyymm') and to_char($actualdt,'yyyymm') 


data.edwex:

 1 1 CHARGE_ID NUMBER 38 0 1 2 SVC_ID NUMBER 38 0 1 3 VND_ID NUMBER 38 0 1 4 PRICE NUMBER 38 5 1 5 QUANTITY NUMBER 38 5 1 6 BASE NUMBER 38 5 1 7 TAX NUMBER 38 5 1 8 TOTAL NUMBER 38 5 1 9 TAX_RATE NUMBER 38 5 1 10 TAX_IN VARCHAR 1 1 11 CHARGE_KIND VARCHAR 3 1 12 PRIVILEGE_ID NUMBER 38 0 1 13 CHARGE_REF_ID NUMBER 38 0 1 14 EBID NUMBER 38 0 1 15 INVOICE_ID NUMBER 38 0 1 16 ZERO_STATE_ID NUMBER 38 0 1 17 USER_ID NUMBER 38 0 1 18 BID NUMBER 38 0 1 19 QUANTITY_REAL NUMBER 38 5 2 1 CURBID NUMBER 38 0 2 2 USER_ID NUMBER 38 0 2 3 VND_ID NUMBER 38 0 2 4 APPBID NUMBER 38 0 2 5 SVC_ID NUMBER 38 0 2 6 DEBT NUMBER 38 5 2 7 INSTDEBT NUMBER 38 5 3 1 INVOICE_ID NUMBER 38 0 3 2 INVOICE_DATE DATE 3 3 INVOICE_NUM VARCHAR 64 3 4 INVOICE_NUM_N NUMBER 38 5 3 5 BASE NUMBER 38 5 3 6 TAX NUMBER 38 5 3 7 TOTAL NUMBER 38 5 3 8 PREPAID VARCHAR 1 3 9 EXPLICIT VARCHAR 1 3 10 VND_ID NUMBER 38 0 3 11 ADV_PAYMENT_ID NUMBER 38 0 3 12 MDBID NUMBER 38 0 3 13 BID NUMBER 38 0 3 14 USER_ID NUMBER 38 0 3 15 ZERO_STATE_ID NUMBER 38 0 3 16 ACTIVE_SUM NUMBER 38 5 3 17 SPLIT_VND NUMBER 38 5 3 18 PRECREATED VARCHAR 1 


Beispiel für ein Json-Artefakt
 Table.json: { "metadata": [ { "colOrder":"1", "name":"charge_id", "dataType":"DECIMAL", "precision":"0", "requied":"true", "keyFile":"" }, { "colOrder":"2", "name":"svc_id", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"3", "name":"vnd_id", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"4", "name":"price", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"5", "name":"quantity", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"6", "name":"base", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"7", "name":"tax", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"8", "name":"total", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"9", "name":"tax_rate", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"10", "name":"tax_in", "dataType":"STRING", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"11", "name":"charge_kind", "dataType":"STRING", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"12", "name":"privilege_id", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"13", "name":"charge_ref_id", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"14", "name":"ebid", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"15", "name":"invoice_id", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"16", "name":"zero_state_id", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"17", "name":"user_id", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"18", "name":"bid", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"19", "name":"quantity_real", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" } ], "ctlPath":"  ctl", "errPath":"    ", "inPath":"    hdfs", "outSchema":" ", "outTable":" ", "isPartitioned":" ", "sourceId":"id  " } 


Beispiel DDL-Artefakte
Tabellenschema ändern.GP_000001_TABLE in Z_GP_000001_TABLE_20180807 umbenennen;
Tabellenschema erstellen.GP_000001_TABLE
(

`load_id` DECIMAL (38.0),
`svc_id` DECIMAL (38.0),
`vnd_id` DECIMAL (38.0),
`Preis` DEZIMAL (38,5),
`Menge` DEZIMAL (38,5),
`base` DECIMAL (38,5),
`tax` DECIMAL (38.5),
`total` DECIMAL (38,5),
`tax_rate` DECIMAL (38.5),
`tax_in` STRING,
`load_kind` STRING,
`privileg_id` DECIMAL (38.0),
`load_ref_id` DECIMAL (38.0),
`ebid` DECIMAL (38.0),
`rechnungs_id` DECIMAL (38.0),
`zero_state_id` DECIMAL (38,0),
`user_id` DECIMAL (38.0),
`bid` DECIMAL (38.0),
`quantity_real` DECIMAL (38.5),
`load_dttm` TIMESTAMP,
`src_id` SMALLINT,
`package_id` BIGINT,
`wf_run_id` BIGINT,
`md5` STRING
)
REIHENFORMAT BEGRENZTE FELDER BEENDET DURCH '\ t'
GESPEICHERT ALS INPUTFORMAT 'org.apache.hadoop.mapred.TextInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LAGE 'Weg zur Bildung in HDFS'
TBLPROPERTIES ('auto.purge' = 'true', 'transient_lastDlastDdlTime' = '1489060201');
in Schema einfügen.GP_000001_TABLE (`Charge_id`,
`svc_id`,
`vnd_id`,
`Preis`,
`Menge`,
`base`,
"Steuer",
`total`,
`tax_rate`,
`tax_in`,
`load_kind`,
`privileg_id`,
`load_ref_id`,
"ebid",
`rechnungs_ID`,
`zero_state_id`,
`user_id`,
Gebot
`quantity_real`,
`load_dttm`,
`src_id`,
package_id
`wf_run_id`,
`md5`)

Wählen Sie `load_id`,
`svc_id`,
`vnd_id`,
`Preis`,
`Menge`,
`base`,
"Steuer",
`total`,
`tax_rate`,
`tax_in`,
`load_kind`,
`privileg_id`,
`load_ref_id`,
"ebid",
`rechnungs_ID`,
`zero_state_id`,
`user_id`,
Gebot
`quantity_real`,
load_dttm,
src_id
package_id,
wf_run_id,
md5 aus Schema.Z_GP_000001_TABLE_20180807;

Tabellenschema ändern.GP_000001_TABLE in Z_GP_000001_TABLE_20180807 umbenennen;
Tabellenschema erstellen.GP_000001_TABLE
(

`load_id` DECIMAL (38.0),
`svc_id` DECIMAL (38.0),
`vnd_id` DECIMAL (38.0),
`Preis` DEZIMAL (38,5),
`Menge` DEZIMAL (38,5),
`base` DECIMAL (38,5),
`tax` DECIMAL (38.5),
`total` DECIMAL (38,5),
`tax_rate` DECIMAL (38.5),
`tax_in` STRING,
`load_kind` STRING,
`privileg_id` DECIMAL (38.0),
`load_ref_id` DECIMAL (38.0),
`ebid` DECIMAL (38.0),
`rechnungs_id` DECIMAL (38.0),
`zero_state_id` DECIMAL (38,0),
`user_id` DECIMAL (38.0),
`bid` DECIMAL (38.0),
`quantity_real` DECIMAL (38.5),
`load_dttm` TIMESTAMP,
`src_id` SMALLINT,
`package_id` BIGINT,
`wf_run_id` BIGINT,
`md5` STRING
)
REIHENFORMAT BEGRENZTE FELDER BEENDET DURCH '\ t'
GESPEICHERT ALS INPUTFORMAT 'org.apache.hadoop.mapred.TextInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LAGE 'Weg zur Bildung in HDFS'
TBLPROPERTIES ('auto.purge' = 'true', 'transient_lastDlastDdlTime' = '1489060201');
in Schema einfügen.GP_000001_CPA_CHARGE (`Charge_id`,
`svc_id`,
`vnd_id`,
`Preis`,
`Menge`,
`base`,
"Steuer",
`total`,
`tax_rate`,
`tax_in`,
`load_kind`,
`privileg_id`,
`load_ref_id`,
"ebid",
`rechnungs_ID`,
`zero_state_id`,
`user_id`,
Gebot
`quantity_real`,
`load_dttm`,
`src_id`,
package_id
`wf_run_id`,
`md5`)

Wählen Sie `load_id`,
`svc_id`,
`vnd_id`,
`Preis`,
`Menge`,
`base`,
"Steuer",
`total`,
`tax_rate`,
`tax_in`,
`load_kind`,
`privileg_id`,
`load_ref_id`,
"ebid",
`rechnungs_ID`,
`zero_state_id`,
`user_id`,
Gebot
`quantity_real`,
load_dttm,
src_id
package_id,
wf_run_id,
md5 aus Schema.Z_GP_000001_TABLE_20180807;

So automatisieren Sie


Um das Problem zu lösen, haben wir verwendet:

  • Jenkins - als Orchester und Werkzeug zur Umsetzung des CI-Prozesses.
  • Python - implementiert Funktionen und Unit-Tests.
  • SQL - um auf die Metadatendatenbank zuzugreifen.
  • Shell-Skript - zum Kopieren von Artefakten zwischen Verzeichnissen und zum Erstellen von Skripten in Multijob-Projekten, die auf dem Jenkins-Server ausgeführt werden.

Zunächst arbeiten wir mit einer großen Anzahl von Quellen. Daher übergeben wir die IDs der Quellen mithilfe des Shell-Skripts als Startparameter an SQL-Funktionen, um sie zu identifizieren. Die resultierenden SQL-Funktionen werden anschließend automatisch in der Metadatendatenbank ausgeführt. Basierend auf den verfügbaren Metadaten bilden diese Funktionen eine Datei mit einer Liste neuer SQL-Funktionen für jede der Quelltabellen, sodass wir sie anschließend im ausführbaren Programm aufrufen können. Das Ergebnis der Ausführung der generierten Funktionen ist die Übertragung der DDL-, JSON- oder EDWEX-Werte auf den Ausgabeparameter.

Hier verbindet sich Python mit allen ausführbaren Funktionen und Unit-Tests. Bevor eines der Module zum Rollen von Artefakten mithilfe von Komponententests gestartet wird, wird die korrekte Parameterübertragung überprüft, um Python-Skripte auszuführen. Tests überprüfen nicht nur die Richtigkeit der Eingabeparameter, sondern auch deren Vorhandensein im Metadatenmodul, die Größe der erstellten Dateien und das Datum ihrer Erstellung. Tests überwachen auch die Anzahl der neu erstellten Artefakte und die Anzahl der vorhandenen Artefakte. Daher optimieren wir die Verwendung von Serverressourcen, da wir nur neue Dateien zum Rollen verwenden und vorhandene Modelle nicht erneut installieren.

Und erst nach erfolgreichem Bestehen aller Prüfungen wird ein Python-Programm ausgeführt, das die erforderlichen Artefakte erstellt und das Ergebnis in die erforderlichen Projektordner auf dem Server zerlegt. Python leitet die generierten JSON-Dateien nicht nur in Verzeichnisse, sondern bildet auch Strukturen in Data Lake, damit die Daten korrekt geladen werden. Beim Generieren von DDL-Artefakten werden diese nicht nur für eine spätere Analyse und Wiederverwendung gespeichert, sondern können auch mithilfe neuer Modelle und Strukturen, die im Metadatenmodul angegeben sind, sofort in der Datenbank installiert werden. Auf diese Weise können Sie in kurzer Zeit Hunderte von Tabellen ohne manuelle Arbeit erstellen.

Und wo ist Jenkins hier?


Jenkins tritt ein, wenn es notwendig ist, alle diese Prozesse visuell über eine Schnittstelle zu verwalten.

Dieses Tool wurde ausgewählt, weil es:

  • deckt den Bedarf an Automatisierung der Montage und Installation vollständig ab
  • Mit dieser Option können Sie einen Mechanismus zum Zusammensetzen von Artefakten mit der Implementierung des Selbsttestprozesses entwerfen
  • Ermöglicht die einfache Verwaltung von Jobstarts und die Überwachung der Ausführung für eine Person, die weit von der Programmierung entfernt ist
  • Mit dieser Option können Sie den Protokollierungsmechanismus so konfigurieren, dass das Ergebnis der Ausführung für jede Person im Team verständlich ist. Das Problem in der Baugruppe wird explizit angegeben oder der Vorgang wird erfolgreich abgeschlossen.

Um die Aufgaben zu lösen, haben wir mehrere Multijob-Projekte erstellt. Diese Art von Projekt wurde verwendet, da es mit einem einzigen Start parallel zu anderen Jobs arbeiten kann. Jeder Job ist für die Implementierung seines Funktionsblocks verantwortlich. Deshalb haben wir den sequentiellen Prozess des Erhaltens von Artefakten durch autonome parallele ersetzt. Alles beginnt separat: die Bildung von EDWEX, JSON, DDL, die Bildung der Struktur in HIVE, die Installation von Tabellenstrukturen in der Datenbank. Wir analysieren das Ergebnis in verschiedenen Stadien der Bildung von Artefakten und starten bei Erfolg weitere Aktionen.

Der Jenkins-Teil wird ohne viele Tricks implementiert. String- oder Run- Parameter werden an die Eingabe gesendet, um den Python-Code zu starten. Der Parameter String ist ein Fenster zur Eingabe eines Werts vom Typ str vor dem Start. Der Ausführungsparameter kann im laufenden Betrieb zur Ausführung an einen anderen Job übertragen werden. Dazu reicht es aus, nur anzugeben, aus welchem ​​Projekt die empfangene Variable übernommen werden muss. Außerdem wird ein Knoten als separater Parameter für die Ausführung übergeben. Hier wird gerade die Aufteilung in Laufzeiten auf DEV, TST, UAT, PRD implementiert. Ein separater Job wurde verwendet, um die empfangenen EDWEX-Dateien mit der Revisionsnummer an SVN zu übertragen, um Versionen der geänderten Strukturen verfolgen zu können.

Eine Beispielschnittstelle in Jenkins:



Das Ergebnis der Jobausführung ist die Erstellung und Installation der erforderlichen Artefakte, deren Übertragung an SVN und die Erstellung eines HTML-Berichts, der den Erfolg des Bestehens von Komponententests sowie die Ergebnisse der Zusammenstellung und Installation von Artefakten anzeigt. Jobs können einzeln mit Ihren Händen oder im automatischen Modus ausgeführt werden, nachdem zuvor eine Ausführungskette erstellt wurde.


Architektur des Montage- und Installationsmechanismus

Zusammenfassend


Es wurde viel Arbeit geleistet, um die Bildung von Artefakten zu automatisieren. Zuvor mussten Sie manuell auf den Server klettern, Shell-Skripte ausführen und dann die Daten lange Zeit mit Ihren Händen studieren und bearbeiten. Klicken Sie nun einfach auf die Schaltfläche Start, geben Sie die ID des Quellsystems, die Modellnummer und die Ausführungsschleife an. Mit Hilfe von Jenkins war es möglich, den gesamten Montage- und Installationsmechanismus von Artefakten in unabhängige Stufen zu strukturieren und zu zerlegen. Die notwendigen Überprüfungen wurden hinzugefügt, bevor mit der Bildung von Artefakten und deren Integration begonnen wurde. Die empfangenen Artefakte werden automatisch an SVN übertragen, was die Arbeit mit verwandten Teams von Systemanalysten und Datenmodellierern vereinfacht. Es werden Überprüfungen durchgeführt, um Leerlaufstarts der Artefaktbildung zu vermeiden und deren Richtigkeit zu bestätigen.

Infolgedessen haben wir den zeitaufwändigen Prozess des Zusammenstellens und Installierens von Modellartefakten von mehreren Stunden auf einige Minuten reduziert. Und vor allem haben sie das Auftreten von Fehlern aufgrund des menschlichen Faktors beseitigt, die unweigerlich in einem komplexen Routineprozess auftraten.

Source: https://habr.com/ru/post/de428101/


All Articles