The Gandi Hosting API provides a set of remote requests to manage your hosting account like the Gandi.net control panel does. You can manage your hosting devices & servers instances in all Gandi datacenters from any location using the same API.
The Gandi Hosting API is provided through a set of XML-RPC calls.
>>> import xmlrpclib
>>> api = xmlrpclib.ServerProxy('https://rpc.gandi.net/xmlrpc/')
>>>
>>> apikey = 'my 24-character API key'
>>>
>>> # Now you can call API methods.
>>> # You must authenticate yourself by passing
>>> # the API key as the first method's argument
>>> version = api.version.info(apikey)
<?php
// Library installed from PEAR
require_once 'XML/RPC2/Client.php';
// The first step is to connect to the API
$version_api = XML_RPC2_Client::create(
'https://rpc.gandi.net/xmlrpc/',
array( 'prefix' => 'version.', 'sslverify' => True )
);
// Warning !
// PEAR::XML_RPC2 checks the SSL certificate with Curl
// Curl has its own CA bundle so you may :
// * disable the 'sslverify' option: leads to security issue
// * enable the 'sslverify' option (default) and add the Gandi
// SSL certificate to the Curl bundle: best choice for security
// See: http://curl.haxx.se/docs/sslcerts.html
$apikey = 'my 24-character API key';
// Now you can call API method
// You must authenticate yourself by passing the API key
// as the first method's argument
$result = $version_api->info($apikey);
// Warning !
// PEAR::XML_RPC2 has known bugs on methods calls
// See http://pear.php.net/bugs/bug.php?id=13963
// You may use this call instead of the above one :
// $result = $version_api->__call("info", $apikey);
// dump the result
print_r($result);
?>
> var xmlrpc = require('xmlrpc')
> var api = xmlrpc.createSecureClient({
... host: 'rpc.gandi.net',
... port: 443,
... path: '/xmlrpc/'
... })
>
> var apikey = 'my 24-character API key'
>
> // Now you can call API methods.
> // You must authenticate yourself by passing the API key
> // as the first method's argument
> api.methodCall('version.info', [apikey], function (error, value) {
... console.dir(value)
... })
Note
With NodeJS, use the npm xmlrpc package.
use XML::RPC;
my $api = XML::RPC->new('https://rpc.gandi.net/xmlrpc/');
my $apikey = 'my 24-character API key';
# Now you can call API methods.
# You must authenticate yourself by passing the API key
# as the first method's argument
my $version = $api->call( 'version.info', $apikey );
Note
With perl, use the cpan xml::rpc package.
require 'xmlrpc/client'
server = XMLRPC::Client.new2('https://rpc.gandi.net/xmlrpc/')
apikey = 'my 24-character API key'
# Now you can call API methods.
# You must authenticate yourself by passing the API key
# as the first method's argument
version = server.call("version.info", apikey)
Note
With ruby, use the xmlrpc/client module from the standard library.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <xmlrpc.h>
#include <xmlrpc_client.h>
#define CLIENT_NAME "Documentation Client"
#define CLIENT_VERSION "0.1"
#define CLIENT_USERAGENT CLIENT_NAME "/" CLIENT_VERSION
#define SERVER_URL "https://rpc.gandi.net/xmlrpc/"
int client_connect(xmlrpc_env *);
void client_check_fault(xmlrpc_env *);
int
main(int argc, char **argv)
{
xmlrpc_env env;
xmlrpc_value *apikey, *rv;
client_connect(&env);
apikey = xmlrpc_build_value(&env, "(s)", "my 24-character API key");
rv = xmlrpc_client_call_params(&env, SERVER_URL, "version.info", apikey);
client_check_fault(&env);
xmlrpc_DECREF(rv);
xmlrpc_DECREF(apikey);
xmlrpc_env_clean(&env);
xmlrpc_client_cleanup();
return (0);
}
int
client_connect(xmlrpc_env *env)
{
struct xmlrpc_clientparms clientp;
struct xmlrpc_curl_xportparms curlp;
curlp.network_interface = NULL; /* use curl's default */
curlp.ssl_verifypeer = 1; /* Gandi API CA must be present */
curlp.ssl_verifyhost = 2;
curlp.user_agent = CLIENT_USERAGENT; /* XML-RPC requirement */
clientp.transport = "curl";
clientp.transportparmsP = &curlp;
clientp.transportparm_size = XMLRPC_CXPSIZE(user_agent);
xmlrpc_env_init(env);
xmlrpc_client_init2(env, XMLRPC_CLIENT_NO_FLAGS, CLIENT_NAME,
CLIENT_VERSION, &clientp, XMLRPC_CPSIZE(transportparm_size));
client_check_fault(env);
return (1);
}
void
client_check_fault(xmlrpc_env *env)
{
if (env->fault_occurred) {
fprintf(stderr, "XML-RPC Fault: %s (%d)\n", env->fault_string,
env->fault_code);
exit(1);
}
}
Note
With C, use the xmlrpc-c library.
A server instance is represented by a virtual machine with the object hosting.vm. A hosting.vm object contains:
The attributes respect the following conventions:
Gandi Hosting provides devices & servers instances management in the cloud. The main object is the virtual machine or VM (server instance). You can attach devices like disks and network interfaces to a VM.
Note
The Hosting API only manages devices & servers instances. Billing (resources management) is managed on the control panel (Gandi.net website). It means you must have enough resources to create a new VM instance or device, or you will have to add resources using your Gandi.net control panel.
All resources you created are associated with an account, and you can call hosting.account.info() in order to obtain its information.
Gandi Hosting API is preparing a big change on the way it manages the user quota. Gandi Users will be all migrated to a new system based on the rating system. To know in which mode your account is, you have to check your hosting account information.
>>> account = hosting.account.info(apikey)
>>> account['rating_enabled']
False
If the rating_enabled is 0, you are still using the Shares model, otherwise, congratulations, your account has been migrated to Gandi credits.
Warning
This is a temporary situation, Gandi plans to migrate all existing accounts. Every shares and options are going to be cast in credits.
This change doesn’t break others api such as hosting.vm.create().
Note
Gandi has made the choice to drop the hosting.product API for many reasons. The introduction of credits is meant to simplify creation, management and renewal of your resources.
To create resources, you just now need credits, and your credit amount is shared by every hosting resources. To credit your account, just buy some via hosting.account.credit(). Credit are sells via packages, to get the pricing, use catalog.list() method. Then, to get resource prices, in credit, call the hosting.catalog.list(). Finally, watch your rating with hosting.rating.list().
>>> account = api.hosting.account.info(apikey)
>>> account['rating_enabled']
True
Gandi hosts virtual servers in several datacenters. At first, you need to choose where your servers instances will be:
>>> api.hosting.datacenter.list(apikey)
[{'country': 'France',
'id': 1,
'iso': 'FR',
'name': 'Equinix Paris'},
{'country': 'United States of America',
'id': 2,
'iso': 'US',
'name': 'Level3 Baltimore'}]
You can automate this by retrieving the datacenter’s country from the configuration file:
>>> fr_datacenters = [dc for dc in api.hosting.datacenter.list(apikey)
... if dc['country'].lower() == myvm_description['datacenter'].lower()]
>>> fr_datacenters
[{'country': 'France', 'id': 1, 'iso': 'FR', 'name': 'Equinix Paris'}]
>>> dc_id = fr_datacenters[0]['id']
Before you create a VM, you need to choose the disk image with the OS you want. Lets imagine you want to create a VM with an Ubuntu image:
>>> images = api.hosting.image.list(apikey, {'datacenter_id': 1})
>>> ubuntu_images = [x for x in images if x['label'].lower().startswith('ubuntu')]
>>> ubuntu_images
[{'author_id': 248842,
'datacenter_id': 1,
'date_created': <DateTime '20100101T00:00:00' at 25cd248>,
'date_updated': <DateTime '20101007T06:43:17' at 25cd200>,
'disk_id': 43024,
'id': 15,
'label': 'Ubuntu 9.10',
'os_arch': 'x86-32',
'visibility': 'all'},
{'author_id': 248842,
'datacenter_id': 1,
'date_created': <DateTime '20100101T00:00:00' at 25cd2d8>,
'date_updated': <DateTime '20101007T06:43:17' at 25cd290>,
'disk_id': 45512,
'id': 16,
'label': 'Ubuntu 9.10 + ispCP',
'os_arch': 'x86-32',
'visibility': 'alpha'},
{'author_id': 248842,
'datacenter_id': 1,
'date_created': <DateTime '20100101T00:00:00' at 25cd368>,
'date_updated': <DateTime '20101007T06:43:17' at 25cd320>,
'disk_id': 49300,
'id': 17,
'label': 'Ubuntu 9.10 + Cherokee',
'os_arch': 'x86-32',
'visibility': 'all'},
{'author_id': 248842,
'datacenter_id': 1,
'date_created': <DateTime '20100101T00:00:00' at 25cd3f8>,
'date_updated': <DateTime '20101007T06:43:17' at 25cd3b0>,
'disk_id': 51848,
'id': 18,
'label': 'Ubuntu 10.04',
'os_arch': 'x86-32',
'visibility': 'all'}]
It will return the list of all images with a name like (‘~’) ubuntu (case-insensitive). You can filter the list for the version:
>>> filter(lambda x: '10.04' in x['label'], ubuntu_images)
[{'author_id': 248842,
'datacenter_id': 1,
'date_created': <DateTime '20100101T00:00:00' at 25cd3f8>,
'date_updated': <DateTime '20101007T06:43:17' at 25cd3b0>,
'disk_id': 51848,
'id': 18,
'label': 'Ubuntu 10.04',
'os_arch': 'x86-32',
'visibility': 'all'}]
Let take the disk associated with this image to create our VM:
>>> src_disk_id = 51848
Note
You may choose a disk image you created yourself and configured to fit your needs. It is easier to duplicate VMs this way.
Create the VM from a vm_spec mapping with hosting.vm.create_from():
>>> disk_spec = {
'datacenter_id': dc_id,
'name': myvm_description['disks'][0]}
>>> vm_spec = {
'datacenter_id':dc_id,
'hostname': myvm_description['hostname'],
'memory': myvm_description['memory'],
'cores': myvm_description['cores'],
'ip_version': myvm_description['ifaces']['ip_version'],
'bandwidth': myvm_description['ifaces']['bandwidth'],
'password': 'password_to_change'}
>>> op = api.hosting.vm.create_from(apikey, vm_spec, disk_spec, src_disk_id)
hosting.vm.create_from() takes the VM specification as its second argument, the disk specification as its third and finally the source disk id. Behind the scenes, the Gandi backend creates a new disk from the source disk. When you ask Gandi to create a VM, the VM is not immediately available. It will start to work in Gandi’s backend to prepare the environment of the VM. This work is tracked with the Operation.
A VM create operation does 3 operations:
- disk_create
- iface_create
- vm_create
You can poll the operation status by calling operation.info():
>>> op2 = api.operation.info(apikey, op[2]['id'])
>>> vm_id = op2['params']['vm_id']
>>> vm_id
63907
Note
in order to boot, a VM will use the cmdline defined with its first disk. With a linux disk image, cmdline may contain root=/dev/xvda1. This means the kernel will mount the first partition of the first disk as the root filesystem.
The process of VM creation will automatically create a network interface. When creating a network interface, the system tries to recycle an IP. If you have already released an IP (by deleting the network interface that was using it), the next created network interface will get the old IP.
After the creation, the VM is automatically started.
Once the VM has successfully started you can log in:
$ ssh user@vm_ip
<enter password from vm_spec passed to vm.create>
Note
You may want to add an SSH public key for some users in ~<user>/.ssh/authorized_keys . Please refer to the system administration and security manual of the operation system distribution. You may also add directly the public SSH key in the vm_spec object using the ssh_key parameter. The vm_spec can manage password, SSH key or both.
The VM is running and you want to increase its memory:
>>> op = api.hosting.vm.update(apikey, vm['id'], {'memory': 1024})
The following VM attributes can be updated:
The state is managed by hosting.vm.start(), hosting.vm.reboot(), and hosting.vm.stop().
Note
vm_max_memory is used to limit the memory reserved by xen to manage memory allocation on the guest. It is an implementation-specific attribute we need to expose to the user. In practice, it defines the maximum memory the VM can manage. When a VM is created with less than 2048MB of memory, vm_max_memory is equal to 2048MB. If you want to increase memory beyond this limit you need to update vm_max_memory and reboot the VM.