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"
,
"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;
/*-------------------------------- 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 IP
$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 (utiliser par le protocole HTTP), les protocole sont ICMP/UDP/TCP
$args
[
'protocol'
]
=
"TCP"
;
// Définition du masque réseau qui nous permet d'autoriser certaines IP,
// ici nous acceptons la connexion 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 (utiliser 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 connexion 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 DNS sortant #
#########################
// Requête API
$args
[
'command'
]
=
"createEgressFirewallRule"
;
$args
[
'networkid'
]
=
$vm01
[
'conf'
][
'networkid'
];
// Définition du protocole a filtrer ici UDP (utiliser 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 connexion 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 (utiliser par le protocole SSH), les protocole sont ICMP/UDP/TCP
$args
[
'protocol'
]
=
"TCP"
;
// Définition du masque réseau qui nous permet d'autoriser certaines IP,
// ici nous acceptons la connexion 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
);
###################################
# 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 (utiliser par le protocole SSH), les protocole sont ICMP/UDP/TCP
$args
[
'protocol'
]
=
"TCP"
;
// Le Port public sur lequel vous allez initialiser la connexion 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;
/*-----------------------------------------------------------------------------------------------------------*/
#############
# 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 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
) &
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...
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. 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