GRIMD Queue Management - Digital Forensics @ UniSa
Transcript
GRIMD Queue Management - Digital Forensics @ UniSa
Università degli Studi di Salerno Facoltà di Scienze Matematiche Fisiche e Naturali Corso di Laurea Magistrale in Informatica Tesina per il corso di Sistemi Operativi II GRIMD Queue Management Gestione code utenti tramite interfaccia web e refactoring architetturale di GRIMD Prof. Giuseppe Cattaneo Gruppo Antonio Balsamo Salvatore Cascone Anno Accademico 2011-2012 Indice 1 Introduzione 1.1 Grid Computing . 1.2 Motivazioni . . . 1.3 Caso di studio . . 1.3.1 Obiettivi . 1.4 Stato dell’arte . . 1.5 Risultati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 Le tecnologie 2.1 .NET Framework . . . . . . . . . . . . . . . 2.1.1 Entity Framework . . . . . . . . . . . 2.1.2 Membership . . . . . . . . . . . . . . 2.1.3 Windows Communication Foundation 2.2 SQL Server . . . . . . . . . . . . . . . . . . 2.3 Windows Server 2003 . . . . . . . . . . . . . 2.3.1 Internet Information Services . . . . 2.4 Virtual Private Network . . . . . . . . . . . 3 Refactoring architettura 3.1 GRIMD 1.1 . . . . . . 3.2 Modifiche apportate . 3.2.1 Sicurezza . . . 3.3 Requisiti minimi . . . . . . . . . . . . . . . . . . . i . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1 1 3 3 4 5 . . . . . . . . 6 6 8 11 12 13 14 14 15 . . . . 17 17 18 19 20 INDICE ii 4 Struttura del sistema 4.1 Gestione utenti . . . . . . . . . . . . . 4.2 Base dei dati . . . . . . . . . . . . . . 4.3 Servizio di gestione Master . . . . . . . 4.3.1 Modulo di identificazione Slave 4.3.2 Modulo di gestione coda . . . . 4.4 Modulo di controllo di stato del Master 4.5 Altre modifiche . . . . . . . . . . . . . 4.5.1 Master . . . . . . . . . . . . . . 4.5.2 FRED e GDUMP . . . . . . . . 4.5.3 Slave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 22 23 25 25 27 29 30 30 30 31 Conclusioni 32 Bibliografia 33 A Appendice A.1 Servizio di controllo stato Master A.1.1 IMasterStatus . . . . . . . A.1.2 MasterStatus . . . . . . . A.2 Servizio di coda . . . . . . . . . . A.2.1 IMasterQueue . . . . . . . A.2.2 MasterQueue . . . . . . . A.2.3 QueueHandler . . . . . . . A.3 Servizio identificazione slave . . . A.3.1 IVPNIDResolver . . . . . A.3.2 VPNIDResolver . . . . . . 34 34 34 34 37 37 37 41 48 48 49 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Capitolo 1 Introduzione 1.1 Grid Computing Al giorno d’oggi i sistemi di Grid Computing (Griglia Computazionale) rappresentano una diffusa infrastruttura di calcolo distribuito, utilizzati per l’elaborazione di grandi quantità di dati mediante l’uso di un grande numero di risorse. Il termine “griglia” fu coniato nella prima metà degli anni Novanta. Il principale problema alla base del concetto di griglia è la condivisione coordinata di risorse all’interno di un’organizzazione virtuale. La condivisione non è limitata solo allo scambio dei file, ma si estende all’accesso diretto a computer, a software ed in generale a tutto l’hardware necessario alla risoluzione di un problema scientifico, ingegneristico o industriale. Gli individui e le istituzioni, che mettono a disposizione della griglia le loro risorse per la medesima finalità, fanno parte della stessa organizzazione. 1.2 Motivazioni Caratteristica comune dei progetti di grid computing è la necessità di disporre un ambiente di calcolo data-intensive, all’interno del quale le applicazioni 1 CAPITOLO 1. INTRODUZIONE 2 hanno il bisogno di accedere a grandi quantità di dati geograficamente distribuiti in maniera veloce ed affidabile. Compito della griglia è far operare tali applicazioni nel miglior modo possibile. È facile osservare che nessun computer attualmente in commercio sarebbe in grado, da solo, di elaborare moli di dati abbastanza grandi in tempi ragionevoli. Tuttavia la condivisione di risorse quali CPU e dischi opportunamente coordinati può dare l’impressione all’utente di accedere ad un supercomputer virtuale, con una incredibile potenza computazionale e capacità di memorizzazione in grado di sopportare grandi carichi di lavoro. Tutta l’architettura di una griglia, vista come un unico supercomputer virtuale, nasconde una grande complessità interna. Per esempio è importante notare l’esigenza di progettare e realizzare uno scheduler di risorse, che rappresenta uno dei componenti critici del sistema di gestione delle risorse. Questo ha il compito di assegnare le risorse ai job, in modo da soddisfare le esigenze delle applicazioni e del sistema. Le risorse di cui esso deve tenere traccia e gestire includono sistemi di calcolo e sistemi di immagazzinamento dati. Lo scheduling è un campo tradizionale dell’informatica, ma nonostante siano state studiate molte tecniche per numerose tipologie di sistemi, le caratteristiche tipiche delle griglie di dati rendono molti di questi approcci inadeguati. Infatti, mentre nei sistemi tradizionali le risorse e i job sono sotto il diretto controllo dello scheduler, le risorse delle griglie invece sono geograficamente distribuite. Queste inoltre sono di natura eterogenea e appartengono a diversi individui o organizzazioni, ciascuna con le proprie politiche di scheduling, costi d’accesso, carichi di lavoro e disponibilità di risorse che varia dinamicamente nel tempo. La mancanza di un controllo centralizzato, insieme alla presenza di utenti che generano job, molto diversi l’uno dall’altro, rendono lo scheduling più complicato rispetto a quello dei sistemi di calcolo tradizionali. CAPITOLO 1. INTRODUZIONE 1.3 3 Caso di studio Nel corso del documento si discuterà delle modifiche apportate a GRIMD (Grid for Molecular Dynamics), un sistema concepito per effettuare calcolo distribuito tramite l’utilizzo di YASARA (Yet Another Scientific Artificial Reality Application) su una griglia di computer, sfruttando la loro potenza di calcolo nei periodi di inutilizzo. L’architettura prevede la presenza di una macchina master che coordina il lavoro di un numero indeterminato di slave. Attualmente il sistema è installato su alcune delle macchine presenti nel laboratorio Turing della facoltà di Informatica, nell’aula 33 e nel laboratorio di bioinformatica del dipartimento di scienze farmaceutiche e biomediche dell’Università degli Studi di Salerno. 1.3.1 Obiettivi L’intento è quello di estendere le capacità di GRIMD ad un ambito più ampio, accademico o aziendale, mantenendo la versione precedente e sviluppando una versione web che consenta l’utilizzo di computer appartenenti a diverse subnet, scavalcando i problemi dovuti alla presenza di NAT (Network Address Translation) e che permetta l’utilizzo a più utenti contemporaneamente. La versione attuale infatti è stata pensata per un utilizzo ristretto ad un ambito di laboratorio, la nuova versione dovrà invece far operare i computer attualmente disponibili insieme ad altri appartenenti a diversi laboratori. Tali computer sono normalmente inaccessibili dall’esterno della propria rete a causa della presenza di servizi come NAT o firewall. La nuova versione dovrà ovviare a questi problemi fornendo un’interfaccia web alla quale i vari utenti possano autenticarsi e sottomettere i propri lavori che saranno distribuiti sulla griglia ed eseguiti non appena questa sarà disponibile. Dovrà quindi essere gestita una coda dei vari lavori sottomessi dagli utenti ed eseguirli cercando di utilizzare la massima potenza di calcolo disponibile. CAPITOLO 1. INTRODUZIONE 1.4 4 Stato dell’arte Uno dei progetti, forse anche il più famoso, che più si avvicina agli argomenti trattati in precedenza è SETI@home (SETI at home) [2], un progetto di calcolo distribuito volontario che usa computer connessi ad internet, ospitato dalla Space Sciences Laboratory all’Università della California, Berkeley, negli Stati Uniti d’America. SETI è l’acronimo di Search for Extra-Terrestrial Intelligence ed il suo scopo è quello di analizzare segnali radio in cerca di segni di intelligenze extraterrestri. Chiunque con un computer connesso ad internet può partecipare a SETI@home eseguendo un software gratuito che scarica ed analizza dati provenienti dal radio-telescopio. Il software di calcolo distribuito di SETI@home può essere eseguito sia come screensaver sia mentre l’utente è a lavoro, sfruttando la potenza di elaborazione che altrimenti sarebbe inutilizzata. La prima piattaforma software, ora denominata “SETI@home Classic” [3] è stata utilizzata dal 17 maggio 1999 al 15 dicembre 2005. Quest’ultima consentiva di eseguire solo SETI@home. Fu sostituito da Berkeley Open Infrastructure for Network Computing (BOINC) [4], il quale permette agli utenti di contribuire anche ad altri progetti di calcolo distribuito contemporaneamente all’esecuzione di SETI@home. Un altro famoso progetto di calcolo distribuito è neuGRID [5], finanziato dalla Comunità Europea. Il progetto prevede lo sviluppo di un’infrastruttura digitale per la ricerca scientifica, basata sul sistema Grid ed è dotata di un’interfaccia che permetterà alla comunità di neuroscienziati europei l’avanzamento della ricerca per lo studio delle malattie neurodegenerative (come il morbo di Alzheimer). All’interno di neuGRID, vi è la possibilità di raccogliere ed archiviare un’ingente quantità di dati di imaging molecolare e di effettuare analisi computazionalmente impegnative, attraverso il paradigma del calcolo distribuito. Un ricercatore interagisce con neuGRID per selezionare un gruppo di immagini da analizzare, usando l’algoritmo prescelto. Completata l’elaborazione dell’immagine sulla griglia, il dato di input viene confrontato al dato di output per verificare il risultato del processo. Questo CAPITOLO 1. INTRODUZIONE 5 viene poi trasferito dall’utente in postazione remota per ulteriori eventuali analisi statistiche e visualizzazioni avanzate. 1.5 Risultati Tutti gli obiettivi prefissati sono stati raggiunti con successo. La versione precedente di GRIMD ha dovuto essere modificata allo scopo di permettere tale gestione multiutente. Infatti sono state introdotte alcune componenti aggiuntive ed inoltre è stato necessario anche effettuare un refactoring a livello architetturale per risolvere alcune problematiche che saranno presentate successivamente. Allo stato attuale è disponibile un’interfaccia web che permette l’accesso al sistema agli utenti autorizzati e fornisce loro la possibilità di sottomettere i lavori che si desidera eseguire. I lavori sottomessi vengono poi gestiti da un apposito servizio di gestione della coda ed eseguiti utilizzando le basi fornite da GRIMD con le opportune modifiche. Capitolo 2 Le tecnologie In questo capitolo saranno mostrate le tecnologie utilizzate durante lo svolgimento del lavoro. Se queste sono già conosciute la lettura del capitolo può essere tralasciata, in quanto si fornirà solamente una panoramica generale e non saranno trattati i dettagli delle varie tecnologie. 2.1 .NET Framework Il .NET Framework è un framework software sviluppato dalla Microsoft, destinato ad essere usato dalla maggior parte delle nuove applicazioni create per le piattaforme Windows le quali ne forniscono il pieno supporto. Esso include una vasta gamma di librerie di base, detta Base Class Library (BCL) e fornisce l’interoperabilità di linguaggio attraverso i diversi linguaggi di programmazione supportati (cioè ogni linguaggio può utilizzare del codice scritto in altri linguaggi). In particolare nel corso del lavoro sono stati utilizzati i seguenti linguaggi di programmazione .NET: • C# , linguaggio ad oggetti simile al Java della Oracle Corporation. • Visual Basic .NET (abbreviato VB.NET), linguaggio orientato agli oggetti e multi-thread basato sulla sintassi di Visual Basic 6 CAPITOLO 2. LE TECNOLOGIE 7 • ASP.NET, evoluzione del classico ASP (Active Server Pages), linguaggio di programmazione in ambiente web, implementa .NET ed è dotato di librerie .NET, anche se non viene considerato un linguaggio vero e proprio poiché può essere scritto utilizzando un qualsiasi altro linguaggio .NET. • ADO.NET, nuova versione per il .NET Framework di ADO (ActiveX Data Objects) BCL fornisce classi per la creazione di interfacce utente, accesso ai dati, connettività a database, crittografia, sviluppo di applicazioni web, algoritmi numerici e comunicazione su rete. I programmatori producono software combinando il loro codice sorgente con BCL ed eventuali altre librerie di terze parti. Tutto il codice della BCL, librerie di terze parti e qualsiasi altro programma scritto in un qualsiasi linguaggio .NET viene tradotto nel Common Intermediate Language (CIL) che rappresenta il linguaggio di programmazione di più basso livello ancora leggibile dall’uomo definito dalla Common Figura 2.1: Diagramma della Common Language Infrastructure. CAPITOLO 2. LE TECNOLOGIE 8 Language Infrastructure (CLI) rappresentata in figura 2.1, ossia lo standard Microsoft che descrive il codice eseguibile e l’ambiente d’esecuzione che forma il nucleo del .NET Framework. I programmi trasformati in CIL vengono quindi eseguiti all’interno di un ambiente software noto come Common Language Runtime (CLR), una macchina virtuale che fornisce importanti servizi e funzionalità quali la sicurezza, la gestione della memoria, la gestione delle eccezioni, etc. Per fare un esempio, il CIL e il CLR possono essere paragonati al Bytecode ed alla macchina virtuale di Java. Le librerie di classi BCL e il CLR, insieme costituiscono il .NET Framework. In figura 2.2 è rappresentato lo stack .NET Framework fino alla versione 4.0. 2.1.1 Entity Framework Entity Framework è un set di tecnologie ADO.NET (ActiveX Data Objects), ossia un sottoinsieme di librerie della BCL utilizzato per suppor- Figura 2.2: Lo stack .NET Framework fino alla versione 4.0. CAPITOLO 2. LE TECNOLOGIE 9 tare lo sviluppo di applicazioni software orientate ai dati. Le tecnologie ADO.NET rappresentano il primo modello di accesso relazionale ai dati per le applicazioni basate su Microsoft .NET Framework. Entity Framework rappresenta una soluzione di mapping relazionale ad oggetti ed è uno strumento che consente alle applicazioni di accedere e modificare i dati, i quali vengono rappresentati come entità e relazioni. Le informazioni contenute nei file di modello e di mapping, che necessitano di essere definiti tramite appositi linguaggi, vengono utilizzate per tradurre le query eseguite sui vari tipi di entità in query specifiche dell’origine dati. Questo accade poiché le origini dei dati possono essere di tipo differente (Strutture dati, DBMS, file, etc) ed il risultato delle query viene poi rappresentato da oggetti gestiti da Entity Framework. Il meccanismo di traduzione delle query è fornito dai provider di dati EntityClient. Tali provider gestiscono connessioni alle sorgenti dei dati, convertono query di entità in query specifiche dell’origine dati e restituiscono un lettore dati utilizzato successivamente da Entity Framework per materializzare i dati dell’entità in oggetti. I metodi disponibili per eseguire query su un modello concettuale e restituire oggetti sono fondamentalmente due: • LINQ to Entities: Fornisce il supporto LINQ (Language-Integrated Query) per l’esecuzione di query su tipi di entità definiti in un modello concettuale • Entity SQL: Sottolinguaggio SQL indipendente dall’archiviazione che interagisce direttamente con le entità del modello concettuale e supporta il concetto di Entity Data Model (derivante dal modello Entity Relationship) La figura 2.3 mostra l’architettura di Entity Framework per l’accesso ai dati. CAPITOLO 2. LE TECNOLOGIE 10 Figura 2.3: Architettura di Entity Framework per l’accesso ai dati. LINQ Language Integrated Query (LINQ, si pronuncia “link”) è un componente del .NET Framework che aggiunge ai linguaggi .NET la possibilità di effettuare interrogazioni su oggetti utilizzando una sintassi simile a SQL. Esso definisce un insieme di operatori che possono essere usati per interrogare, proiettare e filtrare dati in matrici, classi enumerabili, XML, database relazionali e sorgenti dati di terze parti. Consente l’interrogazione di ogni sorgente di dati che rappresenti i dati sotto forma di oggetti. Per questa ragione, se la sorgente non memorizza in maniera nativa i dati come oggetti, è necessario l’utilizzo di un connettore per accedere ai dati. Il risultato di una query viene restituito come una collezione di oggetti in memoria che possono poi essere enumerati. CAPITOLO 2. LE TECNOLOGIE 2.1.2 11 Membership La Membership è una funzionalità integrata di ASP.NET che consente di convalidare e archiviare le credenziali utente, facilitando cosı̀ la gestione dell’autenticazione degli utenti nei siti Web e fornisce il supporto per: • Creazione di nuovi utenti e password. • Archiviazione delle informazioni di account utente (nomi utente, password e dati di supporto) in Microsoft SQL Server, Active Directory o in un archivio dati alternativo. • Autenticazione degli utenti che visitano il sito. È possibile autenticare gli utenti a livello di codice oppure utilizzare i controlli di accesso ASP.NET per creare un sistema di autenticazione completo che non richieda la scrittura di codice o la richieda solo in minima parte. • Gestione delle password, comprese le operazioni di creazione, modifica e reimpostazione. A seconda delle impostazioni utilizzate, la Membership può anche fornire un sistema automatico per la reimpostazione delle password che accetti una domanda ed una risposta segreta fornite dall’utente. • Definizione di un provider Membership personalizzato, che è possibile utilizzare in sostituzione del provider di default per gestire gli account e mantenere i dati relativi. Gli utenti possono essere raggruppati per ruolo. La gestione dei ruoli in ASP.NET consente di gestire le autorizzazioni, permettendo di specificare quali utenti possono accedere a determinate risorse dell’applicazione. Analogamente ai Membership Provider è possibile definire provider personalizzati per la gestione dei ruoli. CAPITOLO 2. LE TECNOLOGIE 2.1.3 12 Windows Communication Foundation Windows Communication Foundation (WCF), conosciuto in fase di sviluppo con il nome Indigo, è un sistema del .NET Framework che offre la struttura API per la creazione di applicazioni distribuite. Ogni protocollo di rete (HTTP, FTP, SMTP, etc.) ha un suo modello di programmazione e necessita quindi di una conoscenza specifica da parte degli sviluppatori per poter essere utilizzata. WCF è stato invece realizzato con l’intento di ricondurre ad un unico modello diverse tecnologie, rendendo più semplice ed uniforme la programmazione. È spesso utilizzato per implementare sistemi con architettura SOA (Service Oriented Architecture) Un servizio WCF si basa sul concetto di Endpoint che rappresenta la porta attraverso la quale le applicazioni comunicano con il mondo esterno. Si può quindi affermare che un servizio WCF sia una collezione di Endpoint. A sua volta, un Endpoint è costituito da quelli che sono i pilastri di WCF: Address, Binding, Contract. Address L’Address è l’indirizzo al quale il servizio risponde. L’indirizzo è composto da un URI, una Identity ed una lista di Header. In fase di definizione di un Address, l’informazione principale è l’URI, che corrisponde all’indirizzo fisico del servizio. Header e Identity sono informazioni opzionali che sono necessarie solo in casi particolari, come ad esempio per specificare un certificato X.509 nel caso sia richiesto un maggior grado di sicurezza. Binding Il concetto di Binding è forse il più importante tra quelli proposti in WCF. Infatti è proprio grazie ad esso se ci si può occupare esclusivamente del codice senza interessarsi minimamente all’infrastruttura di trasporto. I Binding si occupano di quello che avviene tra il momento in cui il servizio spedisce CAPITOLO 2. LE TECNOLOGIE 13 logicamente il messaggio ed il momento in cui questo viene fisicamente trasmesso sulla rete. In questo lasso di tempo vengono eseguiti numerosi passi che seguono una precisa pipeline di cui i binding sono responsabili. Il messaggio deve attraversare due livelli: il primo si occupa dei Behaviour (Comportamenti), ovvero delle trasformazioni che deve subire un messaggio, il secondo si occupa dei Channel (Canali), ovvero dell’instradamento verso il canale fisico di trasporto. Nel primo livello ci si occupa della conversione dei dati dal formato originario al formato specifico del messaggio che dipende dal protocollo utilizzato. Ad esempio, potrebbe essere effettuata la serializzazione di una classe nel formato XML di un messaggio SOAP. In aggiunta i Behaviour si occupano anche della sicurezza, ad esempio della cifratura delle informazioni e di altre funzioni di gestione del dato. Durante la seconda fase il messaggio viene tramesso sul canale di trasporto. La gestione dei Binding può essere interamente gestita in fase di configurazione, si può quindi intuire come semplicemente cambiando la configurazione si può passare da un protocollo ad un altro, come ad esempio da HTTPS ad un trasporto diverso del messaggio come i semplici TCP o HTTP senza dover modificare il codice. Contract Il Contract rappresenta l’interfaccia software vera e propria che il servizio pubblica ed espone all’esterno. Ogni operazione definita nel contract consiste in un semplice scambio di messaggi utilizzando il protocollo specificato in fase di configurazione. 2.2 SQL Server Microsoft SQL Server è un DBMS relazionale, meglio noto come Relational Database Management System (RDBMS), prodotto da Microsoft. Nelle prime versioni era utilizzato per basi dati medio-piccole, ma a partire dalla CAPITOLO 2. LE TECNOLOGIE 14 versione 2000 è stato utilizzato anche per la gestione di basi dati di grandi dimensioni. SQL Server utilizza una variante del linguaggio SQL standard chiamata Transact-SQL (T-SQL) comunicando sulla rete utilizzando un protocollo a livello di applicazione chiamato Tabular Data Stream (TDS). Supporta anche Open Database Connectivity (ODBC). 2.3 Windows Server 2003 Successore di Windows 2000, Microsoft Windows Server 2003 rappresenta una tappa della evoluzione della serie server dei sistemi operativi di Microsoft. Il lancio è avvenuto il 24 aprile 2003 ma conserva ancora oggi la compatibilità con molte delle caratteristiche presenti nei sistemi fino a Windows XP e Windows 7. 2.3.1 Internet Information Services Internet Information Services (abbreviato in IIS), è un complesso di servizi server Internet per sistemi operativi Microsoft Windows. Inizialmente venne distribuito come Option Pack per il sistema operativo Windows NT, venne poi integrato in Windows 2000 e Windows Server 2003. La versione corrente, integrata in Windows Server 2008 R2, è la 7.5 ed include i servizi server per i protocolli FTP, SMTP, NNTP e HTTP/HTTPS. L’applicazione server non è in grado, di per sé, di eseguire elaborazioni Server-side ma ne delega l’esecuzione ad applicazioni ISAPI (Internet Server Application Programming Interface), una interfaccia di programmazione (API) messa a disposizione da Microsoft per gli sviluppatori che intendono interagire ed ampliare le funzionalità del server web. Microsoft stessa fornisce una serie di applicazioni tra le quali il modulo per Active Server Pages ed ASP.NET. Altri sviluppatori hanno reso disponibili i moduli per il supporto ai linguaggi PHP e Perl. CAPITOLO 2. LE TECNOLOGIE 15 Sebbene il mercato dei server web sia controllato saldamente da Apache, IIS è riuscito, negli anni, a guadagnarsi una fetta di server pari a circa il 20% dei domini totali. 2.4 Virtual Private Network Una Rete Privata Virtuale (Virtual Private Network o VPN) è una rete di telecomunicazioni privata, instaurata tra soggetti che utilizzano un sistema di trasmissione pubblico e condiviso, come per esempio Internet. Lo scopo delle reti VPN è di offrire alle aziende, a un costo inferiore, le stesse possibilità delle linee private in affitto sfruttando reti condivise pubbliche. Si può vedere una VPN come l’estensione, a scala geografica, di una rete locale privata aziendale che colleghi tra loro siti interni all’azienda stessa variamente dislocati su un ampio territorio sfruttando una rete IP pubblica per il trasporto su scala geografica e realizzando una rete LAN, detta appunto virtuale e privata, logicamente del tutto equivalente ad una infrastruttura fisica di rete appositamente dedicata. Per mezzo di una VPN, utilizzando una connessione Internet, è ad esempio possibile collegarsi dall’esterno alla rete privata del proprio ufficio, scavalcando tutti i problemi dovuti alla raggiungibilità ad esempio per la presenza di firewall o NAT (Network Address Translation). Generalmente una VPN comprende due parti: una interna alla rete, e quindi protetta, che preserva la trasmissione, e una meno affidabile e sicura che è quella esterna alla rete privata, ad esempio via Internet. Le reti VPN utilizzano collegamenti che necessitano di autenticazione in modo da garantire l’accesso ai soli utenti autorizzati. Per garantire la sicurezza che i dati inviati in Internet non siano intercettati o utilizzati da altri non autorizzati, le reti utilizzano sistemi di crittografia. Le reti VPN sicure adottano dunque protocolli che provvedono a cifrare il traffico transitante sulla rete virtuale. Oltre alla cifratura, una VPN sicura deve prevedere nei suoi protocolli dei meccanismi che impedisca- CAPITOLO 2. LE TECNOLOGIE 16 no violazioni della sicurezza, come ad esempio il furto dell’identità digitale o l’alterazione dei messaggi. Alcuni dei protocolli più comuni utilizzati nelle VPN sono: • IPsec (IP security), comunemente usate su IPv4 (parte obbligatoria dell’IPv6). • PPTP (point-to-point tunneling protocol), sviluppato da Microsoft. • SSL/TLS, utilizzata nel progetto OpenVPN, è un framework molto spesso associato con il commercio elettronico, che s’è rivelato di grande flessibilità ed è quindi usato come strato di sicurezza per varie implementazioni (più o meno standard) di reti private virtuali. In particolare nel corso del lavoro si è scelto di utilizzare il servizio VPN offerto da Windows Server 2003 che fa uso del protocollo PPTP. Capitolo 3 Refactoring architettura In questo capitolo sarà presentata l’architettura di GRIMD 1.1 [1], e le modifiche apportate nella nuova versione allo scopo di fornire un servizio di gestione web e multiutente. Ci si concentrerà quindi solamente sugli aspetti architetturali analizzando i vantaggi derivanti dalle scelte adottate nell’ultima fase di sviluppo. 3.1 GRIMD 1.1 L’architettura originaria di GRIMD prevede la presenza di una macchina master che coordina il lavoro di un numero indeterminato di slave. Il master gestisce una lista statica di slave ai quali si connette all’avvio. Gli slave che non sono raggiungibili in quel determinato istante, o che vengono persi durante la computazione, saranno ricontattati ad intervalli regolari per verificarne la nuova eventuale disponibilità. È importante notare quindi che la direzione della connessione va dal master agli slave. Una volta instaurata, la connessione resta aperta fino alla terminazione dello slave o del master. Allo stesso modo una volta terminata una computazione il master ricontatta tutti gli slave, preleva da ciascuno un file contenente una sintesi dei risultati ottenuti, ed eventualmente li recupera salvandoli sulla macchina che lo ospita. 17 CAPITOLO 3. REFACTORING ARCHITETTURA 3.2 18 Modifiche apportate La precedente versione di GRIMD si è rivelata particolarmente adatta all’utilizzo in un ambito di laboratorio, dove ogni computer si trova all’interno della stessa rete e i requisiti di sicurezza sono limitati. Con l’intento di estendere le capacità di GRIMD ad un ambito più ampio, accademico o aziendale, abbiamo scelto di mantenere la versione precedente di GRIMD per un utilizzo di laboratorio e sviluppare una versione web che consenta l’utilizzo di computer appartenenti a diverse subnet, scavalcando i problemi dovuti alla presenza di NAT (Network Address Translation), e più utenti contemporaneamente e che, soprattutto, preservi l’integrità di ciascuna macchina slave negando l’accesso ad utenti malintenzionati. Maggiori dettagli sulla sicurezza saranno forniti nella successiva sezione. Nella versione precedente di GRIMD, era il master ad instaurare la connessione verso gli slave. Questo risulta essere un grosso limite architetturale nell’ottica di fornire accesso ad un numero maggiore di utenti, infatti non era possibile contattare slave che non si trovavano nella stessa sottorete del master. Inoltre, dal momento che il master comunica con gli slave utilizzando il protocollo SMB e richiede la disponibilità di una determinata porta (di default TCP 8883) la presenza di firewall sulle macchine slave potrebbe impedire la comunicazione, a meno che non siano configurate appositamente. Si è pertanto pensato di usufruire di un servizio VPN (Virtual Private Network). Il server che ospita il master, dotato di Windows Server 2003, è particolarmente adatto a far da server anche nella VPN, essendo già raggiungibile da tutti tramite IP pubblico (yadamp.unisa.it). La nuova versione dello slave all’avvio si preoccuperà di instaurare una connessione alla rete virtuale utilizzando il supporto nativo del sistema operativo tramite protocollo PPTP (Point-to-Point Tunneling Protocol). CAPITOLO 3. REFACTORING ARCHITETTURA 19 Figura 3.1: Diagramma dell’architettura di GRIMD. 3.2.1 Sicurezza Nella versione precedente di Grimd le password utilizzate per la comunicazione tra master e slave erano memorizzate in chiaro sul master e nel file batch di installazione dello slave. Dovendo la nuova versione lavorare con un insieme più vasto di slave, dislocati in diversi laboratori dell’ateneo, si è deciso di memorizzare tali informazioni sensibili in un unico database consultabile solo dagli addetti ai lavori, per evitare intrusioni nel file system distribuito del sistema, anche da parte di computer che appartengono alla griglia. Verranno, inoltre, impostate per la cartella dello slave maggiori restrizioni, in modo tale da permettere solo all’utente amministratore l’accesso in lettura e scrittura. La connessione e la comunicazione alla VPN sono cifrate tramite MSCHAPv2 (Microsoft Challenge Handshake Authentication Protocol) e MP- CAPITOLO 3. REFACTORING ARCHITETTURA 20 PE (Microsoft Point-to-Point Encryption), che fa uso di RSA RC4 con chiave di sessione a 128bit. Qualunque operazione sul file system degli slave continuerà a richiedere username e password. GRIMD 1.1 password in chiaro nei file di configurazione del master GRIMD 1.2 rimozione file di configurazione e gestione dinamica degli account degli slave password in chia- rimozione del file di ro in file batch di installazione installazione permessi non impo- accesso consentito stati per la directo- solo agli utenti griry slave md e administrator Tabella 3.1: Sicurezza in GRIMD 1.1 e 1.2 3.3 Requisiti minimi Il codice sorgente del master e dello slave è stato scritto utilizzando i linguaggi VB.NET e C# appartenenti alla famiglia di linguaggi Microsoft .NET Framework, mentre per l’interfaccia web è stato utilizzato ASP.NET. La comunicazione interprocesso avviene utilizzando WCF (Windows Communication Foundation), mentre lo spostamento dei files sfrutta il protocollo SMB. Per garantire il funzionamento del sistema pertanto è necessario che tutti i pc slave dispongano dei seguenti requisiti: • Windows XP SP3 o successiva CAPITOLO 3. REFACTORING ARCHITETTURA 21 • .NET Framework v.4 o successiva • Raggiungibilità al file system locale tramite protocollo SMB (Configurazione del firewall su interfaccia VPN) • Raggiungibilità tramite protocollo TCP alla porta 8883 (Configurazione del firewall su interfaccia VPN) Capitolo 4 Struttura del sistema In questo capitolo saranno descritte nel dettaglio l’architettura ed il funzionamento di tutte le componenti del sistema introdotte per svolgere il lavoro. Saranno riportati anche gli schemi relazionali delle tabelle che compongono il database. 4.1 Gestione utenti Dal momento che uno degli obiettivi principali è quello di fornire l’accesso a GRIMD ad un determinato numero di utenti, si è pensato fosse necessario introdurre, per motivi di ordine, una semplice gerarchia tra questi ultimi. Sono infatti stati definiti due ruoli per gli utenti, uno con privilegi amministrativi e l’altro con normale accesso al sistema. In particolare, l’utente amministratore ha il potere di: • Creare o eliminare nuovi utenti dal sistema e gestirne i ruoli. • Alterare arbitrariamente l’ordine dei lavori in coda. • Eliminare o modificare la posizione dei lavori in coda. • Terminare il sistema. 22 CAPITOLO 4. STRUTTURA DEL SISTEMA 23 Gli utenti normali possono invece sottomettere le macro per uno o più lavori, le quali una volta caricate vengono inserite nella coda. 4.2 Base dei dati In figura 4.1 è mostrato il diagramma ER della base dati utilizzata. Per esigenze di spazio sono mostrate solamente le entità ritenute di maggior importanza. Di seguito sarà riportata una breve descrizione per ogni entità. Figura 4.1: Diagramma Entità-Relazione della base di dati utilizzata per immagazzinare tutte le informazioni necessarie. CAPITOLO 4. STRUTTURA DEL SISTEMA 24 Workset Rappresenta un lavoro caricato da un utente e mantiene traccia di tutte le informazioni relative come il path e il nome del file della macro, data di inizio e fine computazione, tipo di computazione, tipo di scheduler utilizzato ed utente proprietario. Slaves Qui sono memorizzate le informazioni di tutti gli slave disponibili. Indirizzo IP nella VPN, porta in ascolto, stato (online/offline), nome NetBIOS della macchina, numero di core per processore, versione del sistema operativo, username e password di accesso per GRIMD e data di ultimo accesso. Queue Questa tabella viene utilizzata per tener traccia di tutti i workset che sono presenti nella coda dei lavori e la relativa posizione. SecondaryQueue Analoga a Queue, con la differenza che viene utilizzata per tener traccia di tutti i workset nella coda secondaria. aspnet User Tabella gestita quasi interamente dalla Membership di ASP.NET per tener traccia di tutti gli utenti che sono abilitati ad accedere al sistema. aspnet Roles Tabella gestita dalla Membership di ASP.NET per tener traccia di tutti i ruoli degli utenti che sono abilitati ad accedere al sistema. La relazione di tipo molti-a-molti con gli utenti è mantenuta tramite la tabella aspnet UsersInRoles CAPITOLO 4. STRUTTURA DEL SISTEMA 4.3 25 Servizio di gestione Master Come già spiegato in precedenza abbiamo deciso di mantenere quanto più possibile della struttura originale di GRIMD, modificando solo ciò che era strettamente necessario. Nella precedente versione l’avvio del master corrisponde con l’avvio di un nuovo lavoro. Il workset nella nuova versione dovrà essere reperito dalla coda e disposto nell’apposito path. La terminazione del lavoro corrisponde alla terminazione del master. Pertanto si è reso necessario introdurre un servizio, mantenuto costantemente in esecuzione, che avvii il master ogni volta che in testa alla coda è presente un lavoro da eseguire. Chiaramente è necessario che questo servizio possa comunicare con il modulo di gestione della coda per prelevare da questa il prossimo workset e che si preoccupi di tenere avviato il servizio di identificazione degli slaves per poter conoscere le risorse a disposizione che possono essere assegnate al workset in elaborazione. La figura 4.2 mostra il diagramma delle classi del servizio di gestione del master. Le classi MasterQueue e VPNIDResolver contengono le implementazioni dei contract dei servizi di gestione coda e di identificazione slave esposti dal servizio di gestione master tramite WCF. 4.3.1 Modulo di identificazione Slave Nella precedente versione di GRIMD era il master a tener traccia degli indirizzi di tutti i possibili slave, i quali venivano contattati ad intervalli regolari per verificarne la loro eventuale disponibilità. Nella nuova versione, sia per i motivi di sicurezza descritti nel capitolo precedente che a causa dalla presenza della VPN, non è più possibile tener traccia staticamente di tutti gli slave dal momento che l’assegnazione degli indirizzi IP nella VPN avviene tramite l’utilizzo di un server DHCP e quindi uno stesso indirizzo, nel tempo, può essere assegnato a slave diversi. Si è deciso quindi di gestire dinamicamente l’intera situazione facendo in modo che siano gli slave a comunicare la loro CAPITOLO 4. STRUTTURA DEL SISTEMA 26 Figura 4.2: Diagramma delle classi per il gestore del master. disponibilità al servizio di gestione del master, il quale conserva lo stato di tutti gli slave in un unico registro. Per identificare ogni slave, all’atto della registrazione, è necessario che questi forniscano ogni volta un ID univoco assegnato loro dal sistema di gestione, tramite il quale sarà possibile tener traccia di tutte le informazioni relative. Nel caso che uno slave non fornisca un ID valido, o nel caso che non lo fornisca affatto, gli viene assegnato un nuovo ID e vengono reperite e memorizzate tutte le informazioni mostrate nella descrizione della base dati. In figura 4.3 è mostrato il diagramma delle classi per il servizio di identificazione slave. L’interfaccia IVPNIDResolver rappresenta il contract esposto CAPITOLO 4. STRUTTURA DEL SISTEMA 27 Figura 4.3: Diagramma delle classi per il servizio di identificazione slave. tramite WCF, mentre la classe VPNIDResolver ne fornisce l’implementazione tramite l’ausilio della classe GRIMDEntities utilizzata per l’accesso alla base dati. 4.3.2 Modulo di gestione coda Nonostante per un utente sia prevista la possibilità di sottomettere più lavori, nella coda non potrà essere presente un lavoro dello stesso utente per più di una volta. Più precisamente il sistema si preoccuperà di gestire due code differenti, una primaria ed una secondaria. Nella coda primaria, per la quale è prevista una politica di gestione di tipo FIFO (First In First Out), è presente il vincolo di una singola presenza in coda per ogni utente al fine di impedire che si possa monopolizzare il sistema e tenerlo impegnato per un periodo di tempo troppo lungo. Nella coda secondaria invece non sono presenti vincoli, ogni utente puo inserire un numero illimitato di lavori. Il più “anziano” tra questi sarà spostato in coda primaria non appena si sarà liberato l’unico posto disponibile per ciascun CAPITOLO 4. STRUTTURA DEL SISTEMA 28 Figura 4.4: Diagramma delle classi per il modulo di gestione coda. utente. La coda secondaria è stata pensata per permettere di inserire in coda più lavori facendo in modo che venga data priorità all’ordine di inserimento per utente, invece che per lavoro. In figura 4.4 è mostrato il diagramma delle classi del modulo di gestione coda. L’interfaccia IMasterQueue rappresenta il contract in WCF che viene esposto al sistema di gestione coda per interagire con essa. La classe MasterQueue ne fornisce l’implementazione tramite l’utilizzo della classe ausiliaria QueueHandler che si preoccupa di mantenere lo stato della coda nel database utilizzando l’apposita classe GRIMDEntities. CAPITOLO 4. STRUTTURA DEL SISTEMA 4.4 29 Modulo di controllo di stato del Master Tutti i dati riguardanti l’andamento del lavoro, come ad esempio il numero di slave totali, disponibili o persi durante la computazione, sono contenuti solamente all’interno del processo del master e quindi praticamente inaccessibili dall’esterno. Figura 4.5: Diagramma delle classi per il modulo di controllo di stato del master. Per permettere l’accesso a questi dati tramite il pannello di controllo utente presente sull’interfaccia web, è stato necessario introdurre nel master un modulo che esponga all’esterno la possibilità di reperirli e quindi di visualizzarli. Come si può vedere in figura 4.5 il contract WCF (IMasterStatus) contiene un semplice metodo che restituisce un oggetto contenente lo stato del lavoro in esecuzione all’istante dell’invocazione. Per l’implementazione nella classe MasterStatus è stato creato un apposito bean, GRIMDStatus, che viene costantemente aggiornato dal master e restituito come risultato dell’invocazione del metodo presente nell’interfaccia. CAPITOLO 4. STRUTTURA DEL SISTEMA 4.5 30 Altre modifiche Di seguito viene riportato l’elenco di modifiche, di minore impatto, apportate ai servizi già esistenti nella versione precedente che non sono state ancora presentate. 4.5.1 Master Sono state effettuate altre modifiche minori nel master per quanto riguarda la creazione dei file di log. Infatti, in origine, nei file di log si teneva traccia degli indirizzi IP degli slave che, allo stato attuale, non forniscono un’informazione sufficiente per la loro identificazione a causa dei problemi precedentemente descritti. Sono quindi state apportate modifiche al logging facendo in modo che oltre all’indirzzo IP venga memorizzato anche l’ID di ogni slave. 4.5.2 FRED e GDUMP Le informazioni conservate nei file di log sono utilizzate successivamente dai servizi FRED e GDUMP rispettivamente per forzare l’operazione di reduce e per il recupero dell’intero insieme dei risultati conservati sugli slave. È da precisare che la nuova versione di GDUMP permette anche il recupero selettivo dei risultati e non obbligatoriamente quello dell’intero insieme. È stato necessario modificare le versioni precedenti di FRED e GDUMP, sia a causa del cambiamento del formato di log che per permettere il loro funzionamento tramite gli ID degli slave, utilizzati al posto di indirizzi IP. Infatti ora per ogni job cotenuto nel workset viene effettuata la risoluzione dell’ID dello slave associato utilizzando l’apposito servizio. In tal modo è possibile controllare se lo slave di riferimento è disponibile ed eventualmente ottenerne l’indirizzo IP corrente per contattarlo e prelevare i risultati di interesse. CAPITOLO 4. STRUTTURA DEL SISTEMA 4.5.3 31 Slave Le modifiche apportate allo slave riguardano essenzialmente l’introduzione dell’ingresso in VPN e della registrazione al servizio di identificazione. Dopo queste due fasi iniziali lo slave funziona esattamente come nella precedente versione, ad eccezione della gestione dei risultati memorizzati. Nella precedente versione infatti, all’inizio di un nuovo lavoro, il master provvedeva ad inviare allo slave una richiesta RESET DFS che causava la cancellazione dell’intero insieme di risultati memorizzati sullo slave. Nella nuova versione invece, a prescindere dall’inizio di un nuovo lavoro, si garantisce che i risultati siano conservati per un periodo di tempo minimo pari a quattro giorni dall’ultimazione del lavoro, dopo i quali non si garantisce più la permanenza di tali informazioni sulla macchina. Pertanto, se queste sono oggetto di interesse, è obbligatorio effettuarne il recupero da parte dell’utente entro questo termine. Conclusioni Per quanto i sistemi di grid computing siano oggi estremamente utilizzati, esistono molti problemi, di difficile soluzione, quali la gestione dell’alto grado di eterogeneità e la sicurezza, che rendono improponibile un avvento del Grid in qualità di tecnologia pervasiva. Ad oggi, il suo utilizzo resta circoscritto a grandi attori in grado di poter effettuare investimenti importanti in manodopera specializzata in grado di gestire e utilizzare i sistemi Grid di presente generazione. Questo lavoro può essere considerato come la base di partenza per lo sviluppo di applicazioni distribuite condivise tra più utenti, da proseguire sia attraverso l’approfondimento progettuale sia attraverso l’implementazione di ulteriori sviluppi tecnologici. Il progetto nasce come tentativo di allargare l’esperienza d’uso di un sistema condividendolo in un gruppo più vasto di utenti, cercando di facilitare il più possibile la comunicazione tra le risorse interne al sistema, spesso impedite da servizi di protezione come firewall oppure come il NAT. Il sistema sviluppato rimane comunque un progetto sperimentale, durante il quale si sono scoperti numerosi risvolti interessanti. Sviluppi futuri potrebbero consistere in miglioramenti nell’organizzazione e nella comunicazione interna al sistema, nello sviluppo dell’applicazione slave con compatibilità per sistemi LINUX, nell’introduzione del supporto di nuove applicazioni anche non inerenti al calcolo scientifico o nell’inserimento di un sistema che renda possibile la distribuzione e quindi l’esecuzione di un’applicazione generica, sempre seguendo il modello di programmazione Map/Reduce. 32 Bibliografia [1] Alessandro Bove, Alfonso Martorelli, Luigi Di Biasi. “Distributed Map/Reduce Grid for YASARA” 2011 [2] SETI Institute (Search for Extra-Terrestrial Intelligence) http:// www.seti.org [3] SETI@Home - SETI at home Classic http://setiathome. berkeley.edu [4] Berkeley Open Infrastructure for Network Computing (BOINC) http://boinc.berkeley.edu [5] Grid-Based e-Infrastructure for computationally data-intensive application in medical sciences http://www.neugrid.eu/pagine/home. php 33 Appendice A Appendice A.1 A.1.1 Servizio di controllo stato Master IMasterStatus 1 namespace M a s t e r S t a t u s L i b 2 { 3 [ ServiceContract ] 4 public i n t e r f a c e IMasterStatus 5 { 6 [ O p e r a t i o n C o n t r a c t ( IsOneWay = f a l s e ) ] 7 GRIMDStatus g e t S t a t u s ( ) ; 8 } 9 } A.1.2 MasterStatus 1 namespace M a s t e r S t a t u s L i b 2 { 3 [ S e r v i c e B e h a v i o r ( InstanceContextMode = InstanceContextMode . S i n g l e ) ] 4 public c l a s s MasterStatus : IMasterStatus 5 { 6 #r e g i o n V a r i a b i l i d ’ i s t a n z a 7 8 p r i v a t e GRIMDStatus s t a t u s ; 9 private ServiceHost host ; 10 11 #e n d r e g i o n 12 34 APPENDICE A. APPENDICE 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 #r e g i o n Implementazione i n t e r f a c c i a p u b l i c GRIMDStatus g e t S t a t u s ( ) { return status ; } #e n d r e g i o n #r e g i o n Metodi p u b b l i c i public void Listen ( ) { h o s t = new S e r v i c e H o s t ( t h i s ) ; h o s t . Open ( ) ; } public void Close ( ) { host . Close () ; } #e n d r e g i o n #r e g i o n P r o p r i e t à p u b l i c GRIMDStatus S t a t u s { set { status = value ; } } #e n d r e g i o n } p u b l i c c l a s s GRIMDStatus { #r e g i o n V a r i a b i l i d ’ i s t a n z a p r i v a t e i n t numberOfSlave , a c t i v e S l a v e , l o s t S l a v e , MFFAQueue ; p r i v a t e i n t t o t a l J o b s , completedJobs , s l a v e L o s s C o u n t , workToReassign ; #e n d r e g i o n #r e g i o n P r o p r i e t à p u b l i c i n t SlaveLossCount 35 APPENDICE A. APPENDICE 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 { get { return slaveLossCount ; } set { slaveLossCount = value ; } } p u b l i c i n t WorkToReassign { g e t { r e t u r n workToReassign ; } s e t { workToReassign = v a l u e ; } } p u b l i c i n t CompletedJobs { get { return completedJobs ; } s e t { completedJobs = value ; } } public i n t TotalJobs { get { return totalJobs ; } set { totalJobs = value ; } } p u b l i c i n t MFFAQueue { g e t { r e t u r n MFFAQueue ; } s e t { MFFAQueue = v a l u e ; } } public int LostSlave { get { return l o s t S l a v e ; } set { l o s t S l a v e = value ; } } public int ActiveSlave { get { return active Slave ; } set { a c t i v e S l a v e = value ; } } p u b l i c i n t NumberOfSlave { g e t { r e t u r n numberOfSlave ; } s e t { numberOfSlave = v a l u e ; } } #e n d r e g i o n } 36 APPENDICE A. APPENDICE 37 112 } A.2 A.2.1 Servizio di coda IMasterQueue 1 namespace Q u e u e H a n d l e r I n t e r f a c e L i b 2 { 3 [ ServiceContract ] 4 p u b l i c i n t e r f a c e IMasterQueue 5 { 6 [ O p e r a t i o n C o n t r a c t ( IsOneWay = f a l s e ) ] 7 Workset IsUserInQueue ( S t r i n g username , out i n t positionInQueue ) ; 8 9 [ O p e r a t i o n C o n t r a c t ( IsOneWay = f a l s e ) ] 10 v o i d Enqueue ( S t r i n g u s e r , S t r i n g macroFileName , I n t 1 6 s c h e d u l e r , S t r i n g computation , S t r i n g workName ) ; 11 12 [ O p e r a t i o n C o n t r a c t ( IsOneWay = f a l s e ) ] 13 v o i d RemoveFromQueue ( S t r i n g u s e r ) ; 14 15 [ O p e r a t i o n C o n t r a c t ( IsOneWay = f a l s e ) ] 16 v o i d MoveTo ( S t r i n g u s e r , I n t 1 6 newIndex ) ; 17 18 [ O p e r a t i o n C o n t r a c t ( IsOneWay = f a l s e ) ] 19 Workset GetNextWorkset ( ) ; 20 21 [ O p e r a t i o n C o n t r a c t ( IsOneWay = f a l s e ) ] 22 v o i d RemoveCurrentWorkset ( ) ; 23 24 [ O p e r a t i o n C o n t r a c t ( IsOneWay = f a l s e ) ] 25 v o i d RemoveWorkset ( i n t i d ) ; 26 27 [ O p e r a t i o n C o n t r a c t ( IsOneWay = t r u e ) ] 28 v o i d StartDump ( Workset w, S t r i n g arg1 , S t r i n g a r g 2 ) ; 29 30 [ O p e r a t i o n C o n t r a c t ( IsOneWay = t r u e ) ] 31 v o i d Shutdown ( ) ; 32 } 33 } A.2.2 MasterQueue 1 namespace Q u e u e H a n d l e r I n t e r f a c e L i b APPENDICE A. APPENDICE 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 38 [ S e r v i c e B e h a v i o r ( InstanceContextMode = InstanceContextMode . P e r C a l l ) ] p u b l i c c l a s s MasterQueue : IMasterQueue { #r e g i o n V a r i a b i l i d ’ i s t a n z a p r i v a t e QueueHandler queue ; private ServiceHost host ; #e n d r e g i o n #r e g i o n C o s t r u t t o r e p u b l i c MasterQueue ( ) { queue = new QueueHandler ( ) ; } #e n d r e g i o n #r e g i o n Implementazione i n t e r f a c c i a p u b l i c Workset IsUserInQueue ( s t r i n g username , out int positionInQueue ) { r e t u r n queue . GetUserWorkset ( username , out positionInQueue ) ; } p u b l i c v o i d Enqueue ( S t r i n g u s e r , S t r i n g remoteFileName , I n t 1 6 s c h e d u l e r , S t r i n g computation , S t r i n g workName ) { Configuration c o n f i g = ConfigurationManager . OpenExeConfiguration ( C o n f i g u r a t i o n U s e r L e v e l . None ) ; WebClient c l i e n t = new WebClient ( ) ; S t r i n g newDir = c o n f i g . A p p S e t t i n g s . S e t t i n g s [ ” W o r k s e t R e p o s i t o r y ” ] . Value + remoteFileName + ” \\ ” ; S t r i n g URIWorkset = c o n f i g . A p p S e t t i n g s . S e t t i n g s [ ” URIWorksetBaseAddress ” ] . Value + remoteFileName + ” . z i p ” ; S t r i n g saveTo = c o n f i g . A p p S e t t i n g s . S e t t i n g s [ ” W o r k s e t R e p o s i t o r y ” ] . Value + remoteFileName + ” . zip ” ; APPENDICE A. APPENDICE 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 39 c l i e n t . DownloadFile ( URIWorkset , saveTo ) ; D i r e c t o r y . C r e a t e D i r e c t o r y ( newDir ) ; Z i p F i l e w o r k s e t Z i p = new Z i p F i l e ( saveTo ) ; w o r k s e t Z i p . E x t r a c t A l l ( newDir ) ; queue . Enqueue ( u s e r , remoteFileName , s c h e d u l e r , computation , workName ) ; } [ O b s o l e t e ( ” Use RemoveWorkset” ) ] p u b l i c v o i d RemoveFromQueue ( S t r i n g u s e r ) { queue . RemoveUser ( u s e r ) ; } p u b l i c v o i d RemoveWorkset ( i n t i d ) { queue . RemoveWorkset ( i d ) ; } p u b l i c v o i d MoveTo ( S t r i n g u s e r , s h o r t newIndex ) { queue . MoveTo ( u s e r , newIndex ) ; } p u b l i c Workset GetNextWorkset ( ) { r e t u r n queue . GetNextWorkset ( ) ; } p u b l i c v o i d RemoveCurrentWorkset ( ) { queue . RemoveCurrentWorkset ( ) ; } p u b l i c v o i d StartDump ( Workset w, s t r i n g arg1 , s t r i n g arg2 ) { Configuration c o n f i g = ConfigurationManager . OpenExeConfiguration ( C o n f i g u r a t i o n U s e r L e v e l . None ) ; S t r i n g baseDir = c o n f i g . AppSettings . S e t t i n g s [ ” W o r k s e t R e p o s i t o r y ” ] . Value ; P r o c e s s dump = new P r o c e s s ( ) ; dump . S t a r t I n f o . FileName = b a s e D i r + ” . . \ \ gdump . exe ” ; APPENDICE A. APPENDICE 81 82 83 dump . S t a r t I n f o . R ed ir e ct S ta n da rd O ut pu t = t r u e ; dump . S t a r t I n f o . U s e S h e l l E x e c u t e = f a l s e ; dump . S t a r t I n f o . Arguments = a r g 1 + ” ” + a r g 2 + ” / createzip ” ; dump . S t a r t ( ) ; dump . WaitForExit ( ) ; 84 85 86 87 88 MailMessage message = new MailMessage ( ) ; message . From = new MailAddress ( ” noreply@yadamp . u n i s a . i t ” , ”GRIMD S e r v i c e ” ) ; message . To . Add( new MailAddress (w . a s p n e t U s e r s . aspnet Membership . LoweredEmail ) ) ; 89 90 91 92 93 94 95 CreateMessage ( message ) ; ContentType c t = new ContentType ( ) ; c t . MediaType = MediaTypeNames . Text . P l a i n ; c t . Name = ” dumplog ” + w . ID + ” ” + DateTime . Now . T o S t r i n g ( ”ddMMMyyyy” ) + ” . l o g ” ; Attachment l o g = new Attachment (dump . StandardOutput . BaseStream , c t ) ; message . Attachments . Add( l o g ) ; 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 40 SmtpClient c l i e n t = new SmtpClient ( ” 1 2 7 . 0 . 0 . 1 ” ) ; c l i e n t . Send ( message ) ; } p u b l i c v o i d Shutdown ( ) { Environment . E x i t ( 0 ) ; } #e n d r e g i o n #r e g i o n Metodi P u b b l i c i public void Listen ( ) { h o s t = new S e r v i c e H o s t ( t y p e o f ( MasterQueue ) ) ; h o s t . Open ( ) ; } public void Close ( ) { host . Close () ; } #e n d r e g i o n APPENDICE A. APPENDICE 125 126 127 } 41 } A.2.3 QueueHandler 1 namespace Q u e u e H a n d l e r I n t e r f a c e L i b 2 { 3 c l a s s QueueHandler 4 { 5 #r e g i o n V a r i a b i l i d ’ i s t a n z a 6 7 p r i v a t e GRIMDEntities db = new GRIMDEntities ( ) ; 8 9 #e n d r e g i o n 10 11 #r e g i o n Metodi P r i v a t i 12 13 p r i v a t e Boolean SecondaryEnqueue ( a s p n e t U s e r s u t e n t e , S t r i n g pathName , I n t 1 6 s c h e d u l e r , S t r i n g computation , S t r i n g workName ) 14 { 15 try 16 { 17 // Crea i l nuovo w o r k s e t e l o a g g i u n g e a l db 18 Workset w o r k s e t = new Workset ( ) ; 19 w o r k s e t . PathName = pathName ; 20 workset . UserId = utente . UserId ; 21 workset . Scheduler = s ch e du le r ; 22 w o r k s e t . Computation = computation ; 23 w o r k s e t . WorkName = workName ; 24 25 db . Workset . AddObject ( w o r k s e t ) ; 26 db . SaveChanges ( ) ; 27 28 SecondaryQueue queue = new SecondaryQueue ( ) ; 29 queue . IDUser = u t e n t e . U s e r I d ; 30 queue . IDWorkset = w o r k s e t . ID ; 31 32 db . SecondaryQueue . AddObject ( queue ) ; 33 db . SaveChanges ( ) ; 34 35 return true ; 36 } 37 catch ( Exception ) 38 { 39 return f a l s e ; 40 } APPENDICE A. APPENDICE 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 82 83 42 } p r i v a t e v o i d MoveToPrimaryQueue ( Guid uid , Queue queue , i n t p o s i t i o n ) { SecondaryQueue nextUserWork = db . SecondaryQueue . F i r s t O r D e f a u l t ( p => p . IDUser . Equals ( u i d ) ) ; queue . IDWorkset = nextUserWork . IDWorkset ; db . SecondaryQueue . D e l e t e O b j e c t ( nextUserWork ) ; db . Workset . D e l e t e O b j e c t ( nextUserWork . Workset ) ; db . SaveChanges ( ) ; } p u b l i c Boolean I s U se r I nS e c o nd a ry Q u eu e ( S t r i n g u s e r ) { // V e r i f i c a che l ’ u t e n t e s i a p r e s e n t e n e l db a s p n e t U s e r s u t e n t e = db . a s p n e t U s e r s . S i n g l e O r D e f a u l t ( p => p . UserName == u s e r ) ; i f ( u t e n t e == n u l l ) r e t u r n f a l s e ; // V e r i f i c a che l ’ u t e n t e s i a p r e s e n t e i n Coda SecondaryQueue utenteInCoda = db . SecondaryQueue . S i n g l e ( p => p . IDUser == u t e n t e . U s e r I d ) ; r e t u r n ( utenteInCoda != n u l l ) ; } p u b l i c Boolean IsWorksetInQueue ( i n t i d ) { // V e r i f i c a che i l w o r k s e t s i a p r e s e n t e n e l db Queue queue = db . Queue . S i n g l e O r D e f a u l t ( q => q . IDWorkset == i d ) ; i f ( queue == n u l l ) r e t u r n f a l s e ; e l s e return true ; } p u b l i c Boolean IsWorksetInSecondaryQueue ( i n t i d ) { // V e r i f i c a che i l w o r k s e t s i a p r e s e n t e n e l db SecondaryQueue queue = db . SecondaryQueue . S i n g l e O r D e f a u l t ( q => q . IDWorkset == i d ) ; i f ( queue == n u l l ) r e t u r n f a l s e ; e l s e return true ; } #e n d r e g i o n #r e g i o n Metodi p u b b l i c i APPENDICE A. APPENDICE 84 85 86 87 88 89 90 91 p u b l i c Boolean Enqueue ( S t r i n g u s e r , S t r i n g macroFileName , I n t 1 6 s c h e d u l e r , S t r i n g computation , S t r i n g workName ) { a s p n e t U s e r s u t e n t e = db . a s p n e t U s e r s . S i n g l e O r D e f a u l t ( p => p . UserName == u s e r ) ; // Se l ’ u t e n t e non e s i s t e r e s t i t u i s c e s u b i t o ’ false ’ i f ( u t e n t e == n u l l ) r e t u r n f a l s e ; // Se l ’ u t e n t e è i n coda l o i n s e r i s c o n e l l a coda s e c o n d a r i a i f ( IsUserInQueue ( u s e r ) ) r e t u r n SecondaryEnqueue ( u t e n t e , macroFileName , s c h e d u l e r , computation , workName ) ; 92 93 94 95 96 97 98 99 100 101 102 103 104 // Crea i l nuovo w o r k s e t e l o a g g i u n g e a l db Workset w o r k s e t = new Workset ( ) ; w o r k s e t . PathName = macroFileName ; workset . UserId = utente . UserId ; workset . Scheduler = s ch ed u le r ; w o r k s e t . Computation = computation ; w o r k s e t . WorkName = workName ; db . Workset . AddObject ( w o r k s e t ) ; // Recupera d a l db l a p o s i z i o n e d e l l ’ u l t i m o e l e m e n t o i n coda var queues = ( from q i n db . Queue s e l e c t q . Position ) ; 105 106 107 108 i n t newPosition = 1 ; i f ( queues != n u l l && queues . Count ( ) > 0 ) n e w P o s i t i o n = queues . Max ( ) + 1 ; 109 110 111 112 113 114 115 116 117 118 119 120 121 122 43 // Crea l a t u p l a da i n s e r i r e n e l l a t a b e l l a Queue e l a i n s e r i s c e Queue queue = new Queue ( ) ; queue . P o s i t i o n = n e w P o s i t i o n ; queue . IDWorkset = w o r k s e t . ID ; queue . IDUser = u t e n t e . U s e r I d ; db . Queue . AddObject ( queue ) ; db . SaveChanges ( ) ; return true ; } p u b l i c Workset GetNextWorkset ( ) APPENDICE A. APPENDICE 123 124 { // Se c ’ è un w o r k s e t a l p o s t o 0 v i e n e restituito Queue e x e c u t i n g W o r k s e t = db . Queue . S i n g l e O r D e f a u l t ( q => q . P o s i t i o n == 0 ) ; 125 126 127 i f ( e x e c u t i n g W o r k s e t != n u l l ) r e t u r n e x e c u t i n g W o r k s e t . Workset ; 128 129 // S c a l a l a p o s i t i o n d i t u t t i g l i e l e m e n t i i n coda d i una p o s i z i o n e var r e s u l t = ( from q i n db . Queue s e l e c t q ) ; 130 131 132 133 134 135 136 137 138 139 f o r e a c h ( Queue q i n r e s u l t ) { q . Position = q . Position − 1; } db . SaveChanges ( ) ; // Recupera i l primo Workset i n coda e ne a g g i o r n a i l campo ’ DateStart ’ Queue queueToReturn = db . Queue . S i n g l e O r D e f a u l t ( q => q . P o s i t i o n == 0 ) ; 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 44 i f ( queueToReturn == n u l l ) r e t u r n n u l l ; Workset c u r r e n t W o r k s e t = queueToReturn . Workset ; c u r r e n t W o r k s e t . D a t e S t a r t = DateTime . Now ; db . SaveChanges ( ) ; r e t u r n queueToReturn . Workset ; } p u b l i c Boolean IsUserInQueue ( S t r i n g u s e r ) { // V e r i f i c a che l ’ u t e n t e s i a p r e s e n t e n e l db a s p n e t U s e r s u t e n t e = db . a s p n e t U s e r s . S i n g l e O r D e f a u l t ( p => p . UserName == u s e r ) ; i f ( u t e n t e == n u l l ) r e t u r n f a l s e ; // V e r i f i c a che l ’ u t e n t e s i a p r e s e n t e i n Coda Queue utenteInCoda = db . Queue . S i n g l e O r D e f a u l t ( p => p . IDUser == u t e n t e . U s e r I d ) ; r e t u r n ( utenteInCoda != n u l l ) ; } p u b l i c Workset GetUserWorkset ( S t r i n g u s e r , out i n t position ) APPENDICE A. APPENDICE 164 165 { // Recupera l a t u p l a d e l l a t a b e l l a Queue che r i g u a r d a l ’ u t e n t e dato a s p n e t U s e r s u t e n t e = db . a s p n e t U s e r s . S i n g l e O r D e f a u l t ( p => p . UserName == u s e r ) ; Queue userQueue = db . Queue . S i n g l e O r D e f a u l t ( p => p . IDUser == u t e n t e . U s e r I d ) ; 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 45 // Se l ’ u t e n t e non è i n coda i f ( userQueue == n u l l ) { p o s i t i o n = −1; return null ; } e l s e // Se l ’ u t e n t e è i n coda ( o i n e s e c u z i o n e ) { p o s i t i o n = userQueue . P o s i t i o n ; r e t u r n userQueue . Workset ; } } p u b l i c v o i d RemoveCurrentWorkset ( ) { Queue c u r r e n t = db . Queue . S i n g l e O r D e f a u l t ( q => q . P o s i t i o n == 0 ) ; c u r r e n t . Workset . DateEnd = DateTime . Now ; S t r i n g username = c u r r e n t . a s p n e t U s e r s . UserName ; Guid u i d = c u r r e n t . a s p n e t U s e r s . U s e r I d ; db . Queue . D e l e t e O b j e c t ( c u r r e n t ) ; db . SaveChanges ( ) ; 194 // Recupero i l p r o s s i m o w o r k s e t d e l l ’ u t e n t e d a l l a coda s e c o n d a r i a SecondaryQueue nextUserWork = db . SecondaryQueue . F i r s t O r D e f a u l t ( p => p . IDUser . Equals ( u i d ) ) ; 195 196 197 198 i f ( nextUserWork == n u l l ) r e t u r n ; 199 200 201 202 203 204 // S p o s t o un e l e m e n t o d a l l a s e c o n d a r y queue a l l a coda p r i n c i p a l e Queue newQueue = new Queue ( ) ; newQueue . IDWorkset = nextUserWork . IDWorkset ; newQueue . IDUser = nextUserWork . IDUser ; // Recupera d a l db l a p o s i z i o n e d e l l ’ u l t i m o e l e m e n t o i n coda var queues = ( from q i n db . Queue s e l e c t q . APPENDICE A. APPENDICE 46 Position ) ; 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 i n t newPosition = 1 ; i f ( queues != n u l l && queues . Count ( ) > 0 ) n e w P o s i t i o n = queues . Max ( ) + 1 ; newQueue . P o s i t i o n = n e w P o s i t i o n ; db . Queue . AddObject ( newQueue ) ; db . SecondaryQueue . D e l e t e O b j e c t ( nextUserWork ) ; db . SaveChanges ( ) ; } p u b l i c v o i d RemoveUser ( S t r i n g u s e r ) { // Recupera l a p o s i z i o n e d e l l ’ u t e n t e i n coda ed elimina la tupla corrispondente dalla t a b e l l a Queue a s p n e t U s e r s u t e n t e = db . a s p n e t U s e r s . S i n g l e O r D e f a u l t ( p => p . UserName == u s e r ) ; Queue userQueue = db . Queue . S i n g l e O r D e f a u l t ( p => p . IDUser == u t e n t e . U s e r I d ) ; I n t 3 2 p o s i t i o n = userQueue . P o s i t i o n ; i f ( p o s i t i o n == 0 ) r e t u r n ; // Se un u t e n t e è i n coda s e c o n d a r i a s p o s t o i l prossimo workset a l l a p o s i z i o n e c o r r e n t e i f ( I sU s e r In S e co n d ar y Q ue u e ( u t e n t e . UserName ) ) { MoveToPrimaryQueue ( u t e n t e . UserId , userQueue , position ) ; return ; } db . Queue . D e l e t e O b j e c t ( userQueue ) ; db . SaveChanges ( ) ; // S c a l a d i una p o s i z i o n e g l i u t e n t i i n coda n e l l e p o s i z i o n i su cc es s iv e all ’ utente rimosso var q u e r y R e s u l t = ( from q i n db . Queue where q . Position > position select q) ; f o r e a c h ( Queue q i n q u e r y R e s u l t ) { q . Position = q . Position − 1; } db . SaveChanges ( ) ; APPENDICE A. APPENDICE 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 47 } p u b l i c v o i d RemoveWorkset ( i n t i d ) { // Recupero i l w o r k s e t Workset w o r k s e t = db . Workset . S i n g l e O r D e f a u l t (w => w . ID == i d ) ; i f ( IsWorksetInQueue ( w o r k s e t . ID ) ) { // Caso1 : Workset i n coda p r i m a r i a RemoveUser ( w o r k s e t . a s p n e t U s e r s . UserName ) ; } else { // Caso2 : Workset i n coda s e c o n d a r i a db . Workset . D e l e t e O b j e c t ( w o r k s e t ) ; db . SaveChanges ( ) ; } } p u b l i c v o i d MoveTo ( S t r i n g u s e r , I n t 1 6 newIndex ) { // Recupera l a p o s i z i o n e d e l l ’ u t e n t e i n coda a s p n e t U s e r s u t e n t e = db . a s p n e t U s e r s . S i n g l e O r D e f a u l t ( p => p . UserName == u s e r ) ; Queue userQueue = db . Queue . S i n g l e O r D e f a u l t ( p => p . IDUser == u t e n t e . U s e r I d ) ; I n t 3 2 p o s i t i o n = userQueue . P o s i t i o n ; // C o n t r o l l a che i l nuovo i n d i c e s i a minore d e l l ’ u l t i m o i n d i c e i n coda e maggiore d i 0 var queues = ( from q i n db . Queue s e l e c t q . Position ) ; i f ( queues != n u l l && queues . Count ( ) == 0 ) return ; i n t l a s t P o s i t i o n = queues . Max ( ) ; i f ( newIndex > l a s t P o s i t i o n ) newIndex = Convert . ToInt16 ( l a s t P o s i t i o n ) ; i f ( newIndex < 1 ) newIndex = 1 ; // Assegna a l l ’ u t e n t e dato i l p o s t o dato userQueue . P o s i t i o n = newIndex ; db . SaveChanges ( ) ; // Recupera g l i u t e n t i i n coda d a l l a nuova posizione dell ’ utente e riassegna l e APPENDICE A. APPENDICE 48 p o s i z i o n i in ordine crescente 284 285 286 287 i f ( newIndex < p o s i t i o n ) { var q u e r y R e s u l t = ( from q i n db . Queue where ( q . P o s i t i o n >= newIndex && q . IDUser != utente . UserId ) orderby q . P o s i t i o n s e l e c t q) ; I n t 3 2 s t a r t P o s = newIndex + 1 ; 288 289 290 291 292 293 294 295 296 297 298 f o r e a c h ( Queue q i n q u e r y R e s u l t ) { q . Position = startPos ; s t a r t P o s ++; } 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 } } e l s e i f ( newIndex > p o s i t i o n ) { var q u e r y R e s u l t = ( from q i n db . Queue where ( q . P o s i t i o n > p o s i t i o n && q . P o s i t i o n <= newIndex && q . IDUser != u t e n t e . U s e r I d ) orderby q . P o s i t i o n s e l e c t q ) ; Int32 startPos = p o s i t i o n ; f o r e a c h ( Queue q i n q u e r y R e s u l t ) { q . Position = startPos ; s t a r t P o s ++; } } e l s e i f ( newIndex == p o s i t i o n ) r e t u r n ; db . SaveChanges ( ) ; } #e n d r e g i o n } A.3 A.3.1 Servizio identificazione slave IVPNIDResolver 1 namespace VPNIDResolverLib 2 { 3 [ ServiceContract ] APPENDICE A. APPENDICE 4 5 6 7 49 p u b l i c i n t e r f a c e IVPNIDResolver { [ O p e r a t i o n C o n t r a c t ( IsOneWay = f a l s e ) ] Guid GetNewID ( S t r i n g os , S t r i n g machineName , s h o r t coreNum ) ; 8 9 10 11 12 13 14 15 16 17 18 19 20 21 } [ O p e r a t i o n C o n t r a c t ( IsOneWay = f a l s e ) ] Boolean Update ( Guid myGuid ) ; [ O p e r a t i o n C o n t r a c t ( IsOneWay = f a l s e ) ] v o i d S e t O f f l i n e ( Guid myGuid ) ; [ O p e r a t i o n C o n t r a c t ( IsOneWay = f a l s e ) ] S l a v e s GetSlaveByID ( Guid g u i d ) ; [ O p e r a t i o n C o n t r a c t ( IsOneWay = f a l s e ) ] L i s t <S t r i n g > g e t A v a i l a b l e S l a v e s L i s t ( ) ; } A.3.2 VPNIDResolver 1 namespace VPNIDResolverLib 2 { 3 [ S e r v i c e B e h a v i o r ( InstanceContextMode = InstanceContextMode . S i n g l e ) ] 4 p u b l i c c l a s s VPNIDResolver : IVPNIDResolver 5 { 6 #r e g i o n V a r i a b i l i d ’ i s t a n z a 7 8 p r i v a t e GRIMDEntities db ; 9 private ServiceHost host ; 10 p r i v a t e L i s t <S l a v e O b j e c t > s l a v e L i s t = new L i s t < S l a v e O b j e c t >() ; 11 private s t a t i c Configuration config = C o n f i g u r a t i o n M a n a g e r . OpenExeConfiguration ( C o n f i g u r a t i o n U s e r L e v e l . None ) ; 12 13 #e n d r e g i o n 14 15 #r e g i o n C o s t r u t t o r e 16 17 p u b l i c VPNIDResolver ( ) 18 { 19 db = new GRIMDEntities ( ) ; 20 21 var s l a v e s = ( from s i n db . S l a v e s where s . I s O n l i n e == t r u e s e l e c t s ) ; 22 APPENDICE A. APPENDICE 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 50 foreach ( Slaves slave in slaves ) { a d d S l a v e T o L i s t ( new S l a v e O b j e c t ( s l a v e . IP , s l a v e . Port . T o S t r i n g ( ) , ” \\\\ ” + s l a v e . IP + ” \\ y d f s ” , ” \\\\ ” + s l a v e . IP + ” \\ temp ” , s l a v e . Username , s l a v e . Password , s l a v e . SlaveID ) ) ; } } #e n d r e g i o n #r e g i o n Implementazione i n t e r f a c c i a p u b l i c Guid GetNewID ( S t r i n g os , S t r i n g machineName , s h o r t coreNum ) { S l a v e s s l a v e = new S l a v e s ( ) ; s l a v e . SlaveID = Guid . NewGuid ( ) ; s l a v e . IP = getRemoteIP ( ) ; slave . IsOnline = true ; s l a v e . MachineName = machineName ; s l a v e . OSVersion = o s ; s l a v e . CoreNumber = coreNum ; s l a v e . Port = Convert . ToInt32 ( c o n f i g . A p p S e t t i n g s . S e t t i n g s [ ” D e f a u l t P o r t ” ] . Value ) ; s l a v e . Username = c o n f i g . A p p S e t t i n g s . S e t t i n g s [ ” DefaultUsername ” ] . Value ; s l a v e . Password = c o n f i g . A p p S e t t i n g s . S e t t i n g s [ ” D e f a u l t P a s s w o r d ” ] . Value ; s l a v e . LastUpdate = DateTime . Now ; try { db . S l a v e s . AddObject ( s l a v e ) ; db . SaveChanges ( ) ; a d d S l a v e T o L i s t ( new S l a v e O b j e c t ( s l a v e . IP , s l a v e . Port . T o S t r i n g ( ) , ” \\\\ ” + s l a v e . IP + ” \\ y d f s ” , ” \\\\ ” + s l a v e . IP + ” \\ temp ” , s l a v e . Username , s l a v e . Password , s l a v e . SlaveID ) ) ; r e t u r n s l a v e . SlaveID ; } catch ( Exception ) { r e t u r n Guid . Empty ; APPENDICE A. APPENDICE 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 51 } } p u b l i c b o o l Update ( Guid myGuid ) { S l a v e s s l a v e = db . S l a v e s . S i n g l e O r D e f a u l t ( p => p . SlaveID . Equals ( myGuid ) ) ; try { s l a v e . IP = getRemoteIP ( ) ; slave . IsOnline = true ; s l a v e . LastUpdate = DateTime . Now ; db . SaveChanges ( ) ; a d d S l a v e T o L i s t ( new S l a v e O b j e c t ( s l a v e . IP , s l a v e . Port . T o S t r i n g ( ) , ” \\\\ ” + s l a v e . IP + ” \\ y d f s ” , ” \\\\ ” + s l a v e . IP + ” \\ temp ” , s l a v e . Username , s l a v e . Password , s l a v e . SlaveID ) ) ; return true ; } catch ( Exception ) { return f a l s e ; } } p u b l i c v o i d S e t O f f l i n e ( Guid myGuid ) { S l a v e s s l a v e = db . S l a v e s . S i n g l e O r D e f a u l t ( p => p . SlaveID . Equals ( myGuid ) ) ; slave . IsOnline = f a l s e ; db . SaveChanges ( ) ; } p u b l i c S l a v e s GetSlaveByID ( Guid g u i d ) { S l a v e s s l a v e = db . S l a v e s . S i n g l e O r D e f a u l t ( p => p . SlaveID . Equals ( g u i d ) ) ; return slave ; } p u b l i c L i s t <S t r i n g > g e t A v a i l a b l e S l a v e s L i s t ( ) { L i s t <S t r i n g > toReturn = new L i s t <s t r i n g >() ; foreach ( SlaveObject s in s l a v e L i s t ) APPENDICE A. APPENDICE 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 52 { toReturn . Add( S l a v e T o S t r i n g ( s ) ) ; } r e t u r n toReturn ; } #e n d r e g i o n #r e g i o n Metodi p r i v a t i p r i v a t e S t r i n g getRemoteIP ( ) { OperationContext c o n t e x t = OperationContext . Current ; MessageProperties messageProperties = context . IncomingMessageProperties ; RemoteEndpointMessageProperty e n d p o i n t P r o p e r t y = messageProperties [ RemoteEndpointMessageProperty . Name ] a s RemoteEndpointMessageProperty ; r e t u r n e n d p o i n t P r o p e r t y . Address ; } p r i v a t e i n t getRemotePort ( ) { OperationContext c o n t e x t = OperationContext . Current ; MessageProperties messageProperties = context . IncomingMessageProperties ; RemoteEndpointMessageProperty e n d p o i n t P r o p e r t y = messageProperties [ RemoteEndpointMessageProperty . Name ] a s RemoteEndpointMessageProperty ; r e t u r n e n d p o i n t P r o p e r t y . Port ; } p r i v a t e void addSlaveToList ( SlaveObject s l a v e ) { removeSlaveFromList ( s l a v e . SlaveID ) ; s l a v e L i s t . Add( s l a v e ) ; } p r i v a t e v o i d removeSlaveFromList ( Guid SlaveID ) { S l a v e O b j e c t toRemove = n u l l ; foreach ( SlaveObject s in s l a v e L i s t ) { i f ( s . SlaveID . Equals ( SlaveID ) ) APPENDICE A. APPENDICE 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 53 { toRemove = s ; break ; } } s l a v e L i s t . Remove ( toRemove ) ; } private String SlaveToString ( SlaveObject s ) { r e t u r n ( s . sIPAddress + ” ∗” + s . s I P P o r t + ” ∗ ” + s . DFSPath + ”∗ ” + s . UNC Username + ” | ” + s . UNC Password + ” ∗” + s . SlaveID ) . R e pl a ce ( ” : : 1 ” , ” 127.0.0.1 ”) ; } #e n d r e g i o n #r e g i o n Metodi P u b b l i c i public void Listen ( ) { h o s t = new S e r v i c e H o s t ( t h i s ) ; h o s t . Open ( ) ; } public void Close ( ) { host . Close () ; } #e n d r e g i o n #r e g i o n Metodi S t a t i c i p u b l i c s t a t i c L i s t <S l a v e O b j e c t > g e t S l a v e s O b j e c t L i s t ( L i s t <S t r i n g > l i s t a ) { L i s t <S l a v e O b j e c t > toReturn = new L i s t < S l a v e O b j e c t >() ; foreach ( String s in l i s t a ) { toReturn . Add( new S l a v e O b j e c t ( s . T o S t r i n g ( ) ) ) ; } r e t u r n toReturn ; } APPENDICE A. APPENDICE 185 186 187 } #e n d r e g i o n } 54