Déployer une instance Debian 7 avec un WordPress prêt à l'emploi en quelques secondes avec 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éployer une instance Debian 7 avec un WordPress prêt à l'emploi en quelques secondes avec CloudStack

- Auteur : Ikoula

- Parution : 9 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. Déploiement de l'API

- II. Remerciements Developpez

I - Déploiement de l'API

<?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","&lt;VOTRE CLEF API");
define("SECRETKEY","&lt;VOTRE CLEF SECRETE>");
//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'] = "&lt;VOTRE ID DE RESEAU>";
/* 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'] = "c6b89fea-1242-4f54-b15e-9d8ec8a0b7e8";
/* UUID du modèle de systeme 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'] = "06239517-eb64-441a-ae71-7a0c6d3a057a";
/* 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'] = "wordpress01";
/* Données utilisateur a passer au processus de déploiement de l'instance.
Ce paramètre nous sert à passer les paramètres Puppet au travers des userdata */
$vm01['conf']['userdata'] = 'puppet module install jonhadfield/wordpress &amp;&amp; puppet apply -e "include wordpress"';
/* ------------------------------ 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'];
// Stockage de l'IP correspondante
$vm01['conf']['publicIP'] = $json_response['listpublicipaddressesresponse']["publicipaddress"][0]['ipaddress'];
// 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
$args['userdata'] = $vm01['conf']['userdata']; //Userdata
$args['userdata'] = base64_encode($vm01['conf']['userdata']); // Données utilisateur
//Type de retour : JSON ou XML (par défaut : XML)
$args['response'] = "json";
// Initialisation du client API
sendRequest($args, $json_response);
//On vérifie la presence 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;
//On cherche à récupérer le mot de passe de l'instance via 'queryAsyncJobResult'
$args['command'] = "queryAsyncJobResult";
$args['jobid'] = $json_response['deployvirtualmachineresponse']['jobid'];
//Type de retour : JSON ou XML (par défaut : XML)
$args['response'] = "json";
// Initialisation du client API
sendRequest($args, $json_response);
// Indication du mot de passe de l'instance
print($vm01['conf']['hostname']." - Mot de passe : ".$json_response['queryasyncjobresultresponse']['jobresult']['virtualmachine']['password']."\n");
/*-------------------------------- Création des règles de sortie --------------------------------*/
// On réinitialise les variables utilisées pour l'envoi de requêtes API
unset($args);
################
# Ping sortant #
################
$args['command'] = "createEgressFirewallRule";
$args['networkid'] = $vm01['conf']['networkid'];
// Définition du protocole a filtrer ici ICMP (utiliser pour les ping), les protocoles sont ICMP/UDP/TCP
$args['protocol'] = "ICMP";
// Définition du masque réseau qui nous permet d'autoriser certaines IP,
// ici nous acceptons "le ping" vers toutes les IPs
$args['cidrlist'] = "0.0.0.0/0";
// On définit le type ICMP le code 8 et une demande d'ECHO (echo-request) cela permet le ping
$args['icmptype'] = 8;
// On définit le code ICMP le code 0 doit être défini à 0 pour l'utilisation du type 8 pour l'ICMP
$args['icmpcode'] = 0;
// Execution de la requête
sendRequest($args, $json_response);
// Traitement de la requête
if(preg_match("/^[0-9a-f\-]+$/", $json_response['createegressfirewallruleresponse']['jobid']) > 0)
{
$jobs[] = $json_response['createegressfirewallruleresponse']['jobid'];
}
else{
echo "ID de job non trouvé.\n";
}
if(!checkJobs($jobs))
exit;
// On réinitialise les variables utilisées pour l'envoi de requêtes API
unset($args);
##########################
# Protocole HTTP sortant #
##########################
$args['command'] = "createEgressFirewallRule";
$args['networkid'] = $vm01['conf']['networkid'];
// Définition du protocole a filtrer ici TCP (utilisé par le protocole HTTP), les protocoles sont ICMP/UDP/TCP
$args['protocol'] = "TCP";
// Définition du masque réseau qui nous permet d'autoriser certaines IP,
// ici nous acceptons la connection vers toutes les IP
$args['cidrlist'] = "0.0.0.0/0";
// Le port de début (port 80 port standard pour le HTTP)
$args['startport'] = 80;
// Le port de fin (port 80 port standard pour le HTTP)
$args['endport'] = 80;
// Execution de la requête
sendRequest($args, $json_response);
// Traitement de la requête
if(preg_match("/^[0-9a-f\-]+$/", $json_response['createegressfirewallruleresponse']['jobid']) > 0)
{
$jobs[] = $json_response['createegressfirewallruleresponse']['jobid'];
}
else{
echo "ID de job non trouvé.\n";
}
// On réinitialise les variables utilisées pour l'envoi de requêtes API
unset($args);
###########################
# Protocole HTTPS sortant #
###########################
// Requête API
$args['command'] = "createEgressFirewallRule";
$args['networkid'] = $vm01['conf']['networkid'];
// Définition du protocole a filtrer ici TCP (utilisé par le protocole HTTPS), les protocoles sont ICMP/UDP/TCP
$args['protocol'] = "TCP";
// Définition du masque réseau qui nous permet d'autoriser certaines IP,
// ici nous acceptons la connection vers toutes les IP
$args['cidrlist'] = "0.0.0.0/0";
// Le port de début (port 443 port standard pour le HTTPs)
$args['startport'] = 443;
// Le port de fin (port 443 port standard pour le HTTPs)
$args['endport'] = 443;
// Execution de la requête
sendRequest($args, $json_response);
// Traitement de la requête
if(preg_match("/^[0-9a-f\-]+$/", $json_response['createegressfirewallruleresponse']['jobid']) > 0)
{
$jobs[] = $json_response['createegressfirewallruleresponse']['jobid'];
}
else{
echo "ID de job non trouvé.\n";
}
// On réinitialise les variables utilisées pour l'envoi de requêtes API
unset($args);
###########################
# Protocole FTP sortant #
###########################
// Requête API
$args['command'] = "createEgressFirewallRule";
$args['networkid'] = $vm01['conf']['networkid'];
// Définition du protocole a filtrer ici TCP (utilisé par le protocole FTP), les protocoleles protocoles sont ICMP/UDP/TCP
$args['protocol'] = "TCP";
// Définition du masque réseau qui nous permet d'autoriser certaines IP,
// ici nous acceptons la connection vers toutes les IP
$args['cidrlist'] = "0.0.0.0/0";
// Le port de début (port 21 port standard pour le FTP)
$args['startport'] = 21;
// Le port de fin (port 21 port standard pour le FTP)
$args['endport'] = 21;
// Execution de la requête
sendRequest($args, $json_response);
// Traitement de la requête
if(preg_match("/^[0-9a-f\-]+$/", $json_response['createegressfirewallruleresponse']['jobid']) > 0)
{
$jobs[] = $json_response['createegressfirewallruleresponse']['jobid'];
}
else{
echo "ID de job non trouvé.\n";
}
// On réinitialise les variables utilisées pour l'envoi de requêtes API
unset($args);
#########################
# Protocole DNS sortant #
#########################
// Requête API
$args['command'] = "createEgressFirewallRule";
$args['networkid'] = $vm01['conf']['networkid'];
// Définition du protocole a filtrer ici UDP (utilisé par le protocole DNS), les protocoles sont ICMP/UDP/TCP
$args['protocol'] = "UDP";
// Définition du masque réseau qui nous permet d'autoriser certaines IP,
// ici nous acceptons la connection vers toutes les IP
$args['cidrlist'] = "0.0.0.0/0";
// Le port de début (port 443 port standard pour le HTTPs)
$args['startport'] = 53;
// Le port de fin (port 443 port standard pour le HTTPs)
$args['endport'] = 53;
// Execution de la requête
sendRequest($args, $json_response);
// Traitement de la requête
if(preg_match("/^[0-9a-f\-]+$/", $json_response['createegressfirewallruleresponse']['jobid']) > 0)
{
$jobs[] = $json_response['createegressfirewallruleresponse']['jobid'];
}
else{
echo "ID de job non trouvé.\n";
}
// On réinitialise les variables utilisées pour l'envoi de requêtes API
unset($args);
########################################
# Ouverture du port public pour le SSH #
########################################
// Requête API
$args['command'] = "createFirewallRule";
$args['ipaddressid'] = $vm01['conf']['publicIPid'];
// Définition du protocole a filtrer ici TCP (utilisé par le protocole SSH), les protocoles sont ICMP/UDP/TCP
$args['protocol'] = "TCP";
// Définition du masque réseau qui nous permet d'autoriser certaines IP,
// ici nous acceptons la connection vers toutes les IP
$args['cidrlist'] = "0.0.0.0/0";
// Le port de début (port 2222 port qui sera plus tard redirigé vers le port 22(ssh) de votre VM)
$args['startport'] = 2222;
// Le port de fin (port 2222 port qui sera plus tard redirigé vers le port 22(ssh) de votre VM)
$args['endport'] = 2222;
// Execution de la requête
sendRequest($args, $json_response);
// Traitement de la requête
if(preg_match("/^[0-9a-f\-]+$/", $json_response['createfirewallruleresponse']['jobid']) > 0)
{
$jobs[] = $json_response['createfirewallruleresponse']['jobid'];
}
else{
echo "ID de job non trouvé.\n";
}
// On réinitialise les variables utilisées pour l'envoi de requêtes API
unset($args);
#########################################
# Ouverture du port public pour le HTTP #
#########################################
// Requête API
$args['command'] = "createFirewallRule";
$args['ipaddressid'] = $vm01['conf']['publicIPid'];
// Définition du protocole a filtrer ici TCP (utilisé par le protocole HTTP), les protocoles sont ICMP/UDP/TCP
$args['protocol'] = "TCP";
// Définition du masque réseau qui nous permet d'autoriser certaines IP,
// ici nous acceptons la connection vers toutes les IP
$args['cidrlist'] = "0.0.0.0/0";
// Le port de début (port 80 port qui sera plus tard redirigé vers le port 80 (HTTP) de votre VM)
$args['startport'] = 80;
// Le port de fin (port 2222 port qui sera plus tard redirigé vers le port 80 (HTTP) de votre VM)
$args['endport'] = 80;
// Execution de la requête
sendRequest($args, $json_response);
// Traitement de la requête
if(preg_match("/^[0-9a-f\-]+$/", $json_response['createfirewallruleresponse']['jobid']) > 0)
{
$jobs[] = $json_response['createfirewallruleresponse']['jobid'];
}
else{
echo "ID de job non trouvé.\n";
}
// On réinitialise les variables utilisées pour l'envoi de requêtes API
unset($args);
###################################
# Redirection de port pour le SSH #
###################################
// Requête API
$args['command'] = "createPortForwardingRule";
$args['ipaddressid'] = $vm01['conf']['publicIPid'];
$args['virtualmachineid'] = $vm01['conf']['id'];
// Définition du protocole a filtrer ici TCP (utilisé par le protocole SSH), les protocoles sont ICMP/UDP/TCP
$args['protocol'] = "TCP";
// Le Port public sur lequels vous allez initialiser la connection et définie plus tôt comme ouvert
$args['publicport'] = 2222;
// Le SSH de votre VM
$args['privateport'] = 22;
// Execution de la requête
sendRequest($args, $json_response);
// Traitement de la requête
if(preg_match("/^[0-9a-f\-]+$/", $json_response['createportforwardingruleresponse']['jobid']) > 0)
{
$jobs[] = $json_response['createportforwardingruleresponse']['jobid'];
}
else{
echo "ID de job non trouvé.\n";
}
// On réinitialise les variables utilisées pour l'envoi de requêtes API
unset($args);
if(!checkJobs($jobs))
exit;
####################################
# Redirection de port pour le HTTP #
####################################
// Requête API
$args['command'] = "createPortForwardingRule";
$args['ipaddressid'] = $vm01['conf']['publicIPid'];
$args['virtualmachineid'] = $vm01['conf']['id'];
// Définition du protocole a filtrer ici TCP (utilisé par le protocole HTTP), les protocoles sont ICMP/UDP/TCP
$args['protocol'] = "TCP";
// Le Port public sur lequels vous allez initialiser la connection et définie plus tôt comme ouvert
$args['publicport'] = 80;
// Le SSH de votre VM
$args['privateport'] = 80;
// Execution de la requête
sendRequest($args, $json_response);
// Traitement de la requête
if(preg_match("/^[0-9a-f\-]+$/", $json_response['createportforwardingruleresponse']['jobid']) > 0)
{
$jobs[] = $json_response['createportforwardingruleresponse']['jobid'];
}
else{
echo "ID de job non trouvé.\n";
}
// On réinitialise les variables utilisées pour l'envoi de requêtes API
unset($args);
if(!checkJobs($jobs))
exit;
// Finalisation
echo "D'ici moins de deux minutes, vous pourrez vous connecter à l'adresse http://".$vm01['conf']['publicIP'];
echo "afin de finaliser la configuration de votre installation de WordPress.\n";
echo "Nous vous invitons à modifier le mot de passe par défaut de la base de données pour plus de sécurité.\n";
/*-----------------------------------------------------------------------------------------------------------*/
#############
# 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]) &amp;&amp; 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, &amp;$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 occurences 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 .= "&amp;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) &amp;&amp; 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 &amp;&amp; $secu &lt; 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&#8230;
if($json_response['queryasyncjobresultresponse']['jobstatus'] == 1)
{
// &#8230;On retire simplement la tâche du tableau a surveiller
//return("JOB OK\n");
array_splice($jobs, $ij, 1);
}
// Sinon&#8230;
elseif($json_response['queryasyncjobresultresponse']['jobstatus'] == 2)
{
//&#8230;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 verification la tache 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;
}
?>

Après avoir renseigné les paramètres demandés au début du script et l'avoir exécuté, voici ce qui sera effectué :

•déploiement d'une instance Debian 7 (de type « m1.small ») ;

•installation de l'environnement LAMP+WordPress au sein de cette instance via Puppet ;

•création des règles sortantes nécessaires dans le pare-feu CloudStack : Ping ; FTP ; DNS ; ICMP ;

•création des règles entrantes et de translation nécessaires dans le pare-feu CloudStack : SSH et HTTP.

Quelques dizaines de secondes après la fin de l'exécution du script, vous pourrez vous connecter à l'adresse indiquée par ce dernier afin de finaliser la configuration de votre installation de WordPress.

Nous vous enjoignons à modifier les différents mots de passe de connexion pour plus de sécurité.

II - 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