BLOG
Wissenstransfer von IT-Spezialisten

File-Handling mit dem NetScaler über die NITRO API in PHP

English Version

Die NITRO-API welche der Citrix NetScaler bereitstellt, bietet vielseitige Möglichkeiten der Automatisierung. Dies ist vor allem bei GitHub in verschiedenen Projekten zu sehen. Eines davon ist das automatisierte BackUp Script auf Basis von PowerShell von meinem Kollegen Jens Trendelkamp.

Der Nachteil an diesem Script ist die Notwendigkeit von PSCP um Dateien via SCP zu übertragen, dies wollte ich ändern, also habe ich ein wenig recherchiert und in den Citrix eDocs die entsprechenden NITRO-API Funktionen entdeckt.

Im Vergleich zu vielen anderen REST-APIs, welche das File-Handlich üblicherweise über „multipart/form-data“ oder HTTP PUT realisieren, gibt es bei der NITRO-API eine Besonderheit: Es werden keine Dateien, sondern der Payload der Dateien selbst in Base64 als Payload via HTTP POST, übertragen.

Ich habe auf Basis der Citrix eDocs ein paar PHP-Funktionen (leider bin ich der PowerShell nicht mächtig genug) geschrieben um in einer Art „Proof-of-Concept“ zu demonstrieren, das PSCP nicht weiter notwendig ist. (NetScalerRocks war hierbei recht hilfreich)

Die Skripte beschreibe ich folgend, Updates gibt es in meinem GitHub Repository.

config.php

1
2
3
4
5
<?php
    $nitroNSIP   = "nsip";
    $nitroUser   = "nsroot";
    $nitroPass   = "nsroot";
?>

functions.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
<?php
 function getAuthCookie($nitroNSIP,$nitroUser,$nitroPass) {
    $nitroUrl    = "http://$nitroNSIP/nitro/v1/config/login/";
    $nitroReq    = "POST";
    $nitroData   = '{"login":{"username":"'.$nitroUser.'","password":"'.$nitroPass.'"}}';
    $nitroHeader = "Content-Type: application/vnd.com.citrix.netscaler.login+json";
    $ch = curl_init($nitroUrl);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HEADER, 1);
    curl_setopt($ch, CURLINFO_HEADER_OUT, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER,array($nitroHeader));
    curl_setopt($ch, CURLOPT_POSTFIELDS, $nitroData);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $nitroReq);
    $result = curl_exec($ch);
   
    preg_match_all('/^Set-Cookie:\s*([^\r\n]*)/mi', $result, $ms);
    $cookies     = array();
    foreach ($ms[1] as $m) {
        list($name, $value) = explode('=', $m, 2);
        $cookies[$name]     = $value;
    }
    
    curl_close($ch);
    return $cookies["NITRO_AUTH_TOKEN"];
 }
 
 function getFile($nitroNSIP,$authToken,$fileName,$fileLocation) {
    $nitroUrl    = "http://$nitroNSIP/nitro/v1/config/systemfile/$fileName?args=filelocation:$fileLocation";
    $nitroReq    = "GET";
    $nitroData   = '';
    $nitroHeader = "Cookie: NITRO_AUTH_TOKEN=$authToken";
    $ch = curl_init($nitroUrl);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER,array($nitroHeader));
    curl_setopt($ch, CURLOPT_POSTFIELDS, $nitroData);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $nitroReq);
    $data = curl_exec($ch);
    curl_close($ch);
    $file = json_decode($data, true);
    $file = $file['systemfile'][0];
    return $plainFile = base64_decode($file['filecontent']);
 }
 
 function sendFile($nitroNSIP,$authToken,$fileName,$localFileLocation,$fileLocation) {
    $file = file_get_contents($localFileLocation.$fileName, true);
    $filecontent = base64_encode($file);
    
    $nitroUrl    = "http://$nitroNSIP/nitro/v1/config/systemfile";
    $nitroReq    = "POST";
    $nitroData   = '{"systemfile": {"filename": "'.$fileName.'","filelocation": "'.$fileLocation.'","filecontent":"'.$filecontent.'","fileencoding": "BASE64"}}';
    $nitroCookie = "Cookie:NITRO_AUTH_TOKEN=$authToken";
    $nitroHeader = "Content-Type:application/vnd.com.citrix.netscaler.systemfile+json";
    
    $ch = curl_init($nitroUrl);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER,array($nitroCookie,$nitroHeader));
    curl_setopt($ch, CURLOPT_POSTFIELDS, $nitroData);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $nitroReq);
    $data = curl_exec($ch);
    $return = json_decode($data, true);
    print_r ($return);
    curl_close($ch); 
 }
 
 function logout($nitroNSIP,$authToken) {
    $nitroUrl    = "http://$nitroNSIP/nitro/v1/config/logout/";
    $nitroReq    = "POST";
    $nitroData   = '{"logout":{}}';
    $nitroCookie = "Cookie:NITRO_AUTH_TOKEN=$authToken";
    $nitroHeader = "Content-Type: application/vnd.com.citrix.netscaler.logout+json";
    $ch = curl_init($nitroUrl);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER,array($nitroCookie,$nitroHeader));
    curl_setopt($ch, CURLOPT_POSTFIELDS, $nitroData);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $nitroReq);
    
    curl_exec($ch);
    curl_close($ch);
    unset($authToken);
}
?>

Der Datei Download wird mit der Funktion „getFile“ aufgerufen, dabei übergebe ich über das worker-script den Relativen Pfad der Datei aus dem NetScalers im ASCII Format. Darauß erschließt sich das aus „/var/netscaler/something“ also „%2Fvar%2Fnetscaler%2Fsomething“ wird. Als Rückgabe erhalte ich die Datei als JSON im Base64 Format im Feld „filecontent“. Dieses wird decodiert und anschließend lokal als Datei gespeichert.

Der Upload von Dateien wird mit „sendFile“ aufgerufen. Hierbei wird im worker-script der Dateiname, der lokale Pfad und der Pfad auf dem NetScaler (relativ!) übergeben. Es ist nicht notwendig ASCII zu enkodieren. Die Funktion liest die Datei ein, wandelt diese in ein Base64 Encoding um und übergibt den Payload mittels JSON an den NetScaler.

worker.sample.php – Beispiele zur Nutzung der Funktionen.

1
2
3
4
5
6
7
8
9
10
11
<?php
include('config.php');
include ('functions.php');
$fileName = "testfile2.txt";
$localFileLocation = "/Users/skolodziej/ownCloud/Projekte/_dev/netscaler/php-ns-framework/";
$fileLocation = "/nsconfig/ssl/";
$authToken = getAuthCookie($nitroNSIP,$nitroUser,$nitroPass);
//$file = getFile($nitroNSIP,$authToken,$fileName,$fileLocation);
//file_put_contents($fileName, $file);
sendFile($nitroNSIP,$authToken,$fileName,$localFileLocation,$fileLocation)
?>