Fix build issues - Spring Boot plugin, imports, and ENV default #116

Merged
hitanshu merged 18 commits from Dave/CFTunnels:ISSUE-114 into test 2026-04-18 16:16:05 +00:00
Showing only changes of commit df7ea9a2df - Show all commits

View File

@ -22,21 +22,60 @@ import java.util.NoSuchElementException;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
/**
* Service for interacting with the Cloudflare Tunnel API.
*
* <p>This service provides methods to manage Cloudflare Tunnels,
* including fetching tunnel configurations, creating/updating tunnels,
* and adding ingress mappings. It handles all communication with the
* Cloudflare API using the configured credentials.</p>
*
* <p><b>API Endpoints Used:</b></p>
* <ul>
* <li>GET /accounts/{accountId}/cfd_tunnel - List all tunnels</li>
* <li>GET /accounts/{accountId}/cfd_tunnel/{tunnelId}/configurations - Get tunnel config</li>
* <li>PUT /accounts/{accountId}/cfd_tunnel/{tunnelId}/configurations - Update tunnel config</li>
* </ul>
*
* @see CloudflareConfig
* @see Tunnel
* @see Ingress
*/
@Service @Service
public class CloudflareAPIService { public class CloudflareAPIService {
/**
* Configuration for Cloudflare API credentials and settings.
* Loaded from application.properties using the {@code cloudflare.*} prefix.
*/
@Autowired @Autowired
CloudflareConfig cloudflareConfig; CloudflareConfig cloudflareConfig;
/**
* Header provider for Cloudflare API authentication.
* Generates the X-Auth-Key and X-Auth-Email headers.
*/
@Autowired @Autowired
AuthKeyEmailHeader authKeyEmailHeader; AuthKeyEmailHeader authKeyEmailHeader;
/**
* HTTP client for making API requests.
*/
@Autowired @Autowired
RestTemplate restTemplate; RestTemplate restTemplate;
/**
* Repository for storing tunnel configurations locally.
*/
@Autowired @Autowired
TunnelRepository tunnelRepository; TunnelRepository tunnelRepository;
/**
* Fetches all Cloudflare tunnels from the API.
*
* @return Response containing the list of tunnels from Cloudflare
* @see TunnelsResponse
*/
public ResponseEntity<TunnelsResponse> getCloudflareTunnels() { public ResponseEntity<TunnelsResponse> getCloudflareTunnels() {
String url = "https://api.cloudflare.com/client/v4/accounts/" + cloudflareConfig.getAccountId() + "/cfd_tunnel"; String url = "https://api.cloudflare.com/client/v4/accounts/" + cloudflareConfig.getAccountId() + "/cfd_tunnel";
@ -46,9 +85,18 @@ public class CloudflareAPIService {
return responseEntity; return responseEntity;
} }
/**
* Fetches the configuration for a specific tunnel.
*
* @param tunnelId The Cloudflare tunnel ID (UUID string)
* @param restTemplate HTTP client to use for the request
* @param responseType Class to deserialize the response into
* @param <T> Response type
* @return Response containing the tunnel configuration
*/
public <T> ResponseEntity<T> getCloudflareTunnelConfigurations(String tunnelId, RestTemplate restTemplate, Class<T> responseType) { public <T> ResponseEntity<T> getCloudflareTunnelConfigurations(String tunnelId, RestTemplate restTemplate, Class<T> responseType) {
// * * Resource URL to hit get request at // Resource URL to hit get request at
String url = "https://api.cloudflare.com/client/v4/accounts/" + cloudflareConfig.getAccountId() + "/cfd_tunnel/" + tunnelId + "/configurations"; String url = "https://api.cloudflare.com/client/v4/accounts/" + cloudflareConfig.getAccountId() + "/cfd_tunnel/" + tunnelId + "/configurations";
HttpEntity<String> httpEntity = new HttpEntity<>("",authKeyEmailHeader.getHttpHeaders()); HttpEntity<String> httpEntity = new HttpEntity<>("",authKeyEmailHeader.getHttpHeaders());
@ -56,9 +104,22 @@ public class CloudflareAPIService {
return responseEntity; return responseEntity;
} }
/**
* Updates the configuration for a specific tunnel.
*
* <p>This method is used to add, modify, or remove ingress mappings
* by providing a complete configuration object.</p>
*
* @param tunnelId The Cloudflare tunnel ID (UUID string)
* @param restTemplate HTTP client to use for the request
* @param responseType Class to deserialize the response into
* @param config The new configuration to apply
* @param <T> Response type
* @return Response containing the updated tunnel configuration
*/
public <T> ResponseEntity<T> putCloudflareTunnelConfigurations(String tunnelId, RestTemplate restTemplate, Class<T> responseType, Config config) { public <T> ResponseEntity<T> putCloudflareTunnelConfigurations(String tunnelId, RestTemplate restTemplate, Class<T> responseType, Config config) {
// * * Resource URL to hit get request at // Resource URL to hit get request at
String url = "https://api.cloudflare.com/client/v4/accounts/" + cloudflareConfig.getAccountId() + "/cfd_tunnel/" + tunnelId + "/configurations"; String url = "https://api.cloudflare.com/client/v4/accounts/" + cloudflareConfig.getAccountId() + "/cfd_tunnel/" + tunnelId + "/configurations";
HttpHeaders httpHeaders = authKeyEmailHeader.getHttpHeaders(); HttpHeaders httpHeaders = authKeyEmailHeader.getHttpHeaders();
@ -68,10 +129,29 @@ public class CloudflareAPIService {
return responseEntity; return responseEntity;
} }
/**
* Converts a Cloudflare API tunnel result to a local Tunnel entity.
*
* @param tunnelResult The tunnel result from Cloudflare API
* @param env The environment name to associate
* @return New Tunnel entity instance
*/
private Tunnel getTunnelFromTunnelResponse(TunnelResult tunnelResult, String env){ private Tunnel getTunnelFromTunnelResponse(TunnelResult tunnelResult, String env){
return new Tunnel(UUID.fromString(tunnelResult.getId()), env, tunnelResult.getName()); return new Tunnel(UUID.fromString(tunnelResult.getId()), env, tunnelResult.getName());
} }
/**
* Creates or updates a tunnel's local configuration.
*
* <p>This method fetches the tunnel from Cloudflare API, validates it exists,
* and stores a local copy with the environment association.</p>
*
* @param tunnelId The Cloudflare tunnel ID
* @param environment Environment name (e.g., "production", "staging")
* @return The created or updated Tunnel entity
* @throws ExternalServiceException if Cloudflare API returns an error
* @throws NoSuchElementException if the tunnel doesn't exist in Cloudflare
*/
public Tunnel createOrUpdateTunnel(String tunnelId, String environment) throws ExternalServiceException, NoSuchElementException { public Tunnel createOrUpdateTunnel(String tunnelId, String environment) throws ExternalServiceException, NoSuchElementException {
ResponseEntity<TunnelsResponse> responseEntity = getCloudflareTunnels(); ResponseEntity<TunnelsResponse> responseEntity = getCloudflareTunnels();
@ -92,10 +172,25 @@ public class CloudflareAPIService {
return toBeConfigured; return toBeConfigured;
} }
/**
* Retrieves all tunnels that have been locally configured.
*
* @return List of locally configured tunnels
*/
public List<Tunnel> getAllConfiguredTunnels() { public List<Tunnel> getAllConfiguredTunnels() {
return tunnelRepository.findAll(); return tunnelRepository.findAll();
} }
/**
* Adds an ingress mapping to an existing tunnel.
*
* <p>The new ingress is inserted at the second-to-last position in the
* ingress list (Cloudflare requires a catch-all rule at the end).</p>
*
* @param tunnelId The Cloudflare tunnel ID
* @param ingress The ingress configuration to add
* @return Response with the updated tunnel configuration
*/
public ResponseEntity<TunnelResponse> addTunnelIngress(String tunnelId, Ingress ingress) { public ResponseEntity<TunnelResponse> addTunnelIngress(String tunnelId, Ingress ingress) {
ResponseEntity<TunnelResponse> currentConfig = getCloudflareTunnelConfigurations(tunnelId, restTemplate, TunnelResponse.class); ResponseEntity<TunnelResponse> currentConfig = getCloudflareTunnelConfigurations(tunnelId, restTemplate, TunnelResponse.class);