> For the complete documentation index, see [llms.txt](https://docs.plenit.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.plenit.com/fr/referencia/cliente-sdk/cliente-sdk-python.md).

# Client SDK Python

La section actuelle détaille le Client SDK Python de Jotelulu pour l’accès simplifié à l’API publique de Jotelulu.

### 📖 Documentation de l’API

#### Points de terminaison principaux

| Service                | Point de terminaison                                  | Description                    |
| ---------------------- | ----------------------------------------------------- | ------------------------------ |
| **Noyau**              | `/core/v1/organizations`                              | Gestion des organisations      |
| **Noyau**              | `/core/v1/organizations/{id}/users`                   | Gestion des utilisateurs       |
| **Serveurs**           | `/servers/v1/subscriptions/{id}/instances`            | Instances de serveur           |
| **Serveurs**           | `/servers/v1/subscriptions/{id}/networks`             | Gestion des réseaux            |
| **Bureaux à distance** | `/remote-desktops/v1/subscriptions/{id}/instances`    | Instances de bureau à distance |
| **Bureaux à distance** | `/remote-desktops/v1/subscriptions/{id}/applications` | Applications                   |

#### Modèles principaux

* **Organisation**: Représente une organisation
* **Utilisateur**: Utilisateur du système
* **Abonnement**: Abonnement aux services
* **Instance**: Instance de serveur ou de bureau à distance
* **Application**: Application installable
* **NetworkInterface**: Interface réseau
* **FirewallInboundRule**: Règle de Pare-feu

#### 🚀 Installation dans un environnement virtuel (recommandé)

```bash
# Créer un environnement virtuel
python -m venv jotelulu-env

# Activer l’environnement virtuel
# Sous Windows :
jotelulu-env\Scripts\activate
# Sous Linux/macOS :
source jotelulu-env/bin/activate

# Installer le SDK
pip install generated-client-python
```

### 🔐 Authentification avec JWT

#### Configuration de base

```python
import openapi_client
from openapi_client.configuration import Configuration
from openapi_client.api_client import ApiClient

# Configurer le Client avec JWT
configuration = Configuration(
    host="https://connect-eu1.jotelulu.com",  # Production
    access_token="your_jwt_token_here"
)

# Créer le client API
api_client = ApiClient(configuration)
```

#### Configuration des environnements

```python
# Environnements disponibles
ENVIRONMENTS = {
    'production': 'https://connect-eu1.jotelulu.com'
}

# Configuration par environnement
def create_jotelulu_client(environment='production', token=None):
    configuration = Configuration(
        host=ENVIRONMENTS[environment],
        access_token=token
    )
    return ApiClient(configuration)
```

#### Gestion sécurisée des jetons

```python
import os
from openapi_client import Configuration, ApiClient

class JoteluluClient:
    def __init__(self, environment='production'):
        # Obtenir le token depuis les variables d’environnement
        token = os.getenv('JOTELULU_JWT_TOKEN')
        if not token:
            raise ValueError("La variable d’environnement JOTELULU_JWT_TOKEN est requise")
        
        self.configuration = Configuration(
            host=ENVIRONMENTS.get(environment, ENVIRONMENTS['production']),
            access_token=token
        )
        self.api_client = ApiClient(self.configuration)
    
    def get_organizations_api(self):
        from openapi_client.api.organizations_api import OrganizationsApi
        return OrganizationsApi(self.api_client)
    
    def get_instances_api(self):
        from openapi_client.api.instances_api import InstancesApi
        return InstancesApi(self.api_client)
```

### 🐍 Intégration avec Django

#### 1. Installation dans le projet Django

```bash
# Créer un nouveau projet Django
django-admin startproject mi_proyecto_jotelulu
cd mi_proyecto_jotelulu

# Créer une application
python manage.py startapp jotelulu_integration

# Installer les dépendances
pip install django
pip install generated-client-python
```

#### 2. Configuration dans settings.py

```python
# settings.py
import os

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'jotelulu_integration',  # Votre application
]

# Configuration Jotelulu
JOTELULU_SETTINGS = {
    'ENVIRONMENT': os.getenv('JOTELULU_ENV', 'production'),
    'JWT_TOKEN': os.getenv('JOTELULU_JWT_TOKEN'),
    'API_ENDPOINTS': {
        'production': 'https://connect-eu1.jotelulu.com'
    }
}
```

#### 3. Service Django pour Jotelulu

```python
# jotelulu_integration/services.py
from django.conf import settings
import openapi_client
from openapi_client.api.organizations_api import OrganizationsApi
from openapi_client.api.instances_api import InstancesApi
from openapi_client.api.applications_api import ApplicationsApi
from openapi_client.exceptions import ApiException

class JoteluluService:
    def __init__(self):
        jotelulu_config = settings.JOTELULU_SETTINGS
        environment = jotelulu_config['ENVIRONMENT']
        
        self.configuration = openapi_client.Configuration(
            host=jotelulu_config['API_ENDPOINTS'][environment],
            access_token=jotelulu_config['JWT_TOKEN']
        )
        self.api_client = openapi_client.ApiClient(self.configuration)
    
    def get_user_organizations(self):
        """Obtenir les organisations de l’Utilisateur actuel"""
        try:
            api_instance = OrganizationsApi(self.api_client)
            response = api_instance.list_user_organizations()
            return response.data
        except ApiException as e:
            print(f"Erreur lors de l’obtention des organisations : {e}")
            return []
    
    def get_organization_users(self, organization_id):
        """Obtenir les utilisateurs d’une organisation"""
        try:
            api_instance = OrganizationsApi(self.api_client)
            response = api_instance.list_organization_users(organization_id)
            return response.data
        except ApiException as e:
            print(f"Erreur lors de l’obtention des utilisateurs : {e}")
            return []
    
    def get_remote_desktop_instances(self, subscription_id):
        """Obtenir les instances de bureau à distance"""
        try:
            api_instance = InstancesApi(self.api_client)
            response = api_instance.list_remote_desktop_subscription_instances(subscription_id)
            return response.data
        except ApiException as e:
            print(f"Erreur lors de l’obtention des instances : {e}")
            return []
```

#### 4. Vues Django

```python
# jotelulu_integration/views.py
from django.shortcuts import render
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from .services import JoteluluService

def dashboard(request):
    """Vue principale du tableau de bord"""
    jotelulu = JoteluluService()
    organizations = jotelulu.get_user_organizations()
    
    context = {
        'organizations': organizations,
        'user': request.user
    }
    return render(request, 'jotelulu_integration/dashboard.html', context)

def organization_detail(request, organization_id):
    """Détail d’une organisation"""
    jotelulu = JoteluluService()
    users = jotelulu.get_organization_users(organization_id)
    
    return JsonResponse({
        'organization_id': organization_id,
        'users': [{'id': user.id, 'name': user.name, 'email': user.email} for user in users]
    })

@csrf_exempt
def create_organization_user(request, organization_id):
    """Créer un utilisateur dans l’organisation"""
    if request.method == 'POST':
        import json
        from openapi_client.model.create_organization_user_request import CreateOrganizationUserRequest
        from openapi_client.model.create_organization_user_request_data import CreateOrganizationUserRequestData
        
        data = json.loads(request.body)
        jotelulu = JoteluluService()
        
        try:
            api_instance = jotelulu.get_organizations_api()
            user_request = CreateOrganizationUserRequest(
                data=CreateOrganizationUserRequestData(
                    email=data['email'],
                    name=data['name'],
                    last_name=data['lastName'],
                    password=data.get('password')
                )
            )
            
            response = api_instance.create_organization_user(organization_id, user_request)
            return JsonResponse({'success': True, 'user_id': response.data.user_id})
            
        except Exception as e:
            return JsonResponse({'success': False, 'error': str(e)})
    
    return JsonResponse({'error': 'Méthode non autorisée'}, status=405)
```

#### 5. URLs Django

```python
# jotelulu_integration/urls.py
from django.urls import path
from . import views

app_name = 'jotelulu_integration'

urlpatterns = [
    path('', views.dashboard, name='dashboard'),
    path('organization/<str:organization_id>/', views.organization_detail, name='organization_detail'),
    path('organization/<str:organization_id>/users/', views.create_organization_user, name='create_user'),
]

# fichier urls.py principal du projet
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('jotelulu/', include('jotelulu_integration.urls')),
]
```

### 📚 Exemples d’Utilisation

#### Gestion des Organisations

```python
from openapi_client.api.organizations_api import OrganizationsApi
from openapi_client.model.create_organization_user_request import CreateOrganizationUserRequest

# Initialiser le client
client = JoteluluClient()
org_api = client.get_organizations_api()

# Lister les organisations de l’Utilisateur
organizations = org_api.list_user_organizations()
print(f"Organisations trouvées : {len(organizations.data)}")

# Lister les utilisateurs d’une organisation
org_id = "ORG-123"
users = org_api.list_organization_users(org_id)
for user in users.data:
    print(f"Utilisateur: {user.name} ({user.email})")

# Créer un nouvel utilisateur
new_user_request = CreateOrganizationUserRequest(
    data={
        'email': 'nuevo@ejemplo.com',
        'name': 'Nouveau',
        'lastName': 'Utilisateur',
        'password': 'password123',
        'twoFactorAuthRequired': True
    }
)
result = org_api.create_organization_user(org_id, new_user_request)
print(f"Utilisateur créé avec l'ID : {result.data.user_id}")
```

#### Gestion des instances et des Serveurs

```python
from openapi_client.api.instances_api import InstancesApi
from openapi_client.api.instance_api import InstanceApi

# APIs des instances
instances_api = InstancesApi(api_client)
instance_api = InstanceApi(api_client)

# Lister les instances de Remote Desktop
subscription_id = "SUB-456"
rd_instances = instances_api.list_remote_desktop_subscription_instances(subscription_id)

for instance in rd_instances.data:
    print(f"Instance : {instance.name} - État : {instance.state}")
    
    # Obtenir la progression du déploiement
    if instance.state == 'creating':
        progress = instance_api.get_instance_progress(subscription_id, instance.id)
        print(f"Progression : {progress.data.progress}")

# Lister les instances de serveur
server_instances = instance_api.list_server_subscription_instances(subscription_id)
print(f"Instances de serveur : {len(server_instances.data)}")
```

#### Gestion des applications

```python
from openapi_client.api.applications_api import ApplicationsApi
from openapi_client.model.create_instance_application_request import CreateInstanceApplicationRequest

apps_api = ApplicationsApi(api_client)

# Lister les applications disponibles
available_apps = apps_api.list_applications()
print("Applications disponibles :")
for app in available_apps.data:
    print(f"- {app.name} (ID : {app.id})")

# Lister les applications d'un Abonnement
subscription_apps = apps_api.list_subscription_applications(subscription_id)
print(f"Applications installées : {len(subscription_apps.data)}")

# Installer une nouvelle application
install_request = CreateInstanceApplicationRequest(
    data={
        'instanceId': 'INST-789',
        'applicationId': 'APP-123'
    }
)
result = apps_api.create_instance_application(subscription_id, install_request)
print(f"Application installée: {result.data[0].id}")
```

#### Gestion des réseaux et du Pare-feu

```python
from openapi_client.api.networks_api import NetworksApi
from openapi_client.api.pare-feu_api import Pare-feuApi
from openapi_client.model.create_isolated_network_request import CreateIsolatedNetworkRequest
from openapi_client.model.create_pare-feu_inbound_rule_request import CreatePare-feuInboundRuleRequest

networks_api = NetworksApi(api_client)
pare-feu_api = Pare-feuApi(api_client)

# Créer un réseau isolé
network_request = CreateIsolatedNetworkRequest(
    data={
        'name': 'Mon Réseau privé',
        'network': '192.168.100.0',
        'netmask': '255.255.255.0',
        'gateway': '192.168.100.1'
    }
)
network = networks_api.create_isolated_network(subscription_id, network_request)
print(f"Réseau créé : {network.data.name}")

# Créer une règle de Pare-feu
règle_pare-feu = CréerDemandeDeRègleEntrantePare-feu(
    data={
        'protocole': 'TCP',
        'publicNetworkId': 'NET-456',
        'privateNicAddressIpId': 'NIC-789',
        'publicPort': 80,
        'privatePort' : 8080,
        'origin': '0.0.0.0/0'
    }
)
rule = Pare-feu_api.create_Pare-feu_inbound_rule(
    subscription_id, 
    network.data.main_network_id, 
    Pare-feu_rule
)
print(f"Règle de Pare-feu créée : {rule.data.id}")
```

### 🛠️ Gestion des erreurs

```python
from openapi_client.exceptions import ApiException
import logging

# Configurer la journalisation
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def safe_api_call(api_function, *args, **kwargs):
    """Wrapper pour les appels sécurisés à l'API"""
    try:
        return api_function(*args, **kwargs)
    except ApiException as e:
        logger.error(f"Erreur API : {e.status} - {e.reason}")
        logger.error(f"Corps de la réponse : {e.body}")
        
        # Gestion spécifique par code d'erreur
        if e.status == 401:
            logger.error("Jeton JWT invalide ou expiré")
        elif e.status == 403:
            logger.error("Autorisations insuffisantes")
        elif e.status == 404:
            logger.error("Ressource non trouvée")
        elif e.status >= 500:
            logger.error("Erreur interne du serveur")
        
        return None
    except Exception as e:
        logger.error(f"Erreur inattendue : {str(e)}")
        return None

# Exemple d'Utilisation
organizations = safe_api_call(org_api.list_user_organizations)
if organizations:
    print(f"Organisations obtenues : {len(organizations.data)}")
else:
    print("Impossible d'obtenir les organisations")
```

### 🔧 Configuration avancée

#### Client personnalisé avec Retry

```python
import time
from functools import wraps

def retry_on_failure(max_retries=3, delay=1):
    """Décorateur pour retenter les appels échoués"""
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            for attempt in range(max_retries):
                try:
                    return func(*args, **kwargs)
                except ApiException as e:
                    if e.status >= 500 and attempt < max_retries - 1:
                        time.sleep(delay * (2 ** attempt))  # Backoff exponentiel
                        continue
                    raise
            return None
        return wrapper
    return decorator

class RobustJoteluluClient(JoteluluClient):
    @retry_on_failure(max_retries=3)
    def get_organizations_with_retry(self):
        api = self.get_organizations_api()
        return api.list_user_organizations()
```

#### Configuration du timeout

```python
from openapi_client.configuration import Configuration
from openapi_client.api_client import ApiClient

# Configuration avec des timeouts personnalisés
configuration = Configuration(
    host="https://connect-eu1.jotelulu.com",
    access_token="your_token"
)

# Configurer les timeouts
api_client = ApiClient(configuration)
api_client.rest_client.pool_manager.connection_pool_kw['timeout'] = 30
```

***


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.plenit.com/fr/referencia/cliente-sdk/cliente-sdk-python.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
