Ajouter un commentaire

4.0 Déployer une instance Debian 7 avec un Nginx prêt à l’emploi en quelques secondes avec CloudStack

Aujourd'hui, nous vous proposons de déployer une autre instance applicative.

Beaucoup d’entre vous connaissent sûrement le logiciel serveur web Nginx.
C’est ce que nous vous proposons de déployer aujourd’hui de manière complètement automatique ! Il ne vous restera qu’à vous charger de la partie configuration finale qui se présente sous la forme d’un assistant « web ».

Pour cette tâche, notre déploiement utilise un module mis à la disposition de la communauté au sein de ce qu’on appelle « Puppet Forge ».
Vous trouverez ce module à cette adresse : https://forge.puppetlabs.com/puppetlabs/nginx

Vous devrez disposer des informations suivantes :
  • Vos clefs API
  • L’ID de votre réseau CloudStack
Voici le script à utiliser pour le déploiement :

[Code]

<?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","<VOTRE CLEF API");
	define("SECRETKEY","<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'] = "<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'] = "nginx01";
		
		/* 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 puppetlabs/nginx && puppet apply -e "include nginx"';
		
		
/* ------------------------------ 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 nginx.\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]) && 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 occurences de '+' par des '%20'
		$query = str_replace("+", "%20", $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 a 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 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 Nginx 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, votre Nginx est déployé et prêt a accueillir vos fichiers.

Par ici pour découvrir CloudStack Instances et CloudStack Server.