Gandi

Table Of Contents

Previous topic

Gandi Site API

Next topic

Site API Reference

Site API

Introduction

The Gandi Site API provides a set of remote requests to manage your sites. Gandi site are based on website builder provider. Actually, this api is build on top of basekit.

Connect to the API server

The Gandi Site 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)

Note

In Python, use the xmlrpclib module from the standard library.

In Python 3 xmlrpclib has been renamed xmlrpc.client.

<?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);
?>

Note

In PHP 5, use the XML_RPC2 package from pear.

XML_RPC2 works with ‘prefix’ in order to bind to namespace. The ‘prefix’ isn’t editable, so you have to instanciante a client by namespace.

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

class ZlibParserDecorator
  def initialize(parser)
    @parser = parser
  end
  def parseMethodResponse(responseText)
    @parser.parseMethodResponse(Zlib::GzipReader.new(StringIO.new(responseText)).read)
  end
  def parseMethodCall(*args)
    @parser.parseMethodCall(*args)
  end
end


server = XMLRPC::Client.new2('https://rpc.gandi.net/xmlrpc/')
server.http_header_extra = { "Accept-Encoding" => "gzip" }
server.set_parser ZlibParserDecorator.new(server.send(:parser))

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. Ruby does not support gzip by default, the ZlibParserDecorator is used to enabled with Ruby >1.9.

For older ruby version, neither set the http_header_extra nor the parser.

Note

To avoid RuntimeError with ruby >= 1.9, add:

XMLRPC::Config.module_eval {
    remove_const(:ENABLE_NIL_PARSER)
    const_set(:ENABLE_NIL_PARSER, true)
}
#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.

Site Management

List your sites

To list the sites you own, just call the site.list() method:

>>> api.site.list(apikey)
[]

Count your sites

To count sites you own, just call the site.count() method:

>>> api.site.count(apikey)
0

Get info on a site

Get info on an instance with method site.info() method:

>>> api.site.info(apikey, 1)

Create a site

To create a site, use the site.create() method by specifying a name, virtual hosts and other optional parameters.

>>> site_spec = {
    'name': 'My Site',
    'provider': 'basekit_whitelabel',
    'vhosts': ['example.bk-site.net'],
    'duration': '3m'}
>>> op = api.site.create(apikey, site_spec)
>>> op['type']
'sitebuilder_create'

Then, you have to wait that the operation has succeed for continue.

>>> import time
>>> while op['step'] not in('DONE', 'ERROR'):
        time.sleep(1)
        op = api.operation.info(apikey, op['id'])
>>> op['step']
'DONE'
>>> site_id = api.site.list(apikey, {'name': 'My Site'})[0]['id']

Edit the web site

When the create operation has been done, the site is created, to edit it, retrieve the edition url given in the site.info()

>>> api.site.info(apikey, 158)['edit_url']

Manage Virtual Hosts

In order to ship a web site, it must be attached to a virtual host. Every Provider is coming with a domain name to host them in a subdomain. There is few restrictions about the name, but the main one is: the subdomain is unique. first come, first served.

Besides, A site can be attached to many virtual hosts.It’s the vhosts key in this API (see SiteCreate, SiteUpdate, SiteReturn). You can host your web site on gandi domains without DNS modification and with any domain names (see Additional information about security).

Furthermore, the vhosts orders is important to set or retrieve the preferred vhosts. The preferred vhost is used for the SEO and is also retrieved in the SiteListReturn.

Add the virtualhost ‘www.mydomain.fr’ on the previous site.

>>> # add the virtual host www.mydomain.fr to the domain
>>> vhosts = ['www.mydomain.fr', 'example.bk-site.net']
>>> op = api.site.update(apikey, site_id, {'vhosts': vhosts})
>>> ops[0]['type']
'sitebuilder_update'

Important

It is required to keep the site attach to the Provider domain in order to edit the site.

Important

You must send all virtual hosts. The omitted ones will be deleted.

Upgrade to another offer

>>> # Checkout the prices
>>> prices api.catalog.list(key, {'product': {'type': 'site'}})
>>> # Retrieve list of offers
>>> api.site.package.list(key, {'provider': 'basekit_whitelabel'})

A site can be update to another offer, but cannot be downgraded. It is possible to filter the appropriate “next” offer by using the ‘>name’ filter.

>>> package = api.site.package.list(key, {'provider': 'basekit_whitelabel', '>name': 'personal'})[0]
>>> package
{'name': 'professional', 'provider': 'basekit_whitelabel'}

You can also get the price of this operation.

>>> descr = "{provider}_{name}".format(**package)
>>> api.catalog.list(key, {"product": {"type": "site", "description": descr}, "action": {"name": "update"}})

See the Catalog API for more usage.

The site.update method is free for every usage except the package upgrade.

Delete a site

To delete an instance, use the site.delete() method:

>>> op = api.site.delete(apikey, site_id)
>>> op['type']
'sitebuilder_delete'

Additional information about security

If you are not using the Gandi DNS or you did not register your domain at Gandi, you can also run a Site instance hosted at Gandi. Gandi must verify that the domain is your own by checking you have administration privilege on it. To perform that, Gandi will check DNS record on the vhost you want to bind to a site.

>>> site_spec = {
    'name': 'My Site',
    'package': 'professional',
    'vhosts': ['vhost.test.fr', 'bk-site.net'],
    '--dry-run': True}
>>> ops = api.site.create(apikey, site_spec)
[{'attr': ['vhost.test.fr', 'vhost=2e5d8f0899053fffcd3ecf4ac5a6433b'],
  'error': 'EC_TXT+EC_MISSINGMANDATORY',
  'field': 'vhosts',
  'field_type': None,
  'reason': 'You must put a TXT value in your zone'}]

The DNS zone must be altered to store the record like:

10800 IN TXT “vhost=2e5d8f0899053fffcd3ecf4ac5a6433b”