> ## Documentation Index
> Fetch the complete documentation index at: https://platform.docs.zenoo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Implementing Cloud Providers

> Guide for implementing custom cloud provider support for Azure, GCP, or other platforms

# Implementing Cloud Providers

Guide for implementing support for new cloud providers (Azure, GCP, or custom infrastructure).

## Overview

Adding a new cloud provider requires:

1. Implementing cloud-provider-api interfaces
2. Mapping provider exceptions to CloudProviderException
3. Creating Spring Boot autoconfiguration
4. Writing tests

## Reference Implementations

Before implementing a new provider, review existing implementations:

### Local Provider (Simple Reference)

**Module:** `cloud-provider-local`

The local provider is the **simplest complete implementation** and serves as an excellent reference:

**Advantages as a reference:**

* Single module (easier to understand)
* No external dependencies (focus on core interfaces)
* Simple storage (ConcurrentHashMap)
* Clear error handling patterns
* Well-commented code
* Complete test coverage

**Key classes to study:**

```
cloud-provider-local/
├── store/
│   ├── LocalComponentStore.java          # ComponentStore implementation
│   ├── LocalApiKeyStore.java             # ApiKeyStore implementation
│   └── LocalSharableStore.java           # SharableStore implementation
├── secret/
│   └── LocalApiKeySecretStorage.java     # ApiKeySecretStorage implementation
├── config/
│   ├── LocalComponentConfigStorage.java  # ComponentConfigStorage implementation
│   └── LocalComponentConfigReader.java   # Synchronous config reader
├── support/
│   └── LocalStoreSupport.java            # Base class with error handling
└── autoconfigure/
    ├── LocalCloudProviderAutoConfiguration.java
    ├── LocalProviderConfig.java
    └── SharableCleanupScheduler.java
```

**Example: Simple ComponentStore:**

```java theme={null}
@Service
public class LocalComponentStore extends LocalStoreSupport
                                 implements ComponentStore {

    private final ConcurrentHashMap<String, StringComponent> components =
        new ConcurrentHashMap<>();

    @Override
    public Mono<StringComponent> get(ComponentId id) {
        return wrapWithErrorHandling(
            Mono.fromCallable(() -> {
                ComponentId resolvedId = resolveLatestRevision(id);
                StringComponent component = components.get(toKey(resolvedId));
                if (component == null) {
                    throw new NoSuchElementException("Component not found: " + id);
                }
                return component;
            }),
            "get component",
            id.getName()
        );
    }

    // Error handling in base class (LocalStoreSupport)
    protected Throwable wrapException(Throwable throwable) {
        if (throwable instanceof NoSuchElementException) {
            return new StorageException(
                throwable.getMessage(),
                throwable,
                CloudProviderException.ErrorType.NOT_FOUND
            );
        }
        // ... other mappings
    }
}
```

**Study these patterns:**

1. **Error Handling** - `LocalStoreSupport.wrapWithErrorHandling()`
2. **Exception Mapping** - Java exceptions -> CloudProviderException
3. **Reactive Wrapping** - `Mono.fromCallable()` for synchronous operations
4. **LATEST Resolution** - `resolveLatestRevision()` pattern
5. **Auto-Configuration** - Conditional bean creation

### AWS Provider (Production Reference)

**Module:** `cloud-provider-aws` (4 submodules)

The AWS provider is a **production-ready implementation** showing advanced patterns:

**Advantages as a reference:**

* Real-world external service integration (DynamoDB, Secrets Manager)
* Advanced error handling and retries
* Multi-region support
* Metrics publishing (CloudWatch)
* Production-grade testing

**Module structure:**

```
cloud-provider-aws/
├── aws-stores/              # DynamoDB storage implementations
├── aws-secrets/             # Secrets Manager implementations
├── aws-metrics/             # CloudWatch metrics
└── aws-spring-boot-starter/ # Auto-configuration
```

**Study these patterns:**

1. **SDK Integration** - AWS SDK v2 async client usage
2. **Retry Logic** - Exponential backoff for transient errors
3. **Connection Pooling** - Managing client lifecycle
4. **Metric Publishing** - CloudWatch integration
5. **Multi-Module Structure** - When to split providers

[View AWS provider documentation](/technical-specification/hub-backend/cloud-providers/aws)

### Choosing a Reference

| Aspect                | Local Provider | AWS Provider                       |
| --------------------- | -------------- | ---------------------------------- |
| **Complexity**        | Simple         | Complex                            |
| **Lines of Code**     | \~1,500        | \~5,000                            |
| **External Deps**     | None           | AWS SDK, DynamoDB, Secrets Manager |
| **Module Structure**  | Single         | 4 submodules                       |
| **Best for Learning** | Core patterns  | Production patterns                |
| **Best for Starting** | Yes            | Use as second reference            |

**Recommendation:** Start with the local provider to understand core patterns, then review AWS provider for production considerations.

## Module Structure

Create a new module following the pattern:

```
cloud-provider-{name}/
├── {name}-stores/
│   └── src/main/java/com/zenoo/hub/cloudprovider/{name}/stores/
├── {name}-secrets/
│   └── src/main/java/com/zenoo/hub/cloudprovider/{name}/secrets/
├── {name}-metrics/
│   └── src/main/java/com/zenoo/hub/cloudprovider/{name}/metrics/
└── {name}-spring-boot-starter/
    └── src/main/java/com/zenoo/hub/cloudprovider/{name}/autoconfigure/
```

## Implementing Storage Interfaces

### ComponentStore Implementation

```java theme={null}
@Service
public class AzureComponentStore implements ComponentStore {

    private final CosmosClient cosmosClient;

    @Override
    public Mono<StringComponent> get(ComponentId id) {
        return Mono.defer(() -> {
            try {
                var response = cosmosClient
                    .getDatabase(databaseName)
                    .getContainer(containerName)
                    .readItem(id.getFullName(),
                             new PartitionKey(id.getName()),
                             ComponentRecord.class);
                return Mono.just(response.getItem().toStringComponent());
            } catch (CosmosException e) {
                return Mono.error(mapException(e));
            }
        });
    }

    private Throwable mapException(CosmosException e) {
        if (e.getStatusCode() == 404) {
            return new StorageException(
                "Component not found",
                e,
                CloudProviderException.ErrorType.NOT_FOUND
            );
        }
        return new StorageException(
            "Storage error",
            e,
            CloudProviderException.ErrorType.SERVICE_ERROR
        );
    }
}
```

### SharableStore Implementation

```java theme={null}
@Service
public class AzureSharableStore implements SharableStore {

    @Override
    public Mono<SharableRecord> get(String token) {
        // Implementation using Azure Cosmos DB or Table Storage
    }

    @Override
    public Mono<String> store(SharableRecord record) {
        // Implementation with TTL support
    }
}
```

## Implementing Configuration Interfaces

### ComponentConfigStorage Implementation

```java theme={null}
@Service
public class AzureComponentConfigStorage implements ComponentConfigStorage {

    private final SecretClient secretClient;

    @Override
    public Mono<String> get(ComponentConfigId configId) {
        return Mono.defer(() -> {
            try {
                KeyVaultSecret secret = secretClient.getSecret(
                    buildSecretName(configId)
                );
                return Mono.just(secret.getValue());
            } catch (ResourceNotFoundException e) {
                return Mono.empty();
            } catch (Exception e) {
                return Mono.error(mapException(e));
            }
        });
    }
}
```

## Spring Boot Autoconfiguration

### Main Configuration Class

```java theme={null}
@AutoConfiguration
@ConditionalOnClass(CosmosClient.class)
@ConditionalOnProperty(
    name = "hub.cloud.provider.type",
    havingValue = "azure"
)
@Import({
    AzureStoresAutoConfiguration.class,
    AzureSecretsAutoConfiguration.class
})
public class AzureCloudProviderAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public CosmosClient cosmosClient(AzureConfig config) {
        return new CosmosClientBuilder()
            .endpoint(config.getEndpoint())
            .key(config.getKey())
            .buildClient();
    }
}
```

### Register Autoconfiguration

Create `META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports`:

```
com.zenoo.hub.cloudprovider.azure.autoconfigure.AzureCloudProviderAutoConfiguration
```

## Configuration Properties

```java theme={null}
@Data
@Validated
@ConfigurationProperties(prefix = "hub.azure")
public class AzureConfig {
    @NotBlank
    private String endpoint;

    @NotBlank
    private String key;

    @NotBlank
    private String databaseName;
}
```

## Testing

### Unit Tests

```java theme={null}
@ExtendWith(MockitoExtension.class)
class AzureComponentStoreTest {

    @Mock
    private CosmosClient cosmosClient;

    private AzureComponentStore store;

    @Test
    void shouldGetComponent() {
        // Test implementation
    }
}
```

### Integration Tests

Use Test Containers or Azure emulator for integration tests.

## Example: Azure Provider Structure

```java theme={null}
// Configuration
@ConfigurationProperties("hub.azure")
public class AzureConfig {
    String endpoint;
    String key;
}

// Component Store
@Service
public class AzureComponentStore implements ComponentStore {
    // Cosmos DB implementation
}

// Secrets Management
@Service
public class AzureKeyVaultStorage implements ApiKeySecretStorage {
    // Key Vault implementation
}

// Autoconfiguration
@AutoConfiguration
@ConditionalOnProperty(name = "hub.cloud.provider.type", havingValue = "azure")
public class AzureCloudProviderAutoConfiguration {
    // Bean definitions
}
```

## See Also

* [Cloud Provider Architecture](/technical-specification/hub-backend/cloud-providers/architecture)
* [AWS Provider Implementation](/technical-specification/hub-backend/cloud-providers/aws)
* [Configuration Reference](/technical-specification/hub-backend/cloud-providers/configuration-reference)
