Estimer le VSI pour Bluemix IaaS (anciennement SoftLayer) via l'API

Contenu

Lors de l'estimation d'un nouveau VSI, émettez une estimation via l'API.

supposition

Il est supposé que vous comprenez les articles suivants. En savoir plus sur l'API Bluemix Infrastructure (anciennement SoftLayer).

ShinobiLayer: API SoftLayer Étape suivante: objet de type de données (1) --Qiita

Obtenir locationId

J'ai créé un script pour obtenir le locationId, veuillez donc l'utiliser. (Il est également possible de spécifier à l'aide de keyname.)

scénario

getDcLocationId.py


import SoftLayer
import json
from prettytable import PrettyTable

# account info
client = SoftLayer.create_client_from_env()

#objectmask
objectmask = """
	longName,
	name,
	regions[keyname],
	locationAddress[
		locationId,
		address1,
		address2,
		city,
		country,
		postalCode,
		state
	]
"""
dcs = client['Location'].getDatacenters(mask=objectmask)
#dcs_jsonstring = json.dumps(dcs,indent=4)
#print(dcs_jsonstring) 

table = PrettyTable([
	'ID',
	'KeyName',
	'Name',
	'Detail',
	'Country',
	'State',
	'PostalCode',
	'City',
	'Address1',
	'Address2'
])

    
for key in range(len(dcs)):
	if 'locationAddress' in dcs[key]:
		if 'regions' in dcs[key]:
			table.add_row([
				dcs[key]['locationAddress']['locationId'],
				dcs[key]['regions'][0]['keyname'],
				dcs[key]['name'],
				dcs[key]['longName'],
				dcs[key]['locationAddress'].get('country',""),
				dcs[key]['locationAddress'].get('state',""),
				dcs[key]['locationAddress'].get('postalCode',"")[:11],
				dcs[key]['locationAddress'].get('city',""),
				dcs[key]['locationAddress'].get('address1',""),
				dcs[key]['locationAddress'].get('address2',"")
			])
		else:
			table.add_row([
				dcs[key]['locationAddress']['locationId'],
				dcs[key].get('regions',""),
				dcs[key]['name'],
				dcs[key]['longName'],
				dcs[key]['locationAddress'].get('country',""),
				dcs[key]['locationAddress'].get('state',""),
				dcs[key]['locationAddress'].get('postalCode',"")[:11],
				dcs[key]['locationAddress'].get('city',""),
				dcs[key]['locationAddress'].get('address1',""),
				dcs[key]['locationAddress'].get('address2',"")
			])
	else:
		table.add_row([
			dcs[key].get('locationAddress',""),
			dcs[key]['regions'][0]['keyname'],
			dcs[key]['name'],
			dcs[key]['longName'],
			dcs[key].get('locationAddress',""),
			dcs[key].get('locationAddress',""),
			dcs[key].get('locationAddress',""),
			dcs[key].get('locationAddress',""),
			dcs[key].get('locationAddress',""),
			dcs[key].get('locationAddress',"")
		])

print len(dcs)
print table.get_string(sortby="Name")

Exemple de résultat d'exécution

#Commande d'exécution
python getDcLocationId.py 

#résultat
32
+---------+---------------+-------+--------------+---------+-------+-------------+----------------+----------------------------------------------------------------------------------+-----------------------+
|    ID   |    KeyName    |  Name |    Detail    | Country | State |  PostalCode |      City      |                                     Address1                                     |        Address2       |
+---------+---------------+-------+--------------+---------+-------+-------------+----------------+----------------------------------------------------------------------------------+-----------------------+
|  265592 |   AMSTERDAM   | ams01 | Amsterdam 1  |    NL   |       |   1096 BK   |   Amsterdam    |                           Paul van Vlissingenstraat 16                           |                       |
|  814994 |  AMSTERDAM03  | ams03 | Amsterdam 3  |    NL   |       |    1329BG   |     Almere     |                                    Flevoland                                     |    Rondebeltweg 62,   |
| 1004997 |    CHENNAI    | che01 |  Chennai 1   |    IN   |       |    600053   |    Chennai     |                               226, Red Hills Road                                | Kallikuppam, Ambattur |
|    3    |     DALLAS    | dal01 |   Dallas 1   |    US   |   TX  |    75207    |     Dallas     |                              1950 Stemmons Freeway                               |       Suite 3048      |
|         |    DALLAS02   | dal02 |   Dallas 2   |         |       |             |                |                                                                                  |                       |
|  138124 |    DALLAS05   | dal05 |   Dallas 5   |    US   |   TX  |    75244    |     Dallas     |                                 4849 Alpha Road                                  |                       |
|  154820 |    DALLAS06   | dal06 |   Dallas 6   |    US   |   TX  |    75207    |     Dallas     |                             1333 N. Stemmons Freeway                             |       Suite 110       |
|         |    DALLAS07   | dal07 |   Dallas 7   |         |       |             |                |                                                                                  |                       |
|  449494 |    DALLAS09   | dal09 |   Dallas 9   |    US   |   TX  |    75081    |   Richardson   |                                 900 Quality Way                                  |                       |
| 1441195 |    DALLAS10   | dal10 |  Dallas 10   |    US   |   TX  |    75063    |     Irving     |                               6431 Longhorn Drive                                |                       |
|  449506 |   FRANKFURT   | fra02 | Frankfurt 2  |    DE   |       |    65936    |   Frankfurt    |                           Leonard - Heisswolf - Str 4.                           |                       |
|  352494 |   HONGKONG02  | hkg02 | Hong Kong 2  |    HK   |       |             |   Hong Kong    | 33 Chun Choi Street, Tseung Kwan O Industrial Estate, New Territories, Hong Kong |                       |
|  142775 |   HOUSTON02   | hou02 |  Houston 2   |    US   |   TX  |    77067    |    Houston     |                                855 Greens Parkway                                |       Suite 300       |
|  358694 |    LONDON02   | lon02 |   London 2   |    GB   |       |   KT9 1SJ   |  Chessington   |                             Fountain Court, Cox Lane                             |   Suites 210 and 230  |
|  449596 |   MELBOURNE   | mel01 | Melbourne 1  |    AU   |       |   VIC 3032  |   Melbourne    |                            72 Radnor Drive, Deer Park                            |                       |
|  449600 |     MEXICO    | mex01 |   Mexico 1   |    MX   |       |             |   Querétaro   |                Km 2 200, Lateral Carretera Estatal 431 El Marques                |                       |
|  815394 |     MILAN     | mil01 |   Milan 1    |    IT   |       |    20010    |   CORNAREDO    |                                 VIA MONZORO 103                                  |                       |
|  449610 |    MONTREAL   | mon01 |  Montreal 1  |    CA   |   QC  |   J2C 7W2   | Drummondville  |                                2525 Rue Canadien                                 |                       |
| 1541257 |      OSLO     | osl01 |    Oslo 1    |    NO   |       |     1900    |    Fetsund     |                                 Fet Næringspark                                 |      Heiaveien 9      |
|  449500 |     PARIS     | par01 |   Paris 1    |    FR   |       |    92582    |     Clichy     |                 Société par Actions Simplifiée Unipersonnelle                 |     7-9 rue Petit     |
|  983497 |    SAOPAULO   | sao01 | Sao Paulo 1  |    BR   |       |   Km 67,7   |   Medeiros     |                          Rod Dom Gabriel Paulino Couto,                          |                       |
|  18171  |    SEATTLE    | sea01 |  Seattle 1   |    US   |   WA  |    98168    |    Tukwila     |                         3355 S. 120th Place, Suite# 331                          |                       |
| 1555995 |     SEOUL     | seo01 |   Seoul 1    |    KR   |       | Gyeonggi-do |  Seongnam-si   |                            46, Pangyo-ro 255beon-gil                             |       Bundang-gu      |
|  168642 |    SANJOSE    | sjc01 |  San Jose 1  |    US   |   CA  |    95054    |  Santa Clara   |                            3105 Alfred St, Suite 331                             |                       |
| 1004995 |   SANJOSE03   | sjc03 |  San Jose 3  |    US   |   CA  |    95054    |  Santa Clara   |                              1100 Space Park Drive                               |                       |
|  224092 |   SINGAPORE   | sng01 | Singapore 1  |    SG   |       |    139964   |  East Jurong   |                         29A International Business Park                          |                       |
|  449612 |     SYDNEY    | syd01 |   Sydney 1   |    AU   |       | Ultimo, NSW |     Ultimo     |                                273 Pymont Street                                 |                       |
| 2013295 |               | syd04 |   Sydney 4   |    AU   |       |    2759     |    Sydney      |                                1 13, Templar Road                                |      Erskine Park     |
|  449604 |     TOKYO     | tok02 |   Tokyo 2    |    JP   |       |   135-0061  | Koto-ku, Tokyo |                                  6-2-12 Toyosu                                   |                       |
|  448994 |    TORONTO    | tor01 |  Toronto 1   |    CA   |   ON  |   L3R 4B6   |    Markham     |                                    Suite 130                                     |       371 Gough       |
|  37473  | WASHINGTON_DC | wdc01 | Washington 1 |    US   |   VA  |    20151    |   Chantilly    |                           4030 Lafayette Center Drive                            |       Suite 331       |
|  957095 |   ASHBURN04   | wdc04 | Washington 4 |    US   |   VA  |    20147    |    Ashburn     |                           44060 Digital Loudoun Plaza                            |                       |
+---------+---------------+-------+--------------+---------+-------+-------------+----------------+----------------------------------------------------------------------------------+-----------------------+

Obtenir PackageId

J'ai créé un script pour obtenir le PackageId, veuillez donc l'utiliser.

scénario

getActivePackages.py


# import
import SoftLayer
from prettytable import PrettyTable

#define objectmask
objectmask = """
    id,
    name,
    keyName,
    subDescription
"""

#define table
table = PrettyTable([
    'PackageID',
    'Name',
    'keyName',
    'subDescription'
])

# account info
client = SoftLayer.create_client_from_env()
getActivePackages = client['Account'].getActivePackages(mask=objectmask)

for key in range(len(getActivePackages)):
        table.add_row([
            getActivePackages[key]['id'],
            getActivePackages[key]['name'],
            getActivePackages[key]['keyName'],
            getActivePackages[key]['subDescription']
        ])

print len(getActivePackages)
print table.get_string(sortby="PackageID")

Exemple de résultat d'exécution

#Commande d'exécution
python getActivePackages.py 

#résultat
35
+-----------+-------------------------------------+--------------------------------------+-------------------------------------+
| PackageID |                 Name                |               keyName                |            subDescription           |
+-----------+-------------------------------------+--------------------------------------+-------------------------------------+
|     46    |             Cloud Server            |             CLOUD_SERVER             |       Virtual Server Instance       |
|    174    |      Network Gateway Appliance      |      NETWORK_GATEWAY_APPLIANCE       |      Network Gateway Appliance      |
|    192    |    Application Delivery Appliance   |    APPLICATION_DELIVERY_APPLIANCE    |    Application Delivery Appliance   |
|    194    |            Load Balancers           |            LOAD_BALANCERS            |            Load Balancers           |
|    198    |           Portable Storage          |           PORTABLE_STORAGE           |           Portable Storage          |
|    200    |          Bare Metal Server          |          BARE_METAL_SERVER           |          Bare Metal Server          |
|    206    |            Object Storage           |            OBJECT_STORAGE            |            Object Storage           |
|    208    |       Content Delivery Network      |       CONTENT_DELIVERY_NETWORK       |       Content Delivery Network      |
|    210    |           SSL Certificate           |           SSL_CERTIFICATE            |           SSL Certificate           |
|    212    |            Message Queue            |            MESSAGE_QUEUE             |            Message Queue            |
|    216    |       Network Attached Storage      |       NETWORK_ATTACHED_STORAGE       |       Network Attached Storage      |
|    218    |            iSCSI Storage            |            ISCSI_STORAGE             |            iSCSI Storage            |
|    222    |             Performance             |     PERFORMANCE_STORAGE_SERVICE      |         Performance Storage         |
|    226    |       Authentication Services       |       AUTHENTICATION_SERVICES        |       Authentication Services       |
|    236    | Network Gateway Appliance (10 Gbps) | 2U_NETWORK_GATEWAY_APPLIANCE_1O_GBPS | Network Gateway Appliance (10 Gbps) |
|    242    |            POWER8 Servers           |            POWER8_SERVERS            |            POWER8 Servers           |
|    244    |              Monitoring             |              MONITORING              |              Monitoring             |
|    248    |  Dual E5-2600 v3 Series (36 Drives) |       DUAL_E52600_V3_36_DRIVES       |  Dual E5-2600 v3 Series (36 Drives) |
|    251    |  Dual E5-2600 v3 Series (12 Drives) |     2U_DUAL_E52600_V3_12_DRIVES      |  Dual E5-2600 v3 Series (12 Drives) |
|    253    |  Dual E5-2600 v3 Series (4 Drives)  |         DUAL_E52600_4_DRIVES         |  Dual E5-2600 v3 Series (4 Drives)  |
|    255    |      Single E3-1270 (4 Drives)      |        SINGLE_E31270_4_DRIVES        |      Single E3-1270 (4 Drives)      |
|    257    |     Single E3-1270 v3 (4 Drives)    |      SINGLE_E31270_V3_4_DRIVES       |      Single E3-1270 (4 Drives)      |
|    259    |   Single E5-2600 Series (4 Drives)  |        SINGLE_E52600_4_DRIVES        |   Single E5-2600 Series (4 Drives)  |
|    261    |      Single E3-1270 (2 Drives)      |        SINGLE_E31270_2_DRIVES        |      Single E3-1270 (2 Drives)      |
|    263    |   Dual E5-2600 Series (36 Drives)   |       4U_DUAL_E52600_36_DRIVES       |   Dual E5-2600 Series (36 Drives)   |
|    265    |   Dual E5-2600 Series (12 Drives)   |       2U_DUAL_E52600_12_DRIVES       |   Dual E5-2600 Series (12 Drives)   |
|    267    |   Quad E5-4600 Series (24 Drives)   |       4U_QUAD_E54600_24_DRIVES       |   Quad E5-4600 Series (24 Drives)   |
|    269    |   Quad E7-4800  Series (6 Drives)   |       2U_QUAD_E74800_6_DRIVES        |   Quad E7-4800  Series (6 Drives)   |
|    271    |  Quad E7-4800 v2 Series (24 Drives) |      2U_QUAD_E74800_V2_6_DRIVES      |  Quad E7-4800 v2 Series (24 Drives) |
|    273    |       Dual E5-2600 (4 Drives)       |        DUAL_E52600_4_DRIVES_2        |       Dual E5-2600 (4 Drives)       |
|    295    |          Certified Servers          |      SAP_HANA_CERTIFIED_SERVERS      |        SAP Certified Servers        |
|    297    |          Certified Servers          |   SAP_NETWEAVER_CERTIFIED_SERVERS    |        SAP Certified Servers        |
|    551    |  Dual E5-2600 v4 Series (4 Drives)  |       DUAL_E52600_V4_4_DRIVES        |  Dual E5-2600 v4 Series (4 Drives)  |
|    553    |  Dual E5-2600 v4 Series (12 Drives) |       DUAL_E52600_V4_12_DRIVES       |  Dual E5-2600 v4 Series (12 Drives) |
|    555    |  Dual E5-2600 v4 Series (36 Drives) |       DUAL_E52600_V4_36_DRIVES       |  Dual E5-2600 v4 Series (36 Drives) |
+-----------+-------------------------------------+--------------------------------------+-------------------------------------+

Obtenir ItemId

J'ai créé un script pour obtenir ItemId, veuillez donc l'utiliser.

scénario

getCategoriesAndItemPrices.py


import SoftLayer
import json
from prettytable import PrettyTable
import operator
 
# Get the SoftLayer API client object
client = SoftLayer.create_client_from_env()
 
def getItems(pkgId):
    # Get a list of the categories that can be specified and the item prices within each category that you can choose from.
    # Build a dict of each category id and what its categoryCode is.  This is only used to build the item dict below.
    categories = client['Product_Package'].getConfiguration(id=pkgId, mask='isRequired, itemCategory.id, itemCategory.name, itemCategory.categoryCode')
    cats = {}
    for cat in categories:
        catid = cat['itemCategory']['id']
        cats[catid] = {'code':cat['itemCategory']['categoryCode'], 'name':cat['itemCategory']['name'], 'isRequired':(cat['isRequired'] == 1)}
 
    # Go thru the items for this pkg and put the key/id pair in the correct category
    # Note: the keys are only unique within categories, not between categories
    mask = 'id, itemId, recurringFee, hourlyRecurringFee, item.description, item.keyName, categories.id'
    itemPrices = client['Product_Package'].getItemPrices(id=pkgId, mask=mask)
    items = {}          # this is a 2 level dict: 1st key is categoryCode, 2nd key is item keyName, value is item price id and other info
    for itemP in itemPrices:
        if 'categories' not in itemP:  continue
        itemId = itemP['id']
        itemDesc = itemP['item']['description']
        itemKeyName = itemP['item']['keyName']
        if 'recurringFee' in itemP:  itemFee = itemP['recurringFee']
        else:  itemFee = '0'
        if 'hourlyRecurringFee' in itemP:  itemHourlyFee = itemP['hourlyRecurringFee']
        else:  itemHourlyFee = None
        # Go thru this item's supported categories
        for itemCat in itemP['categories']:
            itemCatId = itemCat['id']
            # We correlate the categories and items by the category id
            if itemCatId in cats:
                # This item supports a category in this package, so add it to the structure under this category
                categoryCode = cats[itemCatId]['code']
                # If we haven't yet added an entry for this categoryCode, create it now
                if categoryCode not in items:  items[categoryCode] = {'catName':cats[itemCatId]['name'], 'isRequired':cats[itemCatId]['isRequired'], 'items':{}}
                entry = {'id':itemId, 'description':itemDesc, 'fee':itemFee}
                if itemHourlyFee:  entry['hourlyFee'] = itemHourlyFee
                if itemKeyName in items[categoryCode]['items']:  print 'Warning: items['+categoryCode+"]['items']["+itemKeyName+'] already has a value of '+str(items[categoryCode]['items'][itemKeyName])+' and we are overwriting it with '+str(entry)
                # Now add the item to this category
                items[categoryCode]['items'][itemKeyName] = entry
    return items
 
pkgId = 46     # specify the package id you want = Virtual Server
#pkgId = 297     # SAP Certified Servers 
items = getItems(pkgId)
#jsonstring = json.dumps(items,indent=4)
#print(jsonstring) 

# define table
table = PrettyTable([
    'keyCategory',
    'isRequired',
    'catName',
    'id',
    'fee',
    'hourlyFee',
    'description'
])

for i in range(len(items)):
	eachItem = items.keys()[i]
	for j in range(len(items[eachItem]['items'].keys())):
		itemContent = items[eachItem].keys()[2]
		itemName = items[eachItem][itemContent].keys()[j]
		table.add_row([
			items.keys()[i],
			items[eachItem]['isRequired'],
			items[eachItem]['catName'],
			items[eachItem][itemContent][itemName].get('id',""),
			items[eachItem][itemContent][itemName].get('fee',""),
			items[eachItem][itemContent][itemName].get('hourlyFee',""),
			items[eachItem][itemContent][itemName].get('description',"")
		])

print table.get_string(sort_key=operator.itemgetter(1,7),sortby='keyCategory')

Exemple de résultat d'exécution

#Commande d'exécution
python getCategoriesAndItemPrices.py 

#résultat
+-------------------------+------------+----------------------------------------+--------+---------+-----------+-----------------------------------------------------------------------+
|       keyCategory       | isRequired |                catName                 |   id   |   fee   | hourlyFee |                              description                              |
+-------------------------+------------+----------------------------------------+--------+---------+-----------+-----------------------------------------------------------------------+
|  av_spyware_protection  |   False    |    Anti-Virus & Spyware Protection     | 34536  |    0    |     0     |                      McAfee VirusScan Enterprise                      |
|        bandwidth        |    True    |            Public Bandwidth            | 24745  |   1500  |           |                 Unlimited Bandwidth (100 Mbps Uplink)                 |
|        bandwidth        |    True    |            Public Bandwidth            | 34183  |    0    |     0     |                             0 GB Bandwidth                            |
|        bandwidth        |    True    |            Public Bandwidth            | 35963  |    0    |           |                             0 GB Bandwidth                            |
|        bandwidth        |    True    |            Public Bandwidth            | 50253  |  494.45 |           |                           10000 GB Bandwidth                          |
|        bandwidth        |    True    |            Public Bandwidth            | 50369  |    0    |           |                            250 GB Bandwidth                           |
|        bandwidth        |    True    |            Public Bandwidth            | 78465  | 1448.56 |           |                           20000 GB Bandwidth                          |
|        bandwidth        |    True    |            Public Bandwidth            | 153549 |  745.74 |           |                           5000 GB Bandwidth                           |
|        bandwidth        |    True    |            Public Bandwidth            | 164857 |   90.7  |           |                           1000 GB Bandwidth                           |
|       bc_insurance      |   False    |               Insurance                | 24329  |    0    |     0     |                     Business Continuance Insurance                    |
|        cdp_backup       |   False    |               CDP Addon                | 32414  |  36.25  |           |                        Idera Disk Agent 10 Pack                       |
...

Émission d'un nouveau devis VSI

Utilisez pleinement le locationId, PackageId et ItemId obtenus ci-dessus pour émettre une estimation.

scénario

placeQuoteVsi.py


#import package
import SoftLayer
import json

# account info
client = SoftLayer.create_client_from_env()

order = {
	"orderContainers": [{
		'complexType': 'SoftLayer_Container_Product_Order_Virtual_Guest', 
		'quantity': 1,
		'virtualGuests': [{
        		'hostname': 'test', 
        		'domain': 'example.com',
      		}],
		'primaryDiskPartitionId': 1,
		'location': 449604, # Tokyo
		'packageId': 46,  # VSI
		'useHourlyPricing': False,
		'prices': [
           		{'id':26125},  # 1 x 2.0 GHz Core
           		{'id':32597},  # 1 GB RAM
           		{'id':23070},  # Reboot / Remote Console
        		{'id':26737},  # 100 Mbps Public & Private Networks
           		{'id':50369},  # 250 GB Bandwidth
           		{'id':34807},  # 1 IP Address
           		{'id':26466},  # 100 GB (LOCAL) First Disk
           		{'id':175779},  # Windows Server 2012 R2 Standard Edition (64 bit)
           		#{'id':171611},  # Ubuntu 16.04 (64 bit)
           		{'id':27023},  # Host Ping Monitoring
           		{'id':32500},  # Email and Ticket Notifications
           		{'id':32627},  # Automated Notification Response
           		{'id':33483},  # Unlimited SSL VPN Users & 1 PPTP VPN User per account
           		{'id':35310}   # Vulnerability Assessments & Management
		],
	},
	{
                'complexType': 'SoftLayer_Container_Product_Order_Virtual_Guest',
                'quantity': 1,
                'virtualGuests': [{ 
                        'hostname': 'test', 
                        'domain': 'example.com',
                }],
                "primaryDiskPartitionId": 1,
                'location': 449604, # Tokyo
                'packageId': 46,  # VSI
                'useHourlyPricing': False,
                'prices': [
                        {'id':26125},  # 1 x 2.0 GHz Core
                        {'id':32597},  # 1 GB RAM 
                        {'id':23070},  # Reboot / Remote Console
                        {'id':26737},  # 100 Mbps Public & Private Networks
                        {'id':50369},  # 250 GB Bandwidth
                        {'id':34807},  # 1 IP Address
                        {'id':26466},  # 100 GB (LOCAL) First Disk
                        #{'id':175779},  # Windows Server 2012 R2 Standard Edition (64 bit)
                        {'id':171611},  # Ubuntu 16.04 (64 bit)
                        {'id':27023},  # Host Ping Monitoring
                        {'id':32500},  # Email and Ticket Notifications
                        {'id':32627},  # Automated Notification Response
                        {'id':33483},  # Unlimited SSL VPN Users & 1 PPTP VPN User per account
                        {'id':35310}   # Vulnerability Assessments & Management
                ],
	}],
		'quoteName': "khayamaQuoteTest",
		'sendQuoteEmailFlag': True
}   

# placeQuote
placeQuote = client['Product_Order'].placeQuote(order)
#placeQuote = client['Product_Order'].verifyOrder(order)

#jsonstring = json.dumps(placeQuote,indent=4)
#print(jsonstring) 

Exemple de résultat d'exécution

#Commande d'exécution
python placeQuoteVsi.py

#résultat
Un devis pour le nom spécifié dans "quoteName" est enregistré sur le portail.

Sortie au format PDF

Vois ici. Enregistrer les citations Bluemix IaaS (anciennement SoftLayer) au format PDF via l'API - Qiita

Site référencé

Recommended Posts

Estimer le VSI pour Bluemix IaaS (anciennement SoftLayer) via l'API
Enregistrer les citations Bluemix IaaS (anciennement SoftLayer) au format PDF via l'API