Un requisito presente con grande frequenza nelle applicazioni cloud è quello di interagire con risorse on-premise. Il caso principale consiste nel poter utilizzare dall’applicazione cloud dati provenienti da uno o più database presenti all’interno di reti aziendali.
Questo tipo di integrazioni risulta spesso problematico perché:
- Le reti aziendali sono reti chiuse e non è pertanto possibile accedere dall’esterno alle risorse necessarie.
- La soluzione di creare API di accesso dal cloud verso l’azienda è costosa sia in termini di implementazione che di gestione della sicurezza della rete aziendale.
- Una soluzione alternativa è quella di pubblicare i dati aziendali tramite API cloud, ma è costosa in termini di implementazione e di duplicazione dei dati.
- La possibilità di creare VPN tra cloud e la rete interna pone problemi di gestione della sicurezza e di performance, oltre che di costi di infrastruttura e rigidità dell’architettura.
Tutti questi problemi vengono risolti utilizzando un componente presente nella piattaforma Instant Developer Cloud: il Cloud Connector.
Architettura di un Cloud Connector #
Il Cloud Connector è un agente software configurabile basato su Node.js che, installato all’interno della rete aziendale, apre una connessione websocket in uscita verso i server cloud per cui è stato configurato e consente alla controparte cloud di inviare comandi verso le risorse visibili della rete interna.
Nell’immagine precedente le righe viola rappresentano l’esecuzione di una query dal cloud verso il database interno alla rete aziendale, quelle verdi la restituzione al server nel cloud dei risultati del comando.
Questa soluzione ha diversi vantaggi rispetto alle varie alternative. Infatti:
- Non presenta costi di programmazione in quanto il Cloud Connector è un componente Node.js che richiede solo un file di configurazione per funzionare.
- Non crea problemi di sicurezza perché il Cloud Connector viene configurato solo localmente tramite un file che specifica a quali server nel cloud esso si può collegare; non richiede quindi porte aperte in entrata nella rete aziendale. Inoltre il Cloud Connector si può collegare solo alle risorse aziendali specificamente elencate nella configurazione.
- Fornisce performance elevate in quanto i protocolli di comunicazione websocket utilizzano tecniche di streaming di dati compressi e sono specializzate per la trasmissione dei comandi in modo asincrono.
- Non richiede alcuna forma di gestione dell’infrastruttura come invece avviene nel caso di VPN. È sufficiente installare il componente su un server interno per attivare l’integrazione con il cloud.
- Rappresenta un’architettura flessibile in quanto consente di collegare al medesimo server cloud un qualunque numero di reti aziendali, anche collegate alla stessa istanza di database cloud.
Risorse integrabili tramite il Cloud Connector #
Tramite un Cloud Connector è possibile integrare con il cloud i seguenti componenti software presenti nelle reti aziendali:
- Database di tipo SQL Server, Oracle, MySQL o PostgreSQL.
- Porzioni del file system del server in cui è installato il Cloud Connector.
- Un servizio di Active Directory presente all’interno della rete aziendale.
- Qualunque risorsa web raggiungibile all’interno della rete aziendale.
Installazione e configurazione del Cloud Connector #
Il Cloud Connector è un componente software disponibile per gli utenti di Instant Developer Cloud in codice sorgente aperto, scaricabile dal repository github. Le istruzioni di installazione sono contenute nel repository e i requisiti di installazione sono i seguenti:
- Installazione di Node.js sul server in cui sarà in funzione il Cloud Connector.
- Configurazione come servizio tramite il pacchetto Node pm2.
- Installazione dei sorgenti del Cloud Connector e aggiornamento delle dipendenze.
- Configurazione del Cloud Connector.
Il file di configurazione, di nome config.json e presente nella directory base dei sorgenti, contiene le seguenti sezioni:
- Elenco dei server cloud (sia di produzione che IDE) a cui il Cloud Connector si deve collegare.
- Elenco dei database utilizzabili dal cloud.
- Elenco dei file system utilizzabili dal cloud.
Nel pacchetto github è presente un esempio di file di configurazione che è possibile usare come template. Esso è visibile a questo link.
Analizziamo ora le varie sezioni del file di configurazione config.json del Cloud Connector.
Nella proprietà name va impostato il nome del Cloud Connector così come sarà visto dai server IDE e di produzione.
La proprietà remoteServers indica quali server di produzione verranno contattati dal Cloud Connector; questa sezione non va cancellata anche se non si utilizzano server di produzione al limite lasciarla vuota con le sole parentesi quadre.
La proprietà remoteUserNames indica a quali utenti è concesso l’accesso al Cloud Connector; è possibile indicare il nome utente e in questo caso lo specifico utente sarà abilitato su tutti i server IDE sui quali può operare. Oppure si può indicare il server (con il suo indirizzo completo) e il nome utente a specificare che solo su quel server IDE sarà utilizzabile il Cloud Connector per quell’utente. Un’ultima possibilità è indicare solo l’indirizzo del server IDE per abilitare tutti i suoi utenti all’utilizzo di un Cloud Connector. Nell’esempio di configurazione del Cloud Connector qui di seguito abbiamo che l’utente paolo-giannelli è abilitato a questo Cloud Connector su tutti i server IDE sui quali opera; l’utente giovanni solo sul server ide2-developer e per il server ide1-pro-gamma tutti i suoi utenti sono abilitati.
La proprietà remoteConfigurationKey è utilizzata per abilitare la configurazione remota del Cloud Connector. Qui sotto un esempio delle proprietà descritte fino ad ora.
{
"name": "pg-connector",
"remoteServers": [
"prod1-pro-gamma.instantdevelopercloud.com",
"prod3-pro-gamma.instantdevelopercloud.com"
],
"remoteUserNames": [
"paolo-giannelli",
"https://ide2-developer.instantdevelopercloud.com/@giobvanni",
"https://ide1-pro-gamma.instantdevelopercloud.com"
],
"remoteConfigurationKey": "e6159f20-2395-4405-8cfe-7ada5525a0f7",
"datamodels": [...]
}
Nella sezione datamodels è possibile indicare i database che si vogliono condividere le cui proprietà sono diverse a seconda del tipo di database. Negli esempi seguenti sono visualizzate le proprietà standard di ogni tipo di database; per specifiche proprietà di un particolare database consultare la documentazione di Node.js specifica.
Esempio di connessione ad un database di tipo SQL Server.
{
"name": "myDB1",
"class": "SQLServer",
"APIKey": "b475019c-1f9f-4bc9-b12c-4d36af07f664",
"connectionOptions": {
"user": "paolo-giannelli",
"password": "password",
"server": "127.0.0.1\\SQLEXPRESS",
"database": "mydb3",
"options": {
"useUTC": false
}
}
}
Esempio di connessione ad un database di tipo Postgres.
{
"name": "myDB2",
"class": "Postgres",
"APIKey": "7a556cbb-cfe6-4c5e-bc20-8a6bd90c5eff",
"connectionOptions": {
"user": "paolo-giannelli",
"password": "password",
"host": "localhost",
"database": "mydb2"
}
}
Esempio di connessione ad un database di tipo MySQL.
{
"name": "myDB3",
"class": "MySQL",
"APIKey": "e334852c-e353-49b9-8855-ebfd87dba6a4",
"connectionOptions": {
"user": "paolo-giannelli",
"password": "password",
"connectString": "localhost/mydb4"
},
"maxRows": 10000
}
Esempio di connessione ad un database di tipo Oracle.
{
"name": "myDB4",
"class": "Oracle",
"APIKey": "3be755df-1b48-4cc5-8c09-236716d37a46",
"connectionOptions": {
"user": "paolo-giannelli",
"password": "password",
"connectString": "localhost/mydb1"
},
"maxRows": 10000
}
Nella sezione fileSystems è possibile impostare le informazioni delle directory che si desidera condividere in sola lettura o anche in scrittura.
Un esempio di condivisione in lettura e scrittura.
"fileSystems": [
{
"name": "myFS",
"path": "C:\\users\\paolo-giannelli\\temp",
"permissions": "rw",
"APIKey": "5f927c1b-5e7b-42cd-9203-37fcf2f01b98"
}
]
Infine abbiamo la sezione plugins dove è possibile configurare l’accesso ad Active Directory.
"plugins": [{
"name" : "myAD" ,
"class" : "ActiveDirectory" ,
"APIKey" : "770c2c25-bad5-4d67-816d-eaa64753ddbf" ,
"config" : {
"url" : "ldapServerUrl" ,
"baseDN" : "dc = esempio, dc = com" ,
"nome utente" : "utente" ,
"password" : "password"
}
}
Utilizzo del Cloud Connector #
Per utilizzare le risorse disponibili tramite il Cloud Connector occorre seguire questi passi:
- Installare e configurare il Cloud Connector.
- Aggiungere come server remoti i propri server di produzione e il proprio server IDE. Nota: per utilizzare il Cloud Connector dai server di produzione è necessario attivare il corrispondente servizio aggiuntivo su tali server (nei server IDE è sempre abilitato).
- Impostare nel file di configurazione almeno una connessione ad un database e scegliere una API KEY.
- Nell’IDE di Instant Developer Cloud creare un nuovo Data Model ed inserire la stessa API KEY inserita nel file di configurazione.
A questo punto la connessione al Data Model mostra il nome del Cloud Connector a cui quel Data Model è collegato, come mostrato nell’immagine seguente.
Si noti che il flag Schema sola lettura viene impostato in modo permanente, in quanto non è possibile modificare la struttura del database tramite il Cloud Connector.
A questo punto è possibile importare la struttura delle tabelle contenute nel database e cominciare ad usarle come se questo fosse connesso localmente al server nel cloud.
Per i database connessi mediante il Cloud Connector è possibile indicare anche il fuso orario al quale appartiene mediante la proprietà timezone in modo da identificare correttamente tutti i campi di tipo datetime.
A livello di codice dell’applicazione, i database connessi tramite Cloud Connector sono utilizzabili con le stesse modalità descritte nei paragrafi precedenti. Occorre però tenere presente la differente architettura di accesso ai dati. Quindi:
- Le performance sono minori, se vengono comparate con il database PostgreSQL presente nei server IDE e di produzione.
- Se la connessione websocket si disconnette, una query può generare eccezione di Connection closed. Riprovando dopo qualche istante la stessa query funzionerà perchè il Cloud Connector gestisce la connessione in modo automatico.
- In caso di query con set di risultati molto ampio, prendere in considerazione la lettura dei dati in modalità paginata.
Cambio connettore a runtime #
Se occorre collegare istanze diverse di un database alla stessa applicazione in un server di produzione in funzione dell’utente che esegue la login è possibile cambiare a runtime il Cloud Connector da utilizzare mediante il metodo setRemoteConnector come da esempio seguente.
let cc = "nome-cloud-connector//nome-datamodel";
let apiKey = "e334852c-e353-49b9-8855-ebfd87dba6a4";
App.nome-database.setRemoteConnector(app, cc, apiKey);
Accesso al file system #
Per accedere al file system di un server messo a disposizione tramite il Cloud Connector è possibile utilizzare la classe RemoteFS.
Le istruzioni seguenti permettono di ottenere la lista dei file della directory images.
let cc = "nome-cloud-connector//nome-datamodel";
let apiKey = "e334852c-e353-49b9-8855-ebfd87dba6a4";
let rfs = new App.RemoteFS(app, cc, apiKey);
let dir = rfs.directory("images");
let lista = yield dir.list();
Le istruzioni seguenti permettono di creare un file sul file system remoto partendo da un file esistente nel server dell’applicazione.
let cc = "nome-cloud-connector//nome-datamodel";
let apiKey = "e334852c-e353-49b9-8855-ebfd87dba6a4";
let rfs = new App.RemoteFS(app, cc, apiKey);
let fr = rfs.file(nomeFile);
yield picture.put(fr);
Utilizzo Web API locali #
Se nella rete locale di un server oppure su di un computer locale, non esposto con un indirizzo pubblico su internet, abbiamo delle Web API che vorremmo testare da un server IDE di Instant Developer Cloud possiamo utilizzare il Cloud Connector per accedervi.
Per accedere ad una Web API locale occorre avere un Cloud Connector che condivida una directory del file system locale e qui di seguito vediamo un esempio di codice.
let cc = "nome-cloud-connector//nome-datamodel";
let apiKey = "e334852c-e353-49b9-8855-ebfd87dba6a4";
let rfs = new App.RemoteFS(app, cc, apiKey);
let url = "http://192.168.0.32/MyApp/Supplier/" + key;
let u = rfs.url(url);
let retInfo = {};
//
try {
let res = yield u.get();
//
// Tutto ok - nel body ho l'entità Supplier
if (res.status === 200) {
let sup = JSON.parse(res.body);
retInfo = {supplier : sup, error : ""};
}
//
// Richiesta errata - nel body ho una stringa di errore
if (res.status === 400) {
retInfo = {supplier : null, error : res.body};
}
//
// Entità non trovata - nel body ho una stringa di errore
if (res.status === 404) {
retInfo = {supplier : null, error : res.body};
}
//
if (res.error) {
retInfo = {supplier : null, error : res.error};
}
}
catch (err) {
// Il Cloud Connector non è stato trovato
retInfo = {supplier : null, error : err.stack};
}
Controllo remoto #
Il Cloud Connector ha una serie di metodi che ne permettono il controllo da remoto attraverso l’applicazione a cui è collegato. È possibile eseguire il riavvio, la modifica di config.json, l’aggiornamento del software. Per consentire la configurazione da remoto occorre impostare il parametro remoteConfigurationKey da utilizzare nell’applicazione di controllo per autorizzare l’accesso. In particolare è possibile utilizzarei metodi:
- app.listCloudConnectors() per ottenere la lista dei Cloud Connector connessi al server su cui è in esecuzione l’applicazione;
- app.pingCloudConnector() per eseguire il ping al Cloud Connector per verificare se connesso e funzionante;
- app.changeCloudConnectorConfig() per cambiare la configurazione del Cloud Connector;
- app.changeCloudConnectorSouceCode() per aggiornare i sorgenti del Cloud Connector;
- app.restartCloudConnector() per riavviare il Cloud Connector.
Consultare la relativa guida nella reference dei singoli metodi nella documentazione in linea dell’IDE.
Di seguito un esempio di utilizzo del ping al Cloud Connector.
try {
let t1 = new Date();
yield app.pingCloudConnector("nome-connector");
let t2 = new Date();
console.log("Tempo di risposta: in millisecondi", t2 - t1);
}
catch (err) {
console.log("Nessuna risposta", err);
}
Note #
Attualmente Cloud Connector non supporta il caching_sha2_password come metodo di autenticazione su MySQL 8. Si consiglia invece di utilizzare il metodo di autenticazione legacy.
Nella connessione a SQL Server se viene utilizzato un certificato autofirmato alla lettura dei dati di struttura delle tabelle può verificarsi l’eccezione: “Failed to connect to: undefined – self signed certificate when connecting to MSSQL Server”.
In questi casi occorre impostare nelle opzioni del database i valori evidenziati qui sotto.
"connectionOptions": {
"user": "paolo-giannelli",
"password": "password",
"server": "127.0.0.1\\SQLEXPRESS",
"database": "mydb3",
"options": {
"encrypt": false,
"trustServerCertificate": true
Attenzione: l’impostazione del parametro trustServerCertificate al valore true rende insicura la connessione in quanto viene applicato un certificato auto firmato; si consiglia di utilizzarlo solamente in un ambiente di sviluppo dove le informazioni utilizzate sono dati di esempio.
Il parametro trustServerCertificate non deve essere utilizzato per i database in produzione.