Déploiement d'une instance GNU/Linux Debian 7 sous CloudStack

Ikoula

CloudStack est un logiciel de cloud computing open source pour la création, la gestion et le déploiement de services de cloud d'infrastructure. Il utilise des hyperviseurs existants tels que KVM, vSphere, XenServer et / XCP pour la virtualisation. En plus de sa propre API, CloudStack prend également en charge les Amazon Web Services. Voici une série de tests effectués par Ikoula sur ce logiciel.

N'hésitez pas à commenter cet article ! Commentez ♪

- Titre : Déploiement d'une instance GNU/Linux Debian 7 sous CloudStack

- Auteur : Ikoula

- Parution : 7 octobre 2013

- Licence : Copyright ® 2013 Ikoula. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Introduction

- II. II Déploiement de l'API

- II-A. Script

- II-B. Conclusion

- III. Remerciements Developpez

I - Introduction

Dans un premier temps, l'utilisateur doit :

- disposer d'un réseau déjà déployé (pour les comptes CloudStack Instances c'est normalement le cas) ;

- avoir la possibilité de créer une nouvelle instance (ne pas être à sa limite de création donc) ;

- déterminer l'ID du réseau auquel sera connectée son instance (via l'interface web ou l'API, de même, indications en commentaires dans le script) ;

- déterminer l'ID de l'offre de service (configuration CPU/RAM/Réseau) voulue, indications au sein du script.

II - II Déploiement de l'API

II-A - Script

<?php

// Liste complète des appels possibles : http://download.cloud.com/releases/3.0.6/api_3.0.6/TOC_User.html

################################

# Paramètres généraux de l'API #

################################

// Renseignez ici votre clef API ainsi que votre clef secrète

// Nous conseillons de déporter cette information au sein d'un autre fichier PHP dont on restreindra l'accès

define("APIKEY","d1Ii4ON33yqUahgtlsjnzK0o7QXNzXZONZKcW_rDcOV4jln48b5ujsSvU-mo9KsoLbp631VyCI4fLb3u176JZg");

define("SECRETKEY","fBenapO2hjOd3Vaj-NDmrekTIK85B8Jl_m8wFld4gi0XvLXy4w0iJz-2srztoVqkGVoblT25DyG4709gibo_TA");

//On définit l'URL d'appel de l'API (ou 'EndPoint')

define("ENDPOINT","https://cloudstack.ikoula.com/client/api");

#############################################################

# Paramètres utilisateur de configuration d(es) instance(s) #

#############################################################

//Première instance :

/* UUID(s) du réseau auquel sera connectée votre instance.

Utilisez la requête API 'listNetworks'
ou l'interface pour lister les réseaux existants et déterminer le réseau voulu

*/

$vm01['conf']['networkid'] = "<ID DU RESEAU QUE VOUS SOUHAITEZ UTILISER>";

/* UUID de l'offre de service (configuration matérielle) voulue.

Utilisez la requête API 'listServiceOfferings' pour lister les offres existantes.

Actuellement :

- m1.small : c6b89fea-1242-4f54-b15e-9d8ec8a0b7e8

- m1.medium : 8dae8be9-5dae-4f81-89d1-b171f25ef3fd

- m1.large : d2b2e7b9-4ffa-419e-9ef1-6d413f08deab

- m1.extralarge : 1412009f-0e89-4cfc-a681-1cda0631094b

*/

$vm01['conf']['serviceofferingid'] = "<ID DE L'OFFRE DE SERVICE A UTILISER>";

/* UUID du modèle de système d'exploitation.

Vous pouvez aussi utiliser la requête API 'listTemplates' pour lister les modèles existants.

Dans notre exemple nous allons nous baser sur le template 'Debian 7 - Minimal - 64bits'

*/

$vm01['conf']['templateid'] = "6d5b069b-4268-4c7c-810f-2793c2ac44fb";

/* Nom de votre choix pour l'instance (Nom de la machine et d'affichage dans l'interface)

Caractères alphanumériques uniquement. Ce nom doit être unique au sein de votre réseau. */

$vm01['conf']['hostname'] = "<NOM DE VOTRE INSTANCE>";

/* ------------------ NE PLUS RIEN MODIFIER APRES CETTE LIGNE ---------------------- */

$json_response = null;

################################################

# Récupération de l'ID de zone pour ce network #

################################################

// Requête API

$args['command'] = "listNetworks";

// On reprend l'ID de réseau renseigné plus tôt

$args['id'] = $vm01['conf']['networkid'];

// Execution de la requête

sendRequest($args, $json_response);

// Stockage de l'ID de zone pour ce réseau

$vm01['conf']['zoneid'] = $json_response['listnetworksresponse']["network"][0]['zoneid'];

// On réinitialise les variables utilisées pour l'envoi de requêtes API

unset($args);

######################################################

# Récupération de l'id de l'adresse IP de ce network #

######################################################

// Requête API

$args['command'] = "listPublicIpAddresses";

$args['associatednetworkid'] = $vm01['conf']['networkid'];

// Execution de la requête

sendRequest($args, $json_response);

// Stockage de l'ID de l'adresse IP publique du réseau

$vm01['conf']['publicIPid'] = $json_response['listpublicipaddressesresponse']["publicipaddress"][0]['id'];

// On réinitialise les variables utilisées pour l'envoi de requêtes API

unset($args);

####################################

# Création de la première instance #

####################################

// Requête API

$args['command'] = "deployVirtualMachine";

$args['zoneid'] = $vm01['conf']['zoneid'];

$args['serviceofferingid'] = $vm01['conf']['serviceofferingid'];

$args['templateid'] = $vm01['conf']['templateid'];

$args['networkids'] = $vm01['conf']['networkid'];

$args['name'] = $vm01['conf']['hostname']; //Hostname

$args['displayname'] = $args['name']; //Nom d'affichage

//Type de retour : JSON ou XML (par défaut : XML)

$args['response'] = "json";

//On réinitialise les variables avant l'appel API

// Initialisation du client API

sendRequest($args, $json_response);

//On vérifie la présence d'un Job

if(preg_match("/^[0-9a-f\-]+$/", $json_response['deployvirtualmachineresponse']['jobid']) > 0)

{

$jobs[] = $json_response['deployvirtualmachineresponse']['jobid'];

}

else{

echo "ID de job non trouvé.\n";

}

//On mémorise la correspondance name/id de l'instance au sein d'un tableau

$vm01['conf']['id'] = $json_response['deployvirtualmachineresponse']['id'];

//On utilise la fonction de vérification des jobs asynchrones

if(!checkJobs($jobs))

exit;

/*-----------------------------------------------------------------------------------------------------------*/

#############

# Fonctions #

#############

//Fonction de gestion d'erreur(s) API

function apiErrorCheck($json_response)

{

if(is_array($json_response))

{

$key = array_keys($json_response);

if(isset($json_response['errorcode']))

{

echo "ERREUR : ".$json_response['errorcode']." - ".$json_response['errortext']."\n";

exit;

}

if(isset($json_response['errorcode']) || (isset($key[0]) && isset($json_response[$key[0]]['errorcode'])))

{

echo "ERREUR : ".$json_response[$key[0]]['errorcode']." - ".$json_response[$key[0]]['errortext']."\n";

exit;

}

}

else

{

echo "ERREUR : PARAMETRE INVALIDE";

exit;

}

}

//Fonction d'envoi de requête à l'API

function sendRequest($args, &$json_response)

{

$json_response = null;

// Clef API

$args['apikey'] = APIKEY;

$args['response'] = "json";

//On classe les paramètres

ksort($args);

// On construit la requête HTTP basée sur les paramètres contenus dans $args

$query = http_build_query($args);

// On s'assure de bien remplacer toutes les occurrences de '+' par des ' '

$query = str_replace("+", " ", $query);

//On utilise la clef secrète et un algorithme HMAC SHA-1 sur la requête pour encoder la signature

$hash = hash_hmac("SHA1",  strtolower($query), SECRETKEY, true);

$base64encoded = base64_encode($hash);

$signature = urlencode($base64encoded);

// Construction de la requête finale sous la forme 'URL API + Requête API et paramètres + Signature'

$query .= "&signature=" . $signature;

// $jobs = null;

// Initialisation du client API

try

{

//Construction de la requête

$httpRequest = new HttpRequest();

$httpRequest->setMethod(HTTP_METH_POST);

$httpRequest->setUrl(ENDPOINT . "?" . $query);

// Envoi de la requête au serveur :

$httpRequest->send();

// Récupération du retour de l'API

$response = $httpRequest->getResponseData();

// retour de la réponse

$json_response = json_decode($response['body'], true);

apiErrorCheck($json_response);

}

catch (Exception $e)

{

echo "Probleme lors de l'envoi de la requête. ERREUR=".$e->getMessage();

exit;

}

}

//Fonction de vérification des jobs asynchrones

function checkJobs($jobs)

{

$json_response = null;

$error_msg = "";

if(is_array($jobs) && count($jobs) > 0)

{

// La tâche est asynchrone, on doit donc régulièrement vérifier les tâches avec une sécurité

$secu = 0;

// On indexe les tâches

$ij = 0;

// Tant qu'il y a des tâches asynchrones non terminées dans la pile de vérification, on boucle et on vérifie le statut

while(count($jobs) > 0 && $secu < 100)

{

try

{

//On interroge le statut de la tâche asynchrone

// http://download.cloud.com/releases/3.0.6/api_3.0.6/root_admin/queryAsyncJobResult.html

$args['apikey'] = APIKEY;

$args['command'] = "queryAsyncJobResult";

$args['jobid'] = $jobs[$ij];

$args['response'] = "json";

$json_response = null;

sendRequest($args, $json_response);

if(is_array($json_response['queryasyncjobresultresponse']))

{

// Si OK...

if($json_response['queryasyncjobresultresponse']['jobstatus'] == 1)

{

// ...On retire simplement la tâche du tableau à surveiller

//return("JOB OK\n");

array_splice($jobs, $ij, 1);

}

// Sinon...

elseif($json_response['queryasyncjobresultresponse']['jobstatus'] == 2)

{

//...On mémorise l'erreur et on retire la tâche du tableau à surveiller

//return("JOB ERREUR\n");

array_splice($jobs, $ij, 1);

$error_msg .= "ERREUR ! RESULT_CODE=".$json_response['queryasyncjobresultresponse']['jobresultcode'];

}

// Cette tâche est encore en cours, on passe à la suivante et on temporise

elseif($json_response['queryasyncjobresultresponse']['jobstatus'] == 0)

{

// Tâche suivante

$ij++;

// Temporisation entre chaque interrogation pour ne pas charger inutilement l'API

sleep(5);

}

}

}

catch(Exception $e)

{

$error_msg .= "EXCEPTION Lors de la vérification la tâche asynchrone. JOB_UUID:".$jobs[$ij]." ERREUR=".$e->getMessage()." \n";

}

// Si l'index arrive en bout de tableau, on le réinitialise

if($ij == count($jobs))

{

$ij = 0;

$secu++;

}

}

if($error_msg)

{

echo "ERRORS:".$error_msg."\n";

return false;

}

return true;

}

echo "No job\n";

return false;

}

?>

II-B - Conclusion

Le principal intérêt des opérations via l'API est la rapidité d'exécution et la flexibilité des procédés.

L'interface CloudStack a comme avantages d'être ergonomique et à la portée de la majorité, mais l'API va encore plus loin et permet des déploiements rapides et automatisés d'une ou plusieurs instances prêtes à l'emploi.

Ce script vous permettra donc de déployer de manière programmatique une instance Debian « Wheezy » prête à l'emploi. La version fournie ici en exemple est très simplifiée, mais il est tout à fait possible via quelques modifications mineures de procéder à la création d'instances d'autres configurations « matérielles » (Mémoire/Processeur/Réseau en changeant d'offre de service) ou logicielles (via la modification du modèle choisi pour un autre système d'exploitation).

De même, cet aspect programmatique permet la création multiple d'instances sans intervention de l'utilisateur (en faisant en sorte de changer automatiquement le nom pour chaque instance).

Via la répétition de son exécution, on peut donc imaginer déployer des clusters complets d'instances identiques en un temps très réduit.

De plus, l'exemple ci-dessus est fourni sur la base du langage PHP5, mais il est tout à fait possible d'utiliser d'autres langages de programmation selon vos préférences ou contraintes.

III - Remerciements Developpez

L'équipe Cloud Computing tient à remercier Ikoula pour la rédaction de ce tutoriel.

Nos remerciements à Wiztricks pour sa relecture technique et Zoom61 pour sa gabarisation.

N'hésitez pas à commenter cet article ! Commentez