Allgemein

Shell Script zum Kopieren

Veröffentlicht am

Ich habe mir heute mal ein keines Shell Script geschrieben, welches mir Dateien hin und hier schiebt. Ziel war es die Daten von meinem Test System in die Produktiv Ordner meines Webserver zu schieben. Da es mehrere Ordner sind, war und ist es ziemlich mühselig Änderungen auf die produktiven Seiten zu kopieren. Die Funktionsweise ist eigentlich ziemlich schnell erklärt. Im Array sind meine Produktiv Systeme, bzw. Ordner. In der ersten IF-Anweisung prüft er ob die Datei, die ich der Shell als Parameter übergeben habe, überhaupt im Test existiert. Sollte dies der Fall sein, springt das Script in ein Loop über das Array und prüft auch dort nach, ob es diese Datei gibt.
Die zweite IF-Anweisung prüft, ob diese Datei im Produktiv System zur Verfügung steht. Falls dies der Fall ist, gibt es eine kleine Nachricht, dass diese Datei existiert und kopiert die Datei aus dem Test System in alle Produktiv System. Falls die Dateien nicht existieren, gibt es eine jeweilige Nachricht.

 

#!/bin/bash

echo $1
array=('Folder1' 'Folder2' 'Folder3' 'Folder4' 'Folder5' 'Folder6' 'Folder7')

if [ -f 'FolderTEST/'$1 ]
then
 for i in "${array[@]}"
  do

   if [ -f $i/$1 ]
   then
     echo $i/$1 'exists, going to replace'
     cp -f 'FolderTEST/'$1 $i/$1
   else
     echo $i/$1 ' does not exist in ' $i
   fi

  done
else
 echo 'File does not exists in TEST'
fi

Ziemlich klein und einfach gehalten aber es erfüllt seinen Zweck 😉

Blog

MSSQL Erweiterte Eigenschaften löschen

Veröffentlicht am

Heute habe ich von einer on-premise Datenbank eine .bacpac Datei erzeugt, damit ich die DB in Azure migrieren kann. Der Datenbankserver ist ein SQL 2008 gewesen. Eine BacPac speichert das Datenbankschema und die enthaltenen Daten. Der Hauptzweck einer solchen Datei ist es, eine Datenbank von einem Server zum anderen zu kopieren. Aber auch die Migrierung in die Cloud kann mit diesem Format erledigt werden. Die eigentlichen Daten werden innerhalb der Datei in JSON Format abgespeichert. Vorweg muss ich sagen, dass ich diesen Test nicht mit einer Produktiv DB gemacht habe, sondern mit einer Kopie in meinem lokalen SQLExpress.

 

BacPac erzeugen

Um eine BacPac zu erzeugen muss die Datenbank, exportiert werden .
Den ganzen Wizard gehe ich nicht durch, aber hier kann gewählt werden, ob die Extraktion direkt in Azure geladen werden soll oder lokal abgespeichert wird. Für Azure wird ein Speicherkonto, Schlüssel und der Container benötigt.

Nachdem ich den Wizard durch hatte, startete der Export, der jedoch fehl schlug. Schnell fand ich heraus, dass es wiederkehrende Fehler sind und ich nur 3 eigentliche Fehler hatte.

Einer davon lautete wie folgt:

Error SQL71564: Das Erweiterte Eigenschaft: [dbo].[DB_VIEW].[MS_DiagramPane1]-Element wird nicht unterstützt, wenn es als Teil eines Datenpakets ('.bacpac') verwendet wird.

 

 

 

Was hat dieser Fehler zu bedeuten?

Jede View hat ihre speziellen Eigenschaften, die in Eigenschaften -> Erweiterte Eigenschaften eingesehen werden können. Hier sind auch MS_DiagramPane1 und MS_DiagramPaneCount zu finden. Beide sind zuständig für das MSSQL Diagramm, welches bei der Erstellung der View angezeigt wird. Da ich dieses Diagramm eh nicht verwende, hatte ich auch keine Probleme damit diese Werte zu löschen. Allerdings wollte ich nicht alles per Hand löschen, somit habe ich mir ein kleines Script geschrieben.

USE DB 

GO

DECLARE @Vname varchar(100)
DECLARE @Vtype varchar(10)
DECLARE @Property varchar(20)

DECLARE MY_CURSOR CURSOR
  LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR
select sys.views.name,sys.views.type_desc,sys.extended_properties.name
from sys.extended_properties INNER JOIN sys.views on sys.extended_properties.major_id = sys.views.object_id
where sys.extended_properties.name in ('MS_DiagramPane1','MS_DiagramPaneCount')

OPEN MY_CURSOR
FETCH NEXT FROM MY_CURSOR INTO @Vname, @Vtype, @Property
WHILE @@FETCH_STATUS = 0
BEGIN
  EXEC sp_dropextendedproperty
  @name = @Property
  ,@level0type = 'schema'
  ,@level0name = 'dbo'
  ,@level1type = @Vtype
  ,@level1name = @Vname
  FETCH NEXT FROM MY_CURSOR INTO @Vname,@Vtype, @Property
END
CLOSE MY_CURSOR
DEALLOCATE MY_CURSOR

Das Select holt mir alle Views mit den beiden Attributen MS_DiagramPane1 und MS_DiagramPaneCount. Das daraus resultierende Resultset liefert mir den Viewnamen, den Typ und den Attributnamen. Mit Hilfe des Cursors kann ich jede einzelne Zeile im Resultset bearbeiten. Um Attribute zu löschen benutze ich den befehl sp_dropextendedproperty. Dieser erwartet einige Argumente, die in der Microsoft Knowledgebase nachzulesen sind.

https://docs.microsoft.com/de-de/sql/relational-databases/system-stored-procedures/sp-dropextendedproperty-transact-sql?view=sql-server-2017 

 

Allgemein

ZPL Online Viewer

Veröffentlicht am
Zebra Logo
Zebra Logo

Wer sich mit Etiketten beschäftigt wird zweifelsohne über ZEBRA stoßen und dementsprechend auch über deren Druckerbeschreibungssprache ZPL. Mit dieser Sprache definiert man das Sichtbare auf dem Etikett. Ich möchte nicht in Detail gehen, wie ZPL funktioniert. Es gibt Blöcke die definieren den Start- und Endpunkt. Aber auch jene die sagen das jetzt ein QR Code, ein normaler Text, Barcode oder einfach nur ein Bild kommt.

Wer mehr über die einzelnen Felder und deren Commands wissen möchte kann den Programming Guide von Zebra benutzen. Dazu folgt einfach diesen Link.

https://www.zebra.com/content/dam/zebra/manuals/printers/common/programming/zpl-zbi2-pm-en.pdf

 

Warum ich hier allerdings schreibe hat einen anderen Grund. Um den selbst erstellten ZPL Code zu testen, ist es mühselig immer wieder das Etikett zu drucken. Nach ein bisschen Internet Recherche habe ich jedoch eine Seite gefunden, die den Code online übersetzen und das entsprechende Label ausgeben kann. So werden nicht etliche Etiketten durch die Testdrucke verschwendet. Falls ihr ebenfalls Interesse an einem Online Test der ZPL Sprache habt, folgt diesen Link.

http://labelary.com/viewer.html

Die Tests, die ich bisher mit der Seite gemacht habe, liefen allesamt zufriedenstellend ab.
Dabei kann das erstellte Etikett als Datei, als PDF oder als PNG heruntergeladen werden.

Blog

MSSQL Error User Group or Role Already Exists in the Current Database

Veröffentlicht am

Ist euch das schon einmal passiert, das ihr eine Datenbank wiederhergestellt habt und euch mit dem User nicht mehr anmelden konntet, mit dem ihr euch vorher angemeldet hattet? Auch ein Ändern der Berechtigungen für besagten User scheitert. Es kommt zu der Fehlermeldung (User, group, or role ‘username’ already exists in the current database (Microsoft SQL Server, Error: 15023).. Was also nun, wenn der Benutzer zwar existiert, aber nicht mehr benutzt werden kann? Im Netz hat dieses Problem schon den Namen ‚orphan user‘ bekommen. Das heißt soviel wie verweißter Benutzer.Der Befehl sp_change_users_login bietet hier Abhilfe. Wenn ihr auf der fehlerhaften Datenbank folgenden Befehl ausführt, dann wird euer ehemaliger Benutzer wieder „freigeschaltet“. Alles in allem ein sehr einfacher Fix.

sp_change_users_login 'AUTO_FIX', 'username'

Microsoft selbst erwähnt in seinen SQL Docs diesen Befehl nicht zu benutzen und auf ALTER USER umzusteigen. Es könnte sein, dass er in neueren MSSQL Releases entfernt wird. Bisher funktioniert er allerdings noch tadellos.

Mehr über den Befehl findet ihr hier:

https://docs.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-change-users-login-transact-sql?view=sql-server-2017

 

Blog

Icinga2 – check_mssql_health

Veröffentlicht am

Das check_mssql_health Modul kann in Icinga2, als auch in Nagios dazu verwendet werden, seine MSSQL Datenbank zu überwachen. Dabei können Checks von Verbindungszeiten, Deadlocks, angemeldete User, existierende Tabellen und viele weitere ausgewählt werden. So macht es das Modul zu einem starken Tool für die Datenbanken. Leider wird check_mssql_health nicht bei der icinga2 respektive nagios mit installiert und muss manuell nachgeholt werden. Ich rede hier von der Installation über den Packet Manager. Die Installation dabei ist aber relativ einfach. Ich gehe davon aus, dass Icinga aus dem Repository heruntergeladen und nach Standard Parametern installiert worden ist.

 

 

Vorbereitung

Um mssql_health vollständig und erfolgreich installieren zu können, müssen einige Vorbereitungen getroffen werden, die ich hier kurz erläutere. Zunächst müssen ein paar Pakete nachinstalliert werden.

apt install libdbd-sybase-perl freetds-common freetds-dev freetds-bin

Dann laden wir die aktuelle mssql_health Version mit wget runter, was in meinem Fall(10.11.2018) die Version 2.6.4.14 ist.

wget https://labs.consol.de/assets/downloads/nagios/check_mssql_health-2.6.4.14.tar.gz

Natürlich müssen wir die tar.gz jetzt noch entpacken und gehen direkt in das neu erstellte Verzeichnis hinein.

tar xvzf check_mssql_health_2.6.4.14
cd check_mssql_health_2.6.4.14

Sobald wir im Verzeichnis sind, fangen wir an mssql_health zu kompilieren. Ich benutze jeweils die default Parameter. Änderungen können sonst mit dem ./configure Command geändert werden.

./configure
make
make install

Wenn die Kompilierung abgeschlossen und das Modul installiert ist, sollten wir überprüfen, ob es nicht doch noch eigene Syntax Errors im Perl Code gibt. Wenn alles soweit in OK ist, kopieren wir das Script in das jeweilige Icinga Verzeichnis

cd plugin-scripts/
perl -c check_mssql_health
cp check_mssql_health /usr/lib/Nagios/plugins

Zuguterletzt müssen wir eine Datenbank-Instanz in der freetds.conf einfügen. Dort ist schon ein Beispiel vorhanden, welches wir einfach für unsere Einstellungen übernehmen können. Falls dieser Eintrag übersprungen wird, kann keine Verbindung mit der Datenbank hergestellt werden.

nano /etc/freetds/freetds.conf

Aus Sicherheitsgründen sollten wir das TDS Protokoll noch auf Version 8.0 ändern. Die anderen Versionen verschicken Username/Passwort im Klartext. Somit hätten wir die Installation + Einrichtung des Modules vollzogen. Machen wir weiter mit der Konfiguration der Datenbank.

 

 

Datenbank einrichten

Das schöne an der Datenbank Einrichtung ist, dass wir hier nicht viel machen müssen. Auf der Projekt Seite steht ein vorgefertigtes Script zur Verfügung. Es ist zu empfehlen sich einen SQL-Benutzer anzulegen und diesen in der dafür vorgesehenen Stelle im Script anzugeben.

declare @dbname varchar(255)
declare @check_mssql_health_USER varchar(255)
declare @check_mssql_health_PASS varchar(255)
declare @check_mssql_health_ROLE varchar(255)
declare @source varchar(255)
declare @options varchar(255)
declare @backslash int

/*******************************************************************/
SET @check_mssql_health_USER = '"icinga"'
SET @check_mssql_health_PASS = 'password'
SET @check_mssql_health_ROLE = 'icinga'
/******************************************************************

PLEASE CHANGE THE ABOVE VALUES ACCORDING TO YOUR REQUIREMENTS

- Example for Windows authentication:
  SET @check_mssql_health_USER = '"[Servername|Domainname]\Username"'
  SET @check_mssql_health_ROLE = 'Rolename'

- Example for SQL Server authentication:
  SET @check_mssql_health_USER = 'Username'
  SET @check_mssql_health_PASS = 'Password'
  SET @check_mssql_health_ROLE = 'Rolename'

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
It is strongly recommended to use Windows authentication. Otherwise
you will get no reliable results for database usage.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

*********** NO NEED TO CHANGE ANYTHING BELOW THIS LINE *************/

SET @options = 'DEFAULT_DATABASE=MASTER, DEFAULT_LANGUAGE=English'
SET @backslash = (SELECT CHARINDEX('\', @check_mssql_health_USER))
IF @backslash > 0
  BEGIN
    SET @source = ' FROM WINDOWS'
    SET @options = ' WITH ' + @options
  END
ELSE
  BEGIN
    SET @source = ''
    SET @options = ' WITH PASSWORD=''' + @check_mssql_health_PASS + ''',' + @options
  END

PRINT 'create Nagios plugin user ' + @check_mssql_health_USER
EXEC ('CREATE LOGIN ' + @check_mssql_health_USER + @source + @options)
EXEC ('USE MASTER GRANT VIEW SERVER STATE TO ' + @check_mssql_health_USER)
EXEC ('USE MASTER GRANT ALTER trace TO ' + @check_mssql_health_USER)
EXEC ('USE MSDB GRANT SELECT ON sysjobhistory TO ' + @check_mssql_health_USER)
EXEC ('USE MSDB GRANT SELECT ON sysjobschedules TO ' + @check_mssql_health_USER)
EXEC ('USE MSDB GRANT SELECT ON sysjobs TO ' + @check_mssql_health_USER)
PRINT 'User ' + @check_mssql_health_USER + ' created.'
PRINT ''

declare dblist cursor for
  select name from sysdatabases WHERE name NOT IN ('master', 'tempdb', 'msdb') open dblist
    fetch next from dblist into @dbname
    while @@fetch_status = 0 begin
      EXEC ('USE [' + @dbname + '] print ''GRANT permissions IN the db '' + ''"'' + DB_NAME() + ''"''')
      EXEC ('USE [' + @dbname + '] CREATE ROLE ' + @check_mssql_health_ROLE)
      EXEC ('USE [' + @dbname + '] GRANT EXECUTE TO ' + @check_mssql_health_ROLE)
      EXEC ('USE [' + @dbname + '] GRANT VIEW DATABASE STATE TO ' + @check_mssql_health_ROLE)
      EXEC ('USE [' + @dbname + '] GRANT VIEW DEFINITION TO ' + @check_mssql_health_ROLE)
      EXEC ('USE [' + @dbname + '] CREATE USER ' + @check_mssql_health_USER + ' FOR LOGIN ' + @check_mssql_health_USER)
      EXEC ('USE [' + @dbname + '] EXEC sp_addrolemember ' + @check_mssql_health_ROLE + ' , ' + @check_mssql_health_USER)
      EXEC ('USE [' + @dbname + '] print ''Permissions IN the db '' + ''"'' + DB_NAME() + ''" GRANTED.''')
      fetch next from dblist into @dbname
    end
close dblist
deallocate dblist

Haben wir das Script ausgeführt, können wir außerhalb von Icinga testen, ob unsere Einstellungen soweit korrekt sind. Hierzu führen wir eine erste Überprüfung durch.

./check_mssql_health –server=wpsql3 –port=1433 –username=icinga –password=<password> --mode=locks-deadlocks –commit

Wenn dieser Check erfolgreich war, haben wir die Datenbank und das mssql_health modul korrekt installiert und eingerichtet. Jedoch fehlen noch die Änderungen in Icinga, damit dieser die Checks überhaupt ausführen kann. Ich hab es soweit eingerichtet, dass ich jedem Host mehrere Serviceobjekte von mssql_health zuweisen kann. Diese Objekte führen unterschiedliche Checks aus. Dazu habe ich einen Command angelegt, der bestimmte Parameter erwartet, aber auch solche die schon fest zugewiesen sind, wie Benutzername und Passwort.

object CheckCommand "checkmssql_health" {
   import "plugin-check-command"

   command = [PluginDir + "/check_mssql_health"]

   arguments = {
   "--server" = "$mssqlhealth_server$"
   "--username" = "$mssqlhealth_username$"
   "--password" = "$mssqlhealth_password$"
   "--mode" = "$mssqlhealth_mode$"
   "--critical" = "$mssqlhealth_critical$"
   "--warning" = "$mssqlhealth_warning$"
   "--commit" = ""

   }

   vars.mssqlhealth_username = "icinga"
   vars.mssqlhealth_password = "passwort"

}

Der erstellte Service geht dabei durch jedes, im Host Objekt angegebene, mssql_health Objekt.

apply Service "mssql_check_health" for (mode => config in host.vars.mssqlhealth_modes){
  import "generic-service"

  check_command = "checkmssql_health"

  vars.mssqlhealth_mode = mode

  vars+=config

  vars.mssqlhealth_critical = config.mssqlhealth_critical
  vars.mssqlhealth_warning = config.mssqlhealth_warning

   assign where ((host.address || host.address6) && host.vars.mssql == "true")
}

Mein Host Objekt sieht dementsprechend so aus und ist gefüllt mit mehreren Modis des Modules.

vars.mssqlhealth_modes["connected-users"] = {
     mssqlhealth_modes = "connected-users"
     mssqlhealth_warning = "1100"
     mssqlhealth_critical = "1500"
  }
vars.mssqlhealth_modes["locks-waits"] = {
     mssqlhealth_modes = "locks-waits"
     mssqlhealth_warning = "1"
     mssqlhealth_critical = "2"
  }
vars.mssqlhealth_modes["locks-deadlocks"] = {
     mssqlhealth_modes = "locks-deadlocks"
     mssqlhealth_warning = "1"
     mssqlhealth_critical = "2"
  }
vars.mssqlhealth_modes["database-backup-age"] = {
     mssqlhealth_modes = "database-backup-age"
     mssqlhealth_warning = "24"
     mssqlhealth_critical = "48"
  }

In „modes“ werden die verfügbaren Modis von mssql_health eingetragen, während die anderen beiden den jeweils kritischen und warnenden Zustand angeben.

Haben wir alles soweit eingerichtet muss selbstverständlich der Icinga Service neugestartet werden, damit die vollzogenen Änderungen überhaupt aktiv werden

service icinga2 restart

Fazit

Wenn alles geschafft ist, haben wir unser Monitoring Tool für MSSQL Datenbanken erweitert und können dementsprechend Checks ausführen. Die Installation von mssql_health an sich ist einfach nur die jeweilige Integration in Icinga bedarf etwas Überlegung. Natürlich kann das Modul auch auf andere Wege in Icinga implementiert werden. Dort stehen alle Möglichkeiten offen. Ich habe mich für diese Integration entschieden, da ich für mich hier die meisten Vorteile sehe. Mit dieser Art der Erstellung müssen nur noch im Host Objekt die einzelnen Modis mit ihren Werten eingeben werden.  So kann auf einfachste Weise ein neuer Check eingefügt werden, ohne den Service bzw. den Command anpacken zu müssen.

Fotografie

Meine Ausrüstung

Veröffentlicht am

Über die Zeit hinweg hat sich meine Ausrüstung für die Kamera stetig erweitert und vergrößert. Mittlerweile zähle ich 8 Objektive, 2 Stative und natürlich meine Canon EOS 700D Kamera.
Preislich gehen meine Objektive dabei von 100€ – 800€. Unter anderem verfüge ich über Tele-, Makro- und Weitwinkelobjektive, wobei jedes zu bestimmten Anlässen benutzt wird.

Weitwinkel:

  • Sigma 24mm F1,4 DG HSM Art Objektiv
  • Sigma 10-20 mm F3,5 EX DC HSM-Objektiv
  • Canon EF-S 10-18mm 1:4.5-5.6 IS STM

 

Makro:

  • Sigma 105 mm F2,8 EX Makro DG OS HSM-Objektiv

 

Tele:

  • Tamron SP 150-600mm F/5-6.3 Di VC USD Teleobjektiv
  • Tamron AF SP 70-300mm 4-5.6 Di VC USD
  • Canon Tele-Zoomobjektiv EF-S 55-250mm 1:4-5,6 IS STM

 

Standard-Zoomobjektiv:

  • EF-S 18-55mm 1:3,5-5,6 IS STM

 

Anderes:

  • Sigma USB-Dock für Canon Objektivbajonett
  • HIILIGHT LED Taschenlampe 2500 Extrem Hell – CREE XM-L T6
  • K&F Concept® TM2515 Reisestativ Dreibeinstativ Aluminium Kamerastativ
  • Cullmann ALPHA 2500 Stativ mit 3-Wege-Kopf
  • Glaskugel 8cm klar massiv handpoliert
  • Canon RC-6 Infrarot-Fernauslöser
  • Canon EW-63C Streulichtblende (EF-S 18-55mm f/3.5-5.6 IS STM Objektiv)
  • Canon ET-63 – Gegenlichtblende
Microsoft

Windows Lizenzen auslesen

Veröffentlicht am

Gelegentlich, z.B. für Audits oder ähnliches, müssen die verwendeten Lizenzschlüssel der einzelnen Microsoft Server, bestehend aus Betriebssystem und eventuell vorhandener Microsoft Applikation wie z.B. den SQL Server ausgelesen werden. Für beide Operationen gibt es unterschiedliche Scripte im Internet zu finden. Vorstellen werde ich eins für den SQL Server und eins für das Betriebssystem von Microsoft. Beide sollten ihren Nutzen in einer homogenen Microsoft Landschaft ausspielen. Sie können für kommerzielle als auch private Audits genutzt werden.

 

 

SQL Server Lizenz

 

Das Script habe ich gefunden bei:
https://gallery.technet.microsoft.com/scriptcenter/Get-SQL-Server-Product-4b5bf4f8

Voraussetzung ist die Verwendung von Powershell. Es lassen sich lokale Keys als auch remote Keys auslesen. Es stellt die SQL Instanz, die SQL Version und Edition, und natürlich den Lizenz Key bereit.

Beispiele:

Get-SqlServerKeys

Holt die SQL Server Version, Edition und Key der lokalen Maschine

Get-SqlServerKeys sqlservera, sqlserver2014a, sql01

Holt die SQL Version, Edition und Keys für alle Instanzen auf sqlservera, sqlserver2014a und sql01.

Get-SqlServerKeys -CentralMgmtServer sqlserver01

Holt die SQL Server version, Edition und Keys für alle SQL Server Datenbank Instanzen innerhalb des Central Management Server auf sqlserver01

Get-SqlServerKeys -ServersFromFile C:\Scripts\servers.txt -verbose

Holt die SQL Server Version, Edition und Keys für alle SQL Server die in C:\Scripts\servers.txt gelistet sind.

 

Windows Betriebssystem

 

Für die Betriebssystem Lizenz habe ich ein VBS Script in der Microsoft Community gefunden, welches ich euch nicht vorenthalten möchte. Gefunden habe ich es hier:

https://answers.microsoft.com/en-us/insider/forum/insider_wintp-insider_repair/how-to-find-all-windows-version-serial-key/a6d7e4eb-2adf-4e57-8ead-0bd85ec2758d

Kopiert dazu folgende Codezeilen in einem Editor wie z.B. Notepad und speichert es mit der Endung .vbs ab.

Set WshShell = CreateObject("WScript.Shell")
MsgBox ConvertToKey(WshShell.RegRead("HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\DigitalProductId"))

Function ConvertToKey(Key)
Const KeyOffset = 52
i = 28
Chars = "BCDFGHJKMPQRTVWXY2346789"
Do
Cur = 0
x = 14
Do
Cur = Cur * 256
Cur = Key(x + KeyOffset) + Cur
Key(x + KeyOffset) = (Cur \ 24) And 255
Cur = Cur Mod 24
x = x -1
Loop While x >= 0
i = i -1
KeyOutput = Mid(Chars, Cur + 1, 1) & KeyOutput
If (((29 - i) Mod 6) = 0) And (i <> -1) Then
i = i -1
KeyOutput = "-" & KeyOutput
End If
Loop While i >= 0
ConvertToKey = KeyOutput
End Function

 

Fotografie

Sigma 24mm F1,4 DG HSM Art Objektiv

Veröffentlicht am

Vor kurzem haben ich mir das Sigma 24mm F1,4 DG HSM Art Objektiv gekauft. Mit dem Kauf habe ich mich schwer getan, da ich als Alternative das Sigma 18-35mm F1,8 DC HSM Art Objektiv im Visier hatte. Beides an für sich ziemlich gute Objektive und von der Sigma ART Reihe, die ohnehin gute Bildqualität liefert. Als ich mich im Internet schlau gemacht habe, haben sich einige für das 18 – 35mm Objektiv, aufgrund seiner Flexibilität, ausgesprochen zudem ist es explizit für den ASP-C Sensor. Andere wiederum sahen den Aspekt, dass das 24mm auch auf Vollformat Kameras verwendet werden kann, falls man in Zukunft eben auf jene umsteigen möchte und die größere Blende.

Warum viel mir die Entscheidung so schwer?

Zum einen natürlich, da das Sigma 18-35 ebenfalls ein sehr gutes Objektiv ist. Man ist ein Stück flexibler mit der 18 – 35mm Brennweite, als es die Festbrennweite vom Sigma 24mm hergibt. Jedoch, und das war für mich entscheidend, hat das 24mm eine Blende von f1,4, was mir mehr Spielraum für die Astrofotografie gibt. So kann ich die ISO runterschrauben um Bild rauschen zu vermeiden. Ebenfalls sollte man bei dem APS-C Sensoren den Crop-Faktor nicht vergessen. Bei meiner Canon EOS 700D liegt der bei 1.6, was aus dem 24mm ungefähr ein 38mm auf dem APS-C Sensor macht. Natürlich wäre hier das andere Objekt mit seinem 18mm wieder im Vorteil. Ein Punkt für das 24mm von Sigma war die Kompatibilität mit dem Vollformat Sensor. Während das 18 – 35mm nur für den APS-C Sensor konstruiert wurde. Also musste ich abwägen, was mir lieber ist. Eine flexiblere Brennweite oder eine größere Blende. Schlussendlich habe ich mich für das 24mm Objektiv entschieden und bereue diese Entscheidung nicht.

Erster Testlauf mit der Kamera

Bisher mache ich mich noch mit dem neuen Objektiv vertraut, aber mein erster Versuch unter Nachthimmel hat mich ins Staunen versetzt. Das Objektiv macht einen soliden und stabilen Eindruck. Es ist das schwerste Weitwinkelobjektiv, welches ich besitze. Mein erster Testlauf fand hinten im Garten statt, es herrschte von umgebenen Häusern Streulicht, die meine Bilder verfälschten, aber selbst hier war ich von dem neuen Objektiv überzeugt. Mein nächster Ort wird weit entfernt von Streulichtern sein, wo ich mich einzig und alleine auf den Sternenhimmel und seine Vielfalt konzentrieren kann. Ich bin gespannt :).

Fotografie

TOTALE MONDFINSTERNIS AM 27.07.2018

Veröffentlicht am

Am 27.07.2018 war die totale Mondfinsternis, die ich mir nicht entgehen lassen wollte, schließlich passiert sowas nicht alle Tage. Also habe ich mich für diesen Tag vorbereitet. Mit meiner Canon und dem Tamron SP 150-600mm Teleobjektiv bin ich losgestiefelt und habe mir einen Spot ausgesucht, der weit entfernt von störenden, externen Lichtquellen ist. Während der totalen Mondfinsternis war es für mich extrem schwierig den Fokus zu setzen, aber durch herumprobieren ist es mir schließlich ganz gut gelungen. Da der Mond generell schwer zu sehen war, zu lange Belichtungszeiten aufgrund seiner Bewegungen nicht möglich waren, ging ich mit der ISO Wert auf höhere Werte. Die maximale Blende war mit 6.3 schon erreicht. Leider konnte ich mein Stativ nicht ordentlich standsicher machen, sodass viele Bilder aufgrund des Statives verwackelt wurden. Die Besten Ergebnisse habe ich mit folgenden Werten geschossen.

 

Bild 1:
  • ISO: 800
  • Blende: f/6.3
  • Belichtungszeit: 1/2 Sec
Bild 2:
  • ISO: 3200
  • Blende: f/6.3
  • Belichtungszeit: 1/4 Sec
Bild 3:
  • ISO: 12800
  • Blende: f/6.3
  • Belichtungszeit: 2,4 sec

 

Python

Python Datenbank Klasse

Veröffentlicht am

Für Python Datenbank Projekte habe ich eine Klasse geschrieben, die sich um die Verbindung und (bisher) Select und Insert Abfragen kümmert. Beim Definieren wird die Konstruktormethode aufgerufen und die Verbindungsparameter übergeben. Die Objektvariablen bekommen die jeweilige Eingaben zugewiesen.

def __init__(self,host,username,password,database): 
    self.host = host 
    self.username = username 
    self.password = password 
    self.database = database

Connect Methode

Die connect Methode benutzt die Objektvariablen und baut mit diesen Informationen die Verbindung zu der Datenbank auf. self.cnx speichert die erzeugte Session. Somit steht diese Session dem Code weiter zur Verfügung und kann vom nachfolgenden Code mit der cnx Variable aufgerufen werden.  Im Falle von Fehlern bei der Verbindung springt der Code in den Exception Block.

def connect(self): 
    config = { 
        'user': self.username, 
        'password': self.password, 
        'host': self.host, 
        'database': self.database 
    } 
    try: 
        self.cnx = mysql.connector.connect(**config) 
        self.cursor = self.cnx.cursor() 
        print colored("[I] + DB Connection established","green") 
    except mysql.connector.Error as err: 
        if err.errno == errorcode.ER_ACCESS_DENIED_ERROR: 
            print colored("[C] + Wrong Username/Password","red") 
        elif err.errno == errorcode.ER_BAD_DB_ERROR: 
            print colored("[C] + Database Error","red") 
        else: print colored("[C] + " + err,"red"

Query_Select Methode

In der query_select Methode werden, wie der Name schon sagt, die Select Abfragen ausgeführt. Die Funktion erwartet das SQL-Statement und falls vorhanden, die Parameters, die z.B. in der where clause mit angegeben werden können. Die IF-Anweisung überprüft dementsprechend, ob Parameters vorhanden sind und springt zum gültigen Programmblock. Bei der cursor.execute() Methode wird das Statement mit dem übergegebenen Parametern ausgeführt, während cursor.fetchall() alle Ergebnisse zurückliefert und in rtnvalue abspeichert. Tritt eine Exception auf, wird eine Fehlermeldung ausgegeben und die Funktion beendet sich mit einem False State.

def query_select(self,sqlstatement, params): 
    if (params is not None): 
        try: 
            self.cursor.execute(sqlstatement, (params,)) 
            rtnvalue = self.cursor.fetchall() 
            print colored("[I] + executed select with params","green") 
            return rtnvalue 
        except: 
            print colored("[C] + something went wrong while executing select with params:","red") 
            return False 
    else: 
        try: 
            self.cursor.execute(sqlstatement) 
            rtnvalue = self.cursor.fetchall() 
            print colored("[I] + executed select without params","green") 
            return rtnvalue 
        except: 
            print colored("[C] + something went wrong while executing select without params","red") 
            return None

Query_Insert Methode

Ähnlich wie die query_select Funktion funktioniert die query_Insert. Die Methode erwartet die Parameter als Dictionary, andernfalls kann die Funktion nicht richtig abgearbeitet werden, da zwei Variablen mit der key() beziehungsweise values() methode gefüttert werden. Diese genannten Methoden stehen nur Dictionaries zur Verfügung. In der sql Variable wird die Insert Query noch mit dem Spaltennamen in „column“ und die dazügehörigen Werte in „join(repr(e) for e in Values)“ gefüttert. cnx.commit  überträgt die Insert Einträge in die Datenbank. Falls das commit abbricht, springt der Code in die Exception und cnx.rollback() rollt den Insert wieder zurück. Abschließend beendet sich die Funktion mit einem False Statement.

def query_insert(self, sqlstatement, params):
    if (params is not None): 
        columns = ', '.join(params.keys()) 
        values = params.values() 
        sql = sqlstatement % (columns, ', '.join(repr(e) for e in values)) 
        print colored("[I] + " + sql,"yellow") 
        self.cursor.execute(sql) 
    else: 
        print colored("[C] + insert execution failed due missing parameters","red") 
        return False 
    try: 
        self.cnx.commit() 
        print colored("[I] + transaction committed, value added","green") 
        return True 
    except mysql.connector.Error as er: 
        self.cnx.rollback() 
        print colored("[C] + transaction rolled back: " + err.erno,"red") 
        return False

Disconnect Methode

Zum Schluss schliesst der Code die aktuelle Python Datenbankverbindung mit cnx.close().

def disconnect(self): 
   self.cnx.close() 
   print colored("[I] + Connection closed","green")

Vollständiger Code

Hier folgt der Code ohne Unterbrechung und Beschreibung:

import mysql.connector
from mysql.connector import errorcode
from termcolor import colored

class databaseconnection:

host=username=password=database=cnx=cursor=None

def __init__(self,host,username,password,database):
     self.host = host
     self.username = username
     self.password = password
     self.database = database

def connect(self):
    config = {
         'user': self.username,
         'password': self.password,
         'host': self.host,
         'database': self.database
     }
     try:
         self.cnx = mysql.connector.connect(**config)
         self.cursor = self.cnx.cursor()
         print colored("[I] + DB Connection established","green")
     except mysql.connector.Error as err:
         if err.errno == errorcode.ER_ACCESS_DENIED_ERROR:
        print colored("[C] + Wrong Username/Password","red")
     elif err.errno == errorcode.ER_BAD_DB_ERROR:
        print colored("[C] + Database Error","red")
     else:
         print colored("[C] + " + err,"red")

    def query_select(self,sqlstatement, params):
         if (params is not None):
             try:
                 self.cursor.execute(sqlstatement, (params,))
                 rtnvalue = self.cursor.fetchall()
                print colored("[I] + executed select with params","green")
                return rtnvalue
            except:
                 print colored("[C] + something went wrong while executing select with params:","red")
                 return False

        else:
            try:
                self.cursor.execute(sqlstatement)
                rtnvalue = self.cursor.fetchall()
                print colored("[I] + executed select without params","green")
                return rtnvalue
            except:
                print colored("[C] + something went wrong while executing select without params","red")
                return None

    def query_insert(self, sqlstatement, params):
        if (params is not None):
            columns = ', '.join(params.keys())
            values = params.values()
            sql = sqlstatement % (columns, ', '.join(repr(e) for e in values))
            print colored("[I] + " + sql,"yellow")
            self.cursor.execute(sql)
        else:
            print colored("[C] + insert execution failed due missing parameters","red")
            return False

        try:
            self.cnx.commit()
            print colored("[I] + transaction committed, value added","green")
            return True
        except mysql.connector.Error as er:
            self.cnx.rollback()
            print colored("[C] + transaction rolled back: " + err.erno,"red")
            return False

    def disconnect(self):
        self.cnx.close()
        print colored("[I] + Connection closed","green")