diff --git a/pom.xml b/pom.xml index ae4da5d3..4c9d48c9 100644 --- a/pom.xml +++ b/pom.xml @@ -43,6 +43,8 @@ 33.4.8-jre 1.21.2 3.50.3.0 + + true 4.6 3.6.0 @@ -420,6 +422,12 @@ com.fasterxml.jackson.dataformat jackson-dataformat-csv + + + org.openapitools + jackson-databind-nullable + 0.2.6 + org.projectlombok lombok @@ -503,6 +511,22 @@ + + org.apache.maven.plugins + maven-surefire-plugin + + + + ${docker.host} + + + false + + + com.mycila license-maven-plugin @@ -519,6 +543,7 @@ + true
LICENSE_HEADER
@@ -579,6 +604,31 @@ + + windows + + + windows + + + + + npipe:////./pipe/docker_engine + + + + non-windows + + + !windows + + + + + ${env.DOCKER_HOST} + + owasp-dependency-check diff --git a/src/main/java/eu/openanalytics/containerproxy/auth/AuthenticationBackendFactory.java b/src/main/java/eu/openanalytics/containerproxy/auth/AuthenticationBackendFactory.java index 45a229a8..38cd3069 100644 --- a/src/main/java/eu/openanalytics/containerproxy/auth/AuthenticationBackendFactory.java +++ b/src/main/java/eu/openanalytics/containerproxy/auth/AuthenticationBackendFactory.java @@ -26,6 +26,7 @@ import eu.openanalytics.containerproxy.auth.impl.OpenIDAuthenticationBackend; import eu.openanalytics.containerproxy.auth.impl.SAMLAuthenticationBackend; import eu.openanalytics.containerproxy.auth.impl.SimpleAuthenticationBackend; +import eu.openanalytics.containerproxy.auth.impl.SpcsAuthenticationBackend; import eu.openanalytics.containerproxy.auth.impl.WebServiceAuthenticationBackend; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.AbstractFactoryBean; @@ -74,6 +75,7 @@ protected IAuthenticationBackend createInstance() { case OpenIDAuthenticationBackend.NAME -> backend = new OpenIDAuthenticationBackend(); case WebServiceAuthenticationBackend.NAME -> backend = new WebServiceAuthenticationBackend(environment); case CustomHeaderAuthenticationBackend.NAME -> backend = new CustomHeaderAuthenticationBackend(environment, applicationEventPublisher); + case SpcsAuthenticationBackend.NAME -> backend = new SpcsAuthenticationBackend(environment, applicationEventPublisher); case SAMLAuthenticationBackend.NAME -> { return samlBackend; } diff --git a/src/main/java/eu/openanalytics/containerproxy/auth/impl/SpcsAuthenticationBackend.java b/src/main/java/eu/openanalytics/containerproxy/auth/impl/SpcsAuthenticationBackend.java new file mode 100644 index 00000000..d0bfeb76 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/auth/impl/SpcsAuthenticationBackend.java @@ -0,0 +1,130 @@ +/* + * ContainerProxy + * + * Copyright (C) 2016-2025 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.auth.impl; + +import eu.openanalytics.containerproxy.auth.IAuthenticationBackend; +import eu.openanalytics.containerproxy.auth.impl.spcs.SpcsAuthenticationFilter; +import eu.openanalytics.containerproxy.auth.impl.spcs.SpcsAuthenticationProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.core.env.Environment; +import org.springframework.security.authentication.ProviderManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.AnonymousAuthenticationFilter; + +import java.util.Map; + +/** + * Authentication backend for SPCS authentication. + * + * This backend authenticates users based on HTTP headers that Snowflake forwards to services + * running inside SPCS containers via ingress. + * + * When a service is configured with executeAsCaller: true in its service specification, + * Snowflake inserts the following headers in every incoming request: + * - Sf-Context-Current-User: The username of the calling user + * - Sf-Context-Current-User-Token: A token representing the calling user's context + * + * The Sf-Context-Current-User-Token is automatically passed to child container services as + * an HTTP header (Sf-Context-Current-User-Token) via ProxyMappingManager, allowing child + * containers to access the caller's rights token for connecting to Snowflake. + * + * Reference: https://docs.snowflake.com/en/developer-guide/snowpark-container-services/additional-considerations-services-jobs#configuring-caller-s-rights-for-your-service + * + * This backend can only be used when running inside SPCS (detected by + * SNOWFLAKE_SERVICE_NAME environment variable). + * + * Note: ShinyProxy's SPCS backend automatically configures executeAsCaller: true for all services + * (see SpcsBackend.buildServiceSpecYaml). + * + * Configuration: + * proxy.authentication: spcs + */ +public class SpcsAuthenticationBackend implements IAuthenticationBackend { + + private static final Logger logger = LoggerFactory.getLogger(SpcsAuthenticationBackend.class); + + public static final String NAME = "spcs"; + + private final SpcsAuthenticationFilter filter; + + public SpcsAuthenticationBackend(Environment environment, ApplicationEventPublisher applicationEventPublisher) { + // Verify we're running inside SPCS + String snowflakeServiceName = environment.getProperty("SNOWFLAKE_SERVICE_NAME"); + boolean runningInsideSpcs = snowflakeServiceName != null && !snowflakeServiceName.isEmpty(); + + if (!runningInsideSpcs) { + throw new IllegalStateException( + "SpcsAuthenticationBackend can only be used when running inside SPCS. " + + "SNOWFLAKE_SERVICE_NAME environment variable not found."); + } + + logger.info("Initializing SPCS authentication backend (SNOWFLAKE_SERVICE_NAME: {})", snowflakeServiceName); + + // Create authentication provider + SpcsAuthenticationProvider provider = new SpcsAuthenticationProvider(environment); + ProviderManager providerManager = new ProviderManager(provider); + filter = new SpcsAuthenticationFilter(providerManager, applicationEventPublisher); + } + + @Override + public String getName() { + return NAME; + } + + @Override + public boolean hasAuthorization() { + return true; + } + + @Override + public void configureHttpSecurity(HttpSecurity http) throws Exception { + http.formLogin(AbstractHttpConfigurer::disable); + + http.addFilterBefore(filter, AnonymousAuthenticationFilter.class) + .exceptionHandling(e -> { + // Empty configuration - the filter handles all authentication exceptions directly by returning + // error responses and stopping the filter chain. This ensures no default Spring Security + // exception handling (like redirects) occurs if any AuthenticationException somehow escapes. + }); + } + + @Override + public void configureAuthenticationManagerBuilder(AuthenticationManagerBuilder auth) throws Exception { + // Nothing to do - authentication is handled by the filter + } + + @Override + public void customizeContainerEnv(Authentication user, Map env) { + // SPCS user token is passed as HTTP header per request, not as environment variable + // See ProxyMappingManager.dispatchAsync() for header forwarding logic + } + + @Override + public String getLogoutSuccessURL() { + return "/logout-success"; + } + +} diff --git a/src/main/java/eu/openanalytics/containerproxy/auth/impl/spcs/SpcsAuthenticationException.java b/src/main/java/eu/openanalytics/containerproxy/auth/impl/spcs/SpcsAuthenticationException.java new file mode 100644 index 00000000..1ee85d3e --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/auth/impl/spcs/SpcsAuthenticationException.java @@ -0,0 +1,31 @@ +/* + * ContainerProxy + * + * Copyright (C) 2016-2025 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.auth.impl.spcs; + +import org.springframework.security.access.AccessDeniedException; + +public class SpcsAuthenticationException extends AccessDeniedException { + + public SpcsAuthenticationException(String explanation) { + super(explanation); + } + +} diff --git a/src/main/java/eu/openanalytics/containerproxy/auth/impl/spcs/SpcsAuthenticationFilter.java b/src/main/java/eu/openanalytics/containerproxy/auth/impl/spcs/SpcsAuthenticationFilter.java new file mode 100644 index 00000000..f6dfbfa9 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/auth/impl/spcs/SpcsAuthenticationFilter.java @@ -0,0 +1,163 @@ +/* + * ContainerProxy + * + * Copyright (C) 2016-2025 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.auth.impl.spcs; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.event.AuthenticationSuccessEvent; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.security.web.util.matcher.NegatedRequestMatcher; +import org.springframework.security.web.util.matcher.OrRequestMatcher; +import org.springframework.security.web.util.matcher.RequestMatcher; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.annotation.Nonnull; +import java.io.IOException; + +/** + * Authentication filter for SPCS authentication. + * Reads the Snowflake username from the Sf-Context-Current-User HTTP header + * that Snowflake inserts when executeAsCaller: true is configured. + * This filter only works when running inside Snowflake SPCS containers. + */ +public class SpcsAuthenticationFilter extends OncePerRequestFilter { + + private static final Logger logger = LoggerFactory.getLogger(SpcsAuthenticationFilter.class); + + // Prevent re-authentication on logout-success page and static resources + private static final RequestMatcher REQUEST_MATCHER = new NegatedRequestMatcher(new OrRequestMatcher( + new AntPathRequestMatcher("/logout-success"), + new AntPathRequestMatcher("/webjars/**"), + new AntPathRequestMatcher("/css/**") + )); + + private static final String SPCS_INGRESS_USERNAME_HEADER = "Sf-Context-Current-User"; + private static final String SPCS_INGRESS_USERTOKEN_HEADER = "Sf-Context-Current-User-Token"; + + private final AuthenticationManager authenticationManager; + private final ApplicationEventPublisher eventPublisher; + + public SpcsAuthenticationFilter( + AuthenticationManager authenticationManager, + ApplicationEventPublisher eventPublisher) { + this.authenticationManager = authenticationManager; + this.eventPublisher = eventPublisher; + } + + @Override + protected void doFilterInternal(@Nonnull HttpServletRequest request, + @Nonnull HttpServletResponse response, + @Nonnull FilterChain chain) throws ServletException, IOException { + + if (!REQUEST_MATCHER.matches(request)) { + chain.doFilter(request, response); + return; + } + + try { + // Get the username from Sf-Context-Current-User header (always present when running inside SPCS) + String spcsIngressUserName = request.getHeader(SPCS_INGRESS_USERNAME_HEADER); + + // Get the user token (Sf-Context-Current-User-Token) if available (only when executeAsCaller=true) + String spcsIngressUserToken = request.getHeader(SPCS_INGRESS_USERTOKEN_HEADER); + + if (spcsIngressUserName == null || spcsIngressUserName.isBlank()) { + // Header is required - SPCS always adds this header to all requests when running inside SPCS + // Fail authentication if header is missing + throw new SpcsAuthenticationException("Required header " + SPCS_INGRESS_USERNAME_HEADER + " not found in request"); + } + + // Check if already authenticated with SPCS + // This validation prevents session hijacking and ensures consistency: + // - Security: Prevents an attacker from switching users mid-session by manipulating headers + // - Performance: Avoids re-authenticating on every request once already authenticated + // - Consistency: Ensures the session user matches the current request headers + Authentication existingAuthentication = SecurityContextHolder.getContext().getAuthentication(); + if (existingAuthentication instanceof SpcsAuthenticationToken) { + // Compare the username in the current request header with the username from the existing session + // If they don't match, throw an exception (potential session hijacking or user switch) + if (!existingAuthentication.getPrincipal().equals(spcsIngressUserName)) { + throw new SpcsAuthenticationException( + String.format("Username in header does not match existing session '%s'", + existingAuthentication.getPrincipal())); + } else { + // They match - user is already authenticated with the same identity + // Continue the request without re-authenticating (performance optimization) + chain.doFilter(request, response); + return; + } + } + + // Create authentication token with username and token (token may be null) + SpcsAuthenticationToken authRequest = new SpcsAuthenticationToken( + spcsIngressUserName, + spcsIngressUserToken, + new WebAuthenticationDetailsSource().buildDetails(request) + ); + + // Authenticate + Authentication authResult = authenticationManager.authenticate(authRequest); + if (authResult == null) { + throw new SpcsAuthenticationException("No authentication result"); + } + + // Set in security context + SecurityContextHolder.getContext().setAuthentication(authResult); + eventPublisher.publishEvent(new AuthenticationSuccessEvent(authResult)); + logger.debug("Successfully authenticated SPCS user: {}", spcsIngressUserName); + + } catch (SpcsAuthenticationException e) { + logger.warn("SPCS authentication failed: {}", e.getMessage()); + SecurityContextHolder.clearContext(); + // Don't continue the filter chain - fail the request + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + response.getWriter().write("SPCS authentication failed: " + e.getMessage()); + return; + } catch (AuthenticationException e) { + logger.warn("SPCS authentication failed", e); + SecurityContextHolder.clearContext(); + // Don't continue the filter chain - fail the request + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + response.getWriter().write("SPCS authentication failed: " + e.getMessage()); + return; + } catch (Exception e) { + logger.warn("Unexpected error during SPCS authentication", e); + SecurityContextHolder.clearContext(); + // Don't continue the filter chain - fail the request + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + response.getWriter().write("Unexpected error during SPCS authentication"); + return; + } + + chain.doFilter(request, response); + } + +} diff --git a/src/main/java/eu/openanalytics/containerproxy/auth/impl/spcs/SpcsAuthenticationProvider.java b/src/main/java/eu/openanalytics/containerproxy/auth/impl/spcs/SpcsAuthenticationProvider.java new file mode 100644 index 00000000..0b956c6d --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/auth/impl/spcs/SpcsAuthenticationProvider.java @@ -0,0 +1,260 @@ +/* + * ContainerProxy + * + * Copyright (C) 2016-2025 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.auth.impl.spcs; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import eu.openanalytics.containerproxy.backend.spcs.client.ApiClient; +import org.springframework.web.reactive.function.client.WebClientResponseException; +import eu.openanalytics.containerproxy.backend.spcs.client.api.StatementsApi; +import eu.openanalytics.containerproxy.backend.spcs.client.auth.HttpBearerAuth; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ResultSet; +import eu.openanalytics.containerproxy.backend.spcs.client.model.SubmitStatementRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class SpcsAuthenticationProvider implements AuthenticationProvider { + + private static final Logger logger = LoggerFactory.getLogger(SpcsAuthenticationProvider.class); + private static final String USER_AGENT = "ContainerProxy/1.2.2"; + + private final ObjectMapper jsonMapper = new ObjectMapper(); + + private final Environment environment; + private final String computeWarehouse; + + public SpcsAuthenticationProvider(Environment environment) { + this.environment = environment; + + // Load optional compute warehouse for SPCS authentication role retrieval + this.computeWarehouse = environment.getProperty("proxy.spcs.compute-warehouse"); + if (computeWarehouse != null && !computeWarehouse.isEmpty()) { + logger.debug("SPCS compute warehouse configured for role retrieval: {}", computeWarehouse); + } + } + + @Override + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + SpcsAuthenticationToken authRequest = (SpcsAuthenticationToken) authentication; + + if (authRequest.isValid()) { + String spcsIngressUserToken = authRequest.getCredentials() != null ? authRequest.getCredentials().toString() : null; + + Collection authorities = new ArrayList<>(); + + // Retrieve all available roles for the user using CURRENT_AVAILABLE_ROLES() + // This stores roles with the principal, allowing authorization logic to check both: + // - admin-groups: via UserService.isAdmin() which uses isMember() to check authorities + // - access-groups: via AccessControlEvaluationService which checks authorities against proxy spec access-groups + if (computeWarehouse == null || computeWarehouse.isEmpty()) { + logger.debug("Compute warehouse not configured (proxy.spcs.compute-warehouse), skipping role retrieval"); + } else if (spcsIngressUserToken == null || spcsIngressUserToken.isBlank()) { + logger.debug("User token not available (executeAsCaller may not be enabled), skipping role retrieval"); + } else { + // All conditions met: retrieve available roles + // Requires: user token and compute warehouse + logger.debug("User token available, retrieving available roles using warehouse {}", computeWarehouse); + List availableRoles = getAvailableRoles(spcsIngressUserToken); + logger.debug("User has {} available roles", availableRoles.size()); + for (String role : availableRoles) { + // Format: ROLE_ROLENAME (UserService.getGroups() strips the "ROLE_" prefix) + String roleName = role.startsWith("ROLE_") ? role : "ROLE_" + role; + authorities.add(new SimpleGrantedAuthority(roleName)); + } + } + + return new SpcsAuthenticationToken( + authRequest.getPrincipal().toString(), + spcsIngressUserToken, + authorities, + authRequest.getDetails(), + true + ); + } + + throw new SpcsAuthenticationException("Invalid Snowflake username"); + } + + /** + * Retrieves all available roles for the user using CURRENT_AVAILABLE_ROLES(). + * Uses the Sf-Context-Current-User-Token to authenticate as the caller. + * + * @param userToken The Sf-Context-Current-User-Token + * @return List of role names available to the user (may be empty) + */ + private List getAvailableRoles(String userToken) { + List availableRoles = new ArrayList<>(); + + try { + // Get account URL from environment + String accountUrl = getAccountUrl(); + if (accountUrl == null) { + logger.warn("Cannot retrieve available roles: account URL not available"); + return availableRoles; + } + + // Create a new API client instance (not shared) with user token as bearer token + // Use KeyPair authentication scheme (HttpBearerAuth) - works for OAuth tokens from SPCS ingress + ApiClient apiClient = new ApiClient(); + apiClient.setBasePath(accountUrl); + + HttpBearerAuth bearerAuth = (HttpBearerAuth) apiClient.getAuthentication("KeyPair"); + + // SPCS authentication requires combined token format: . + // Read service OAuth token from file and combine with user token + String serviceToken = readSpcsSessionTokenFromFile(); + if (serviceToken == null || serviceToken.isEmpty()) { + logger.warn("Service OAuth token not available from file for role retrieval"); + return availableRoles; + } + + // Format: . + String combinedToken = serviceToken + "." + userToken; + bearerAuth.setBearerToken(combinedToken); + + // Using SQL statement endpoint to query CURRENT_AVAILABLE_ROLES() + StatementsApi statementsApi = new StatementsApi(apiClient); + + // Query CURRENT_AVAILABLE_ROLES() which returns a JSON array of role names + String sql = "SELECT CURRENT_AVAILABLE_ROLES() AS available_roles"; + + // Prepare request + SubmitStatementRequest request = new SubmitStatementRequest(); + request.setStatement(sql); + // Set warehouse for SQL execution + request.setWarehouse(computeWarehouse.toUpperCase()); + + try { + ResultSet result = statementsApi.submitStatement( + USER_AGENT, + request, + null, // requestId + false, // async + false, // nullable + null, // accept + "OAUTH" // xSnowflakeAuthorizationTokenType: OAuth token from SPCS ingress + ).block(); + + // Parse result: CURRENT_AVAILABLE_ROLES() returns a JSON array string + // ResultSet.data is List>, first row, first column contains the JSON array + if (result.getData() != null && !result.getData().isEmpty()) { + List firstRow = result.getData().get(0); + if (firstRow != null && !firstRow.isEmpty()) { + String jsonArrayString = firstRow.get(0); + if (jsonArrayString != null && !jsonArrayString.isEmpty()) { + // Parse JSON array: ["ROLE1", "ROLE2", "ROLE3"] + List roles = jsonMapper.readValue(jsonArrayString, new TypeReference>() {}); + if (roles != null) { + for (String role : roles) { + if (role != null && !role.isEmpty()) { + availableRoles.add(role.toUpperCase()); + } + } + logger.debug("Retrieved {} available roles from CURRENT_AVAILABLE_ROLES()", availableRoles.size()); + } + } + } + } + } catch (WebClientResponseException e) { + // Log error details: exception includes message and stack trace + logger.warn("Failed to retrieve available roles (user will not have role-based privileges): code={}", + e.getStatusCode().value(), e); + // Return empty roles on failure (no fallback) + return availableRoles; + } catch (com.fasterxml.jackson.core.JsonProcessingException e) { + logger.warn("Failed to parse available roles JSON (user will not have role-based privileges): {}", + e.getMessage(), e); + // Return empty roles on JSON parsing failure + return availableRoles; + } + } catch (Exception e) { + logger.error("Error retrieving available roles: {}", e.getMessage(), e); + // Return empty roles on exception (no fallback) + return availableRoles; + } + + return availableRoles; + } + + /** + * Reads the SPCS session token from the standard file location if available. + * @return The token string or null if not available. + */ + private String readSpcsSessionTokenFromFile() { + try { + Path tokenPath = Paths.get("/snowflake/session/token"); + if (Files.exists(tokenPath) && Files.isRegularFile(tokenPath)) { + String token = Files.readString(tokenPath).trim(); + if (!token.isEmpty()) { + return token; + } else { + logger.warn("SPCS session token file exists but is empty: {}", tokenPath); + } + } + } catch (Exception ex) { + logger.warn("Error reading SPCS session token from file: {}", ex.getMessage()); + } + return null; + } + + /** + * Gets the Snowflake account URL from environment variables. + * + * @return Account URL or null if not available + */ + private String getAccountUrl() { + // Check SNOWFLAKE_HOST first (preferred when running inside SPCS) + String snowflakeHost = environment.getProperty("SNOWFLAKE_HOST"); + if (snowflakeHost != null && !snowflakeHost.isEmpty()) { + if (snowflakeHost.startsWith("https://") || snowflakeHost.startsWith("http://")) { + return snowflakeHost; + } else { + return "https://" + snowflakeHost; + } + } + + // Fall back to constructing from SNOWFLAKE_ACCOUNT + String snowflakeAccount = environment.getProperty("SNOWFLAKE_ACCOUNT"); + if (snowflakeAccount != null && !snowflakeAccount.isEmpty()) { + return String.format("https://%s.snowflakecomputing.com", snowflakeAccount); + } + + return null; + } + + @Override + public boolean supports(Class authentication) { + return SpcsAuthenticationToken.class.isAssignableFrom(authentication); + } + +} diff --git a/src/main/java/eu/openanalytics/containerproxy/auth/impl/spcs/SpcsAuthenticationToken.java b/src/main/java/eu/openanalytics/containerproxy/auth/impl/spcs/SpcsAuthenticationToken.java new file mode 100644 index 00000000..c0cb5b49 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/auth/impl/spcs/SpcsAuthenticationToken.java @@ -0,0 +1,82 @@ +/* + * ContainerProxy + * + * Copyright (C) 2016-2025 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.auth.impl.spcs; + +import org.springframework.security.authentication.AbstractAuthenticationToken; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.web.authentication.WebAuthenticationDetails; + +import java.util.Collection; + +public class SpcsAuthenticationToken extends AbstractAuthenticationToken { + + private final String spcsIngressUserName; // Sf-Context-Current-User header value + private final String spcsIngressUserToken; // Sf-Context-Current-User-Token header value + private final WebAuthenticationDetails details; + + public SpcsAuthenticationToken(String spcsIngressUserName, String spcsIngressUserToken, WebAuthenticationDetails details) { + super(null); + this.spcsIngressUserName = spcsIngressUserName; + this.spcsIngressUserToken = spcsIngressUserToken; + this.details = details; + super.setAuthenticated(false); + } + + public SpcsAuthenticationToken(String spcsIngressUserName, String spcsIngressUserToken, Collection authorities, WebAuthenticationDetails details, boolean isAuthenticated) { + super(authorities); + this.spcsIngressUserName = spcsIngressUserName; + this.spcsIngressUserToken = spcsIngressUserToken; + this.details = details; + super.setAuthenticated(isAuthenticated); + } + + public boolean isValid() { + return spcsIngressUserName != null && !spcsIngressUserName.isBlank(); + } + + @Override + public Object getPrincipal() { + return spcsIngressUserName; + } + + @Override + public Object getCredentials() { + // Return the SPCS ingress user token as the credential (proof of identity) + // This follows Spring Security conventions where credentials represent authentication proof + return spcsIngressUserToken; + } + + @Override + public String getName() { + return this.spcsIngressUserName; + } + + @Override + public WebAuthenticationDetails getDetails() { + return this.details; + } + + @Override + public void setAuthenticated(boolean isAuthenticated) { + throw new SpcsAuthenticationException("Cannot change authenticated after initialization!"); + } + +} diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsBackend.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsBackend.java new file mode 100644 index 00000000..4ae21296 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsBackend.java @@ -0,0 +1,2502 @@ +/* + * ContainerProxy + * + * Copyright (C) 2016-2025 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.backend.spcs; + +import eu.openanalytics.containerproxy.backend.spcs.client.ApiClient; +import org.springframework.web.reactive.function.client.WebClientResponseException; +import eu.openanalytics.containerproxy.backend.spcs.client.auth.HttpBearerAuth; +import eu.openanalytics.containerproxy.backend.spcs.client.api.ServiceApi; +import eu.openanalytics.containerproxy.backend.spcs.client.api.StatementsApi; +import eu.openanalytics.containerproxy.backend.spcs.client.model.Service; +import eu.openanalytics.containerproxy.backend.spcs.client.model.SubmitStatementRequest; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceContainer; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceEndpoint; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceSpec; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceSpecInlineText; +import com.fasterxml.jackson.core.type.TypeReference; +import eu.openanalytics.containerproxy.ContainerFailedToStartException; +import eu.openanalytics.containerproxy.ContainerProxyException; +import eu.openanalytics.containerproxy.ProxyFailedToStartException; +import eu.openanalytics.containerproxy.backend.AbstractContainerBackend; +import eu.openanalytics.containerproxy.event.NewProxyEvent; +import eu.openanalytics.containerproxy.model.runtime.Container; +import eu.openanalytics.containerproxy.model.runtime.ExistingContainerInfo; +import eu.openanalytics.containerproxy.model.runtime.PortMappings; +import eu.openanalytics.containerproxy.model.runtime.Proxy; +import eu.openanalytics.containerproxy.model.runtime.ProxyStatus; +import eu.openanalytics.containerproxy.model.runtime.ProxyStartupLog; +import eu.openanalytics.containerproxy.model.runtime.runtimevalues.BackendContainerName; +import eu.openanalytics.containerproxy.model.runtime.runtimevalues.BackendContainerNameKey; +import eu.openanalytics.containerproxy.model.runtime.runtimevalues.ContainerImageKey; +import eu.openanalytics.containerproxy.model.runtime.runtimevalues.ContainerIndexKey; +import eu.openanalytics.containerproxy.model.runtime.runtimevalues.HttpHeaders; +import eu.openanalytics.containerproxy.model.runtime.runtimevalues.PortMappingsKey; +import eu.openanalytics.containerproxy.model.runtime.runtimevalues.HttpHeadersKey; +import eu.openanalytics.containerproxy.model.runtime.runtimevalues.InstanceIdKey; +import eu.openanalytics.containerproxy.model.runtime.runtimevalues.ProxyIdKey; +import eu.openanalytics.containerproxy.model.runtime.runtimevalues.ProxySpecIdKey; +import eu.openanalytics.containerproxy.model.runtime.runtimevalues.RealmIdKey; +import eu.openanalytics.containerproxy.model.runtime.runtimevalues.UserIdKey; +import eu.openanalytics.containerproxy.model.runtime.runtimevalues.RuntimeValue; +import eu.openanalytics.containerproxy.model.runtime.runtimevalues.RuntimeValueKey; +import eu.openanalytics.containerproxy.model.runtime.runtimevalues.RuntimeValueKeyRegistry; +import eu.openanalytics.containerproxy.model.spec.ContainerSpec; +import eu.openanalytics.containerproxy.model.spec.ProxySpec; +import eu.openanalytics.containerproxy.spec.IProxySpecProvider; +import eu.openanalytics.containerproxy.util.Retrying; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Component; +import eu.openanalytics.containerproxy.auth.impl.spcs.SpcsAuthenticationToken; + +import javax.annotation.PostConstruct; +import javax.inject.Inject; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.net.URI; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.function.Supplier; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator; + +@Component +@ConditionalOnProperty(name = "proxy.container-backend", havingValue = "spcs") +public class SpcsBackend extends AbstractContainerBackend { + + private static final String PROPERTY_PREFIX = "proxy.spcs."; + private static final String PROPERTY_ACCOUNT_IDENTIFIER = "account-identifier"; + private static final String PROPERTY_USERNAME = "username"; + private static final String PROPERTY_PROGRAMMATIC_ACCESS_TOKEN = "programmatic-access-token"; + private static final String PROPERTY_PRIVATE_RSA_KEY_PATH = "private-rsa-key-path"; + private static final String PROPERTY_DATABASE = "database"; + private static final String PROPERTY_SCHEMA = "schema"; + private static final String PROPERTY_COMPUTE_POOL = "compute-pool"; + private static final String PROPERTY_COMPUTE_WAREHOUSE = "compute-warehouse"; + private static final String PROPERTY_SERVICE_WAIT_TIME = "service-wait-time"; + private static final String PROPERTY_USE_ROLE = "use-role"; + + private ServiceApi snowflakeServiceAPI; + private StatementsApi snowflakeStatementsAPI; + private ApiClient snowflakeAPIClient; + private String snowflakeTokenType; // Token type for API calls (KEYPAIR_JWT, OAUTH, or PROGRAMMATIC_ACCESS_TOKEN) + private int serviceWaitTime; + + // YAML mapper for service spec serialization/deserialization + private final ObjectMapper yamlMapper = new ObjectMapper(YAMLFactory.builder() + .disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER) + .enable(YAMLGenerator.Feature.MINIMIZE_QUOTES) + .build()); + + // JSON mapper for comment metadata serialization/deserialization + private final ObjectMapper jsonMapper = new ObjectMapper(); + + private String database; + private String schema; + private String computePool; + private String accountUrl; + private String accountIdentifier; // Account identifier (e.g., "ORG-ACCOUNT" or "ACCOUNT") - stored separately from URL + private String username; + private AuthMethod authMethod; + private SpcsKeypairAuth keypairAuth; // For keypair authentication + private Supplier jwtTokenSupplier; // Supplier to generate/regenerate JWT tokens for keypair auth + + private static final Path SPCS_SESSION_TOKEN_PATH = Paths.get("/snowflake/session/token"); + + private enum AuthMethod { + SPCS_SESSION_TOKEN, // Running inside SPCS, token from /snowflake/session/token + KEYPAIR, // Username + private RSA key + PAT // Username + PAT token + } + + @Inject + private IProxySpecProvider proxySpecProvider; + + @Override + @PostConstruct + public void initialize() { + super.initialize(); + + // Detect if running inside SPCS by checking SNOWFLAKE_SERVICE_NAME environment variable + String snowflakeServiceName = environment.getProperty("SNOWFLAKE_SERVICE_NAME"); + boolean runningInsideSpcs = snowflakeServiceName != null && !snowflakeServiceName.isEmpty(); + + if (runningInsideSpcs) { + loadConfigurationFromEnvironment(); + setupSpcsSessionTokenAuth(); + } else { + loadConfigurationFromProperties(); + setupExternalAuth(); + } + + serviceWaitTime = environment.getProperty(PROPERTY_PREFIX + PROPERTY_SERVICE_WAIT_TIME, Integer.class, 180000); + + initializeSnowflakeAPIClient(); + + // Validate specs (log warnings only - actual validation happens when starting proxy) + for (ProxySpec spec : proxySpecProvider.getSpecs()) { + ContainerSpec containerSpec = spec.getContainerSpecs().get(0); + if (!containerSpec.getImage().isOriginalValuePresent()) { + log.warn("Spec with id '{}' has no 'container-image' configured, this is required for running on Snowflake SPCS. Proxy will fail to start if this field is missing.", spec.getId()); + } + if (!containerSpec.getMemoryRequest().isOriginalValuePresent()) { + log.warn("Spec with id '{}' has no 'container-memory-request' configured, this is required for running on Snowflake SPCS. Proxy will fail to start if this field is missing.", spec.getId()); + } + if (!containerSpec.getCpuRequest().isOriginalValuePresent()) { + log.warn("Spec with id '{}' has no 'container-cpu-request' configured, this is required for running on Snowflake SPCS. Proxy will fail to start if this field is missing.", spec.getId()); + } + if (containerSpec.getMemoryLimit().isOriginalValuePresent()) { + log.warn("Spec with id '{}' has 'memory-limit' configured, this is not supported by Snowflake SPCS and will be ignored.", spec.getId()); + } + if (containerSpec.getCpuLimit().isOriginalValuePresent()) { + log.warn("Spec with id '{}' has 'cpu-limit' configured, this is not supported by Snowflake SPCS and will be ignored.", spec.getId()); + } + if (containerSpec.isPrivileged()) { + log.warn("Spec with id '{}' has 'privileged: true' configured, this is not supported by Snowflake SPCS and will be ignored.", spec.getId()); + } + + // Validate that volume mounts reference volumes defined in spec's spcs.volumes + SpcsSpecExtension specExtension = spec.getSpecExtension(SpcsSpecExtension.class); + if (specExtension != null && containerSpec.getVolumes().isOriginalValuePresent() && containerSpec.getVolumes().getOriginalValue() != null && !containerSpec.getVolumes().getOriginalValue().isEmpty()) { + java.util.Set definedVolumeNames = new java.util.HashSet<>(); + if (specExtension.getSpcsVolumes() != null) { + for (SpcsVolume volume : specExtension.getSpcsVolumes()) { + if (volume != null && volume.getName() != null) { + definedVolumeNames.add(volume.getName()); + } + } + } + for (String volumeMountString : containerSpec.getVolumes().getOriginalValue()) { + int colonIndex = volumeMountString.indexOf(':'); + if (colonIndex > 0) { + String volumeName = volumeMountString.substring(0, colonIndex).trim(); + if (!volumeName.isEmpty() && !definedVolumeNames.contains(volumeName)) { + throw new IllegalStateException(String.format("Error in configuration of specs: spec with id '%s' references volume '%s' in container-volumes which is not defined in spec's spcs.volumes", spec.getId(), volumeName)); + } + } + } + } + } + } + + + /** + * Loads configuration from Snowflake environment variables (when running inside SPCS). + */ + private void loadConfigurationFromEnvironment() { + log.info("Detected running inside SPCS (SNOWFLAKE_SERVICE_NAME: {})", environment.getProperty("SNOWFLAKE_SERVICE_NAME")); + + // Load Snowflake environment variables + String snowflakeHost = environment.getProperty("SNOWFLAKE_HOST"); + String snowflakeAccount = environment.getProperty("SNOWFLAKE_ACCOUNT"); + String snowflakeDatabase = environment.getProperty("SNOWFLAKE_DATABASE"); + String snowflakeSchema = environment.getProperty("SNOWFLAKE_SCHEMA"); + String snowflakeRegion = environment.getProperty("SNOWFLAKE_REGION"); + String snowflakeComputePool = environment.getProperty("SNOWFLAKE_COMPUTE_POOL"); + + // Get account identifier from SNOWFLAKE_ACCOUNT (required) + if (snowflakeAccount == null || snowflakeAccount.isEmpty()) { + throw new IllegalStateException("Error in SPCS environment: SNOWFLAKE_ACCOUNT not set"); + } + accountIdentifier = snowflakeAccount; + + // Use SNOWFLAKE_HOST if available, otherwise build from account identifier + if (snowflakeHost != null && !snowflakeHost.isEmpty()) { + // SNOWFLAKE_HOST contains the full hostname (e.g., ".us-east-1.snowflakecomputing.com") + // Add https:// if not present + if (snowflakeHost.startsWith("https://") || snowflakeHost.startsWith("http://")) { + accountUrl = snowflakeHost; + } else { + accountUrl = "https://" + snowflakeHost; + } + log.info("Using account URL from SNOWFLAKE_HOST environment variable: {}", accountUrl); + } else { + // Build account URL from account identifier by appending .snowflakecomputing.com + // Format: https://{account_identifier}.snowflakecomputing.com + accountUrl = String.format("https://%s.snowflakecomputing.com", accountIdentifier); + } + + // Database and schema: application yaml config overrides environment variables (when running inside SPCS) + database = getProperty(PROPERTY_DATABASE); + if (database == null || database.isEmpty()) { + database = snowflakeDatabase; + if (database != null && !database.isEmpty()) { + log.info("Using database from SNOWFLAKE_DATABASE environment variable: {}", database); + } else { + throw new IllegalStateException("Error in configuration of SPCS backend: SNOWFLAKE_DATABASE not set and proxy.spcs.database not configured"); + } + } else { + log.info("Using database from configuration: {} (SNOWFLAKE_DATABASE was: {})", database, snowflakeDatabase); + } + + schema = getProperty(PROPERTY_SCHEMA); + if (schema == null || schema.isEmpty()) { + schema = snowflakeSchema; + if (schema != null && !schema.isEmpty()) { + log.info("Using schema from SNOWFLAKE_SCHEMA environment variable: {}", schema); + } else { + throw new IllegalStateException("Error in configuration of SPCS backend: SNOWFLAKE_SCHEMA not set and proxy.spcs.schema not configured"); + } + } else { + log.info("Using schema from configuration: {} (SNOWFLAKE_SCHEMA was: {})", schema, snowflakeSchema); + } + + // Compute pool: use configured value if set, otherwise use SNOWFLAKE_COMPUTE_POOL + computePool = getProperty(PROPERTY_COMPUTE_POOL); + if (computePool == null) { + if (snowflakeComputePool != null && !snowflakeComputePool.isEmpty()) { + computePool = snowflakeComputePool; + log.info("Using compute pool from SNOWFLAKE_COMPUTE_POOL environment variable: {}", computePool); + } else { + throw new IllegalStateException("Error in configuration of SPCS backend: proxy.spcs.compute-pool not set and SNOWFLAKE_COMPUTE_POOL environment variable not available"); + } + } else { + log.info("Using compute pool from configuration: {} (SNOWFLAKE_COMPUTE_POOL was: {})", computePool, snowflakeComputePool); + } + + log.info("Loaded SPCS environment: account={}, region={}, compute-pool={}", + snowflakeAccount, snowflakeRegion, computePool); + } + + /** + * Loads configuration from properties (when running external to SPCS). + */ + private void loadConfigurationFromProperties() { + // Get account identifier from property (required when running external to SPCS) + String accountIdentifierConfig = getProperty(PROPERTY_ACCOUNT_IDENTIFIER); + if (accountIdentifierConfig == null || accountIdentifierConfig.isEmpty()) { + throw new IllegalStateException("Error in configuration of SPCS backend: proxy.spcs.account-identifier not set"); + } + accountIdentifier = accountIdentifierConfig; + + // Check for SNOWFLAKE_HOST environment variable for account URL (works both inside and outside SPCS) + String snowflakeHost = environment.getProperty("SNOWFLAKE_HOST"); + if (snowflakeHost != null && !snowflakeHost.isEmpty()) { + // SNOWFLAKE_HOST contains the full hostname + // Add https:// if not present + if (snowflakeHost.startsWith("https://") || snowflakeHost.startsWith("http://")) { + accountUrl = snowflakeHost; + } else { + accountUrl = "https://" + snowflakeHost; + } + log.info("Using account URL from SNOWFLAKE_HOST environment variable: {}", accountUrl); + } else { + // Construct account URL from account identifier by appending .snowflakecomputing.com + accountUrl = String.format("https://%s.snowflakecomputing.com", accountIdentifier); + } + + database = getProperty(PROPERTY_DATABASE); + if (database == null) { + throw new IllegalStateException("Error in configuration of SPCS backend: proxy.spcs.database not set"); + } + + schema = getProperty(PROPERTY_SCHEMA); + if (schema == null) { + throw new IllegalStateException("Error in configuration of SPCS backend: proxy.spcs.schema not set"); + } + + computePool = getProperty(PROPERTY_COMPUTE_POOL); + if (computePool == null) { + throw new IllegalStateException("Error in configuration of SPCS backend: proxy.spcs.compute-pool not set"); + } + } + + /** + * Sets up SPCS session token authentication (when running inside SPCS). + */ + private void setupSpcsSessionTokenAuth() { + // Check for session token file + if (!Files.exists(SPCS_SESSION_TOKEN_PATH) || !Files.isRegularFile(SPCS_SESSION_TOKEN_PATH)) { + throw new IllegalStateException("Running inside SPCS but session token file not found: " + SPCS_SESSION_TOKEN_PATH); + } + + // Use supplier to read token fresh on each request (allows SPCS to refresh it automatically) + authMethod = AuthMethod.SPCS_SESSION_TOKEN; + jwtTokenSupplier = () -> { + try { + String sessionToken = Files.readString(SPCS_SESSION_TOKEN_PATH).trim(); + if (sessionToken.isEmpty()) { + throw new IllegalStateException("SPCS session token file exists but is empty: " + SPCS_SESSION_TOKEN_PATH); + } + return sessionToken; + } catch (IOException e) { + throw new RuntimeException("Error reading SPCS session token from " + SPCS_SESSION_TOKEN_PATH + ": " + e.getMessage(), e); + } + }; + log.info("Running inside SPCS: will read authentication token from {} on each request", SPCS_SESSION_TOKEN_PATH); + } + + /** + * Initializes the Snowflake API client with authentication. + */ + private void initializeSnowflakeAPIClient() { + try { + // Create a new API client instance for SPCS backend + snowflakeAPIClient = new ApiClient(); + snowflakeAPIClient.setBasePath(accountUrl); + + // Set authentication token based on auth method + // Use KeyPair authentication scheme (HttpBearerAuth) for all token types - works for JWT, OAuth, and PAT tokens + HttpBearerAuth bearerAuth = (HttpBearerAuth) snowflakeAPIClient.getAuthentication("KeyPair"); + + // Set bearer token using supplier so it is resolved on each request + // For SPCS_SESSION_TOKEN: reads current value from file (allows SPCS to refresh token) + // For KEYPAIR: generates JWT on demand (auto-refresh on expiry) + // For PAT: supplier returns same token + bearerAuth.setBearerToken(jwtTokenSupplier); + + // Set X-Snowflake-Authorization-Token-Type header + // This helps snowflake identify the token type and useful in logs for debugging + if (authMethod == AuthMethod.KEYPAIR) { + snowflakeTokenType = "KEYPAIR_JWT"; // Key-pair JWT token + } else if (authMethod == AuthMethod.SPCS_SESSION_TOKEN) { + snowflakeTokenType = "OAUTH"; // OAuth token from SPCS session + } else if (authMethod == AuthMethod.PAT) { + snowflakeTokenType = "PROGRAMMATIC_ACCESS_TOKEN"; // Programmatic access token + } else { + throw new IllegalStateException("Unknown authentication method: " + authMethod); + } + snowflakeAPIClient.addDefaultHeader("X-Snowflake-Authorization-Token-Type", snowflakeTokenType); + + String useRole = getProperty(PROPERTY_USE_ROLE); + if (useRole != null && !useRole.isBlank()) { + snowflakeAPIClient.addDefaultHeader("X-Snowflake-Role", useRole.trim()); + log.info("SPCS REST API will use role: {}", useRole.trim()); + } + + snowflakeServiceAPI = new ServiceApi(snowflakeAPIClient); + snowflakeStatementsAPI = new StatementsApi(snowflakeAPIClient); + log.info("Initialized Snowflake SPCS backend with account URL: {} using authentication type: {}", accountUrl, snowflakeTokenType); + } catch (Exception e) { + throw new IllegalStateException("Error initializing Snowflake API client: " + e.getMessage(), e); + } + } + + /** + * Sets up external authentication (keypair or PAT) when running external to SPCS. + */ + private void setupExternalAuth() { + username = getProperty(PROPERTY_USERNAME); + + String privateRsaKeyPath = getProperty(PROPERTY_PRIVATE_RSA_KEY_PATH); + String programmaticAccessToken = getProperty(PROPERTY_PROGRAMMATIC_ACCESS_TOKEN); + + if (username == null) { + throw new IllegalStateException("Error in configuration of SPCS backend: proxy.spcs.username not set (required when running external to Snowflake SPCS)"); + } + + if (privateRsaKeyPath != null && Files.exists(Paths.get(privateRsaKeyPath))) { + // Priority 2: Keypair authentication + keypairAuth = new SpcsKeypairAuth(accountIdentifier, username, accountUrl, privateRsaKeyPath); + authMethod = AuthMethod.KEYPAIR; + // JWT token will be generated on-demand via supplier + // This allows automatic regeneration when the token expires + jwtTokenSupplier = () -> keypairAuth.generateJwtToken(); + // For REST API, we'll use the supplier to get fresh JWT tokens + // For ingress, JWT needs to be exchanged for Snowflake Token (handled separately) + log.info("Using keypair authentication for user: {} with RSA key: {}", username, privateRsaKeyPath); + } else if (programmaticAccessToken != null && !programmaticAccessToken.isEmpty()) { + // Priority 3: Programmatic Access Token (PAT) authentication + // Use supplier for consistency and to support future token rotation scenarios + authMethod = AuthMethod.PAT; + final String patToken = programmaticAccessToken; // Final variable for use in lambda + jwtTokenSupplier = () -> patToken; + log.info("Using programmatic access token authentication for user: {}", username); + } else { + throw new IllegalStateException("Error in configuration of SPCS backend: one of the following must be set: proxy.spcs.private-rsa-key-path or proxy.spcs.programmatic-access-token"); + } + } + + /** + * Creates one SPCS service with one container per proxy. + * ShinyProxy uses one container per spec; no multi-container or shared services. + */ + @Override + public Proxy startContainer(Authentication authentication, Container initialContainer, ContainerSpec spec, Proxy proxy, ProxySpec proxySpec, ProxyStartupLog.ProxyStartupLogBuilder proxyStartupLogBuilder) throws ContainerFailedToStartException { + Container.ContainerBuilder rContainerBuilder = initialContainer.toBuilder(); + rContainerBuilder.id(UUID.randomUUID().toString()); + + SpcsSpecExtension specExtension = proxySpec.getSpecExtension(SpcsSpecExtension.class); + String serviceName = generateServiceName(proxy); + String fullServiceName = database + "." + schema + "." + serviceName; + String containerName = generateContainerName(proxy.getId(), 0); + + try { + proxyStartupLogBuilder.startingContainer(0); + + // Build and create service (one container) + Map env = buildEnv(authentication, spec, proxy); + String serviceSpecYaml = buildServiceSpecYaml(spec, env, specExtension, proxy, serviceName, containerName, authentication); + + ServiceSpecInlineText serviceSpec = new ServiceSpecInlineText(); + serviceSpec.setSpecType("from_inline"); + serviceSpec.setSpecText(serviceSpecYaml); + + Service service = new Service(); + service.setName(serviceName); + service.setComputePool(specExtension != null ? specExtension.getSpcsComputePool().getValueOrDefault(computePool) : computePool); + service.setSpec(serviceSpec); + if (specExtension != null && specExtension.getSpcsExternalAccessIntegrations() != null && !specExtension.getSpcsExternalAccessIntegrations().isEmpty()) { + service.setExternalAccessIntegrations(specExtension.getSpcsExternalAccessIntegrations()); + } + rContainerBuilder.addRuntimeValue(new RuntimeValue(BackendContainerNameKey.inst, new BackendContainerName(fullServiceName)), false); + service.setComment(createCommentMetadata(proxy, rContainerBuilder.build())); + + snowflakeServiceAPI.createService(database, schema, service, "ifNotExists").block(); + slog.info(proxy, String.format("Created Snowflake service: %s", fullServiceName)); + + applicationEventPublisher.publishEvent(new NewProxyEvent(proxy.toBuilder().updateContainer(rContainerBuilder.build()).build(), authentication)); + + // Wait for container and endpoints + boolean needsEndpoints = !isRunningInsideSpcs() && spec.getPortMapping() != null && !spec.getPortMapping().isEmpty(); + String waitMessage = needsEndpoints ? "SPCS Container and Endpoints" : "SPCS Container"; + + boolean serviceReady = Retrying.retry((currentAttempt, maxAttempts) -> { + try { + List containers = snowflakeServiceAPI.listServiceContainers(database, schema, serviceName).collectList().block(); + boolean containerRunning = false; + if (containers != null && !containers.isEmpty()) { + for (ServiceContainer sc : containers) { + String scName = sc.getContainerName(); + if (scName != null && containerName.equalsIgnoreCase(scName)) { + String status = sc.getStatus(); + String svcStatus = sc.getServiceStatus(); + if ((status != null && ("RUNNING".equals(status) || "UP".equals(status) || "READY".equals(status))) || + (svcStatus != null && ("RUNNING".equals(svcStatus) || "UP".equals(svcStatus) || "READY".equals(svcStatus)))) { + containerRunning = true; + break; + } + if (status != null && ("FAILED".equals(status) || "ERROR".equals(status))) { + slog.warn(proxy, String.format("SPCS container %s failed: status=%s", containerName, status)); + return new Retrying.Result(false, false); + } + } + } + } + if (!containerRunning) return Retrying.FAILURE; + + if (needsEndpoints) { + List endpoints = snowflakeServiceAPI.showServiceEndpoints(database, schema, serviceName).collectList().block(); + if (endpoints == null || endpoints.isEmpty()) return Retrying.FAILURE; + for (eu.openanalytics.containerproxy.model.spec.PortMapping pm : spec.getPortMapping()) { + boolean found = false; + for (ServiceEndpoint ep : endpoints) { + if (ep.getPort() != null && ep.getPort().equals(pm.getPort()) && + Boolean.TRUE.equals(ep.getIsPublic()) && "HTTP".equalsIgnoreCase(ep.getProtocol())) { + String url = ep.getIngressUrl(); + if (url != null && !url.isEmpty() && !url.toLowerCase().contains("provisioning") && + !url.toLowerCase().contains("progress") && (url.contains("://") || url.contains("."))) { + found = true; + break; + } + } + } + if (!found) return Retrying.FAILURE; + } + } + return Retrying.SUCCESS; + } catch (WebClientResponseException e) { + slog.warn(proxy, String.format("Error checking service status: %s", e.getMessage())); + return Retrying.FAILURE; + } + }, serviceWaitTime, waitMessage, 10, proxy, slog); + + if (!serviceReady) { + String logInfo = fetchServiceLogsForError(database, schema, serviceName); + String errorMessage = "Service failed to start" + (needsEndpoints ? " or endpoints failed to provision" : ""); + if (logInfo != null && !logInfo.isEmpty()) { + slog.warn(proxy, String.format("Container logs for failed service %s:\n%s", serviceName, logInfo)); + errorMessage += ". Container logs: " + logInfo; + } + throw new ContainerFailedToStartException(errorMessage, null, rContainerBuilder.build()); + } + + proxyStartupLogBuilder.containerStarted(0); + + if (!spec.getImage().isPresent() || spec.getImage().getValue() == null || spec.getImage().getValue().isEmpty()) { + throw new ContainerFailedToStartException(String.format("Error starting proxy: spec with id '%s' has no 'container-image' configured", proxy.getSpecId()), null, rContainerBuilder.build()); + } + rContainerBuilder.addRuntimeValue(new RuntimeValue(ContainerImageKey.inst, spec.getImage().getValue()), false); + + Proxy.ProxyBuilder proxyBuilder = proxy.toBuilder(); + Map portBindings = new HashMap<>(); + Container rContainer = rContainerBuilder.build(); + Map targets; + try { + targets = setupPortMappingExistingProxy(proxy, rContainer, portBindings); + } catch (Exception e) { + throw new ContainerFailedToStartException("Failed to set up port mapping: " + e.getMessage(), e, rContainer); + } + proxyBuilder.addTargets(targets); + String endpointUrl = extractEndpointUrlFromTargets(targets); + Map headers = setupProxyContainerHTTPHeaders(proxy, endpointUrl, authentication); + proxyBuilder.addRuntimeValue(new RuntimeValue(HttpHeadersKey.inst, new HttpHeaders(headers)), true); + proxyBuilder.updateContainer(rContainer); + return proxyBuilder.build(); + } catch (ContainerFailedToStartException e) { + throw e; + } catch (Throwable e) { + if (e instanceof InterruptedException) { + Thread.currentThread().interrupt(); + } + throw new ContainerFailedToStartException("SPCS container failed to start", e, rContainerBuilder.build()); + } + } + + /** + * Builds service YAML spec for a single container. + */ + private String buildServiceSpecYaml(ContainerSpec spec, Map env, SpcsSpecExtension specExtension, Proxy proxy, String serviceName, String containerName, Authentication authentication) throws IOException { + Map serviceSpec = new HashMap<>(); + Map specSection = new HashMap<>(); + + specSection.put("containers", java.util.Collections.singletonList(buildContainerMap(spec, env, containerName, specExtension))); + + List endpointNames = new ArrayList<>(); + if (spec.getPortMapping() != null && !spec.getPortMapping().isEmpty()) { + List> endpoints = new ArrayList<>(); + for (eu.openanalytics.containerproxy.model.spec.PortMapping pm : spec.getPortMapping()) { + endpointNames.add(pm.getName()); + Map ep = new HashMap<>(); + ep.put("name", pm.getName()); + ep.put("port", pm.getPort()); + ep.put("protocol", "HTTP"); + ep.put("public", !isRunningInsideSpcs()); + endpoints.add(ep); + } + specSection.put("endpoints", endpoints); + } + + if (specExtension != null && specExtension.getSpcsVolumes() != null && !specExtension.getSpcsVolumes().isEmpty()) { + List> volumes = new ArrayList<>(); + for (SpcsVolume vol : specExtension.getSpcsVolumes()) { + Map vm = buildVolumeMap(vol); + if (vm != null) volumes.add(vm); + } + if (!volumes.isEmpty()) specSection.put("volumes", volumes); + } + + serviceSpec.put("spec", specSection); + + boolean executeAsCaller = authentication instanceof SpcsAuthenticationToken && + authentication.getCredentials() != null && !authentication.getCredentials().toString().isBlank(); + Map capabilities = new HashMap<>(); + Map securityContext = new HashMap<>(); + securityContext.put("executeAsCaller", executeAsCaller); + capabilities.put("securityContext", securityContext); + serviceSpec.put("capabilities", capabilities); + + if (!endpointNames.isEmpty()) { + Map role = new HashMap<>(); + role.put("name", serviceName); + role.put("endpoints", endpointNames); + serviceSpec.put("serviceRoles", java.util.Collections.singletonList(role)); + } + + return yamlMapper.writeValueAsString(serviceSpec); + } + + /** + * Creates comment metadata for recovery (single container). + */ + private String createCommentMetadata(Proxy proxy, Container container) { + Map commentMetadata = new HashMap<>(); + Map proxyEntry = new HashMap<>(); + proxyEntry.put("proxyRuntimeValues", buildProxyRuntimeValues(proxy)); + Map containersMap = new HashMap<>(); + containersMap.put("0", buildContainerMetadata(container)); + proxyEntry.put("containers", containersMap); + commentMetadata.put("proxies", java.util.Collections.singletonMap(proxy.getId(), proxyEntry)); + try { + return jsonMapper.writeValueAsString(commentMetadata); + } catch (com.fasterxml.jackson.core.JsonProcessingException e) { + throw new RuntimeException("Failed to serialize comment metadata to JSON", e); + } + } + + /** + * Generates a service name for SPCS. + * Format: SP_SERVICE__{proxyId} + * One service per proxy; services are not shared between proxies. + */ + private String generateServiceName(Proxy proxy) { + String normalizedProxyId = normalizeServiceName(proxy.getId()); + String serviceName = "SP_SERVICE__" + normalizedProxyId; + if (serviceName.length() > 255) { + serviceName = serviceName.substring(0, 255); + } + return serviceName; + } + + /** + * Normalizes a name for use in Snowflake service names. + * Converts to uppercase and replaces invalid characters with underscores. + * + * @param name The name to normalize + * @return Normalized name + */ + private String normalizeServiceName(String name) { + if (name == null) { + return ""; + } + // Convert to uppercase and replace invalid chars (non-alphanumeric, not underscore) with underscores + // Also replace hyphens with underscores for consistency + return name.toUpperCase().replace("-", "_").replaceAll("[^A-Z0-9_]", "_"); + } + + /** + * Normalizes a proxyId for use in container names. + * Container names follow DNS-1123 subdomain rules: + * - Lowercase alphanumeric characters and hyphens only + * - Must start and end with alphanumeric character (handled by "sp--" prefix) + * - No underscores (replaced with dashes) + * - Other special characters are removed + * + * @param proxyId The proxy ID to normalize (user-configurable, may contain special characters) + * @return Normalized proxyId suitable for container names + */ + private String normalizeContainerName(String proxyId) { + if (proxyId == null) { + return ""; + } + // Convert to lowercase, replace underscores with dashes, then remove any remaining non-alphanumeric/dash characters + return proxyId.toLowerCase() + .replace("_", "-") + .replaceAll("[^a-z0-9-]", ""); + } + + /** + * Generates a container name for use in SPCS service YAML. + * Format: sp--{proxyId}--{containerIndex} + * Requirements: + * - Must start with alpha character (starts with "sp") + * - Lowercase, no underscores (SPCS doesn't support underscores in container names) + * - Maximum 63 characters + * - Uses double dashes as separators + * + * @param proxyId The proxy ID (user-configurable, may contain special characters) + * @param containerIndex The container index (0-based) + * @return Container name in format sp--{proxyId}--{containerIndex} + */ + private String generateContainerName(String proxyId, Integer containerIndex) { + // Normalize proxyId: sanitize for container name restrictions + String normalizedProxyId = normalizeContainerName(proxyId); + // Format: sp--{proxyId}--{containerIndex} + return "sp--" + normalizedProxyId + "--" + containerIndex; + } + + /** + * Builds container-specific metadata including portMappings and runtime values. + * Note: containerId is not stored as it's a random UUID that can be regenerated during recovery. + * + * @param initialContainer The container to extract metadata from + * @return Map containing container metadata + */ + private Map buildContainerMetadata(Container initialContainer) { + Map containerMetadata = new HashMap<>(); + + // Store container-specific runtime values + Map containerRuntimeValues = new HashMap<>(); + initialContainer.getRuntimeValues().values().stream() + .filter(runtimeValue -> runtimeValue.getKey().isContainerSpecific()) + .forEach(runtimeValue -> { + if (runtimeValue.getKey().getIncludeAsLabel() || runtimeValue.getKey().getIncludeAsAnnotation()) { + containerRuntimeValues.put(runtimeValue.getKey().getKeyAsLabel(), runtimeValue.toString()); + } + }); + containerMetadata.put("runtimeValues", containerRuntimeValues); + + // Store PortMappingsKey (container-specific) + RuntimeValue portMappingsValue = initialContainer.getRuntimeValues().get(PortMappingsKey.inst); + if (portMappingsValue != null) { + String portMappingsJson = portMappingsValue.getKey().serializeToString(portMappingsValue.getObject()); + containerMetadata.put("portMappings", portMappingsJson); + } + + return containerMetadata; + } + + /** + * Builds proxy-level runtime values map. + * + * @param proxy The proxy to extract runtime values from + * @return Map containing proxy-level runtime values + */ + private Map buildProxyRuntimeValues(Proxy proxy) { + Map proxyRuntimeValues = new HashMap<>(); + proxy.getRuntimeValues().values().stream() + .filter(runtimeValue -> !runtimeValue.getKey().isContainerSpecific()) + .forEach(runtimeValue -> { + if (runtimeValue.getKey().getIncludeAsLabel() || runtimeValue.getKey().getIncludeAsAnnotation()) { + proxyRuntimeValues.put(runtimeValue.getKey().getKeyAsLabel(), runtimeValue.toString()); + } + }); + return proxyRuntimeValues; + } + + /** + * Builds a container map structure for YAML serialization. + * @param spec The container spec + * @param env Environment variables map + * @param containerName The name for this container (sp--{proxyId}--{containerIndex} format) + * @param specExtension The SPCS spec extension (contains secrets configuration) + * @return Map representing the container structure + */ + private Map buildContainerMap(ContainerSpec spec, Map env, String containerName, SpcsSpecExtension specExtension) { + Map container = new HashMap<>(); + container.put("name", containerName); + + // Image from Snowflake image repository + if (!spec.getImage().isPresent() || spec.getImage().getValue() == null || spec.getImage().getValue().isEmpty()) { + throw new IllegalStateException("Error building container spec: 'container-image' is required but not specified. Please configure 'container-image' in your proxy spec."); + } + String image = spec.getImage().getValue(); + image = formatSnowflakeImageName(image); + container.put("image", image); + + // Command + if (spec.getCmd().isPresent() && !spec.getCmd().getValue().isEmpty()) { + container.put("command", spec.getCmd().getValue()); + } + + // Environment variables (must be a map, not a list) + if (!env.isEmpty()) { + container.put("env", new HashMap<>(env)); + } + + // Resources (memory and CPU - requests and limits) + Map resources = new HashMap<>(); + + // Build requests map + Map requests = new HashMap<>(); + boolean hasRequests = false; + if (spec.getMemoryRequest().isPresent()) { + String memoryValue = formatMemoryValue(spec.getMemoryRequest().getValue()); + requests.put("memory", memoryValue); + hasRequests = true; + } + if (spec.getCpuRequest().isPresent()) { + String cpuValue = formatCpuValue(spec.getCpuRequest().getValue()); + requests.put("cpu", cpuValue); + hasRequests = true; + } + if (hasRequests) { + resources.put("requests", requests); + } + + // Build limits map + Map limits = new HashMap<>(); + boolean hasLimits = false; + if (spec.getMemoryLimit().isPresent()) { + String memoryValue = formatMemoryValue(spec.getMemoryLimit().getValue()); + limits.put("memory", memoryValue); + hasLimits = true; + } + if (spec.getCpuLimit().isPresent()) { + String cpuValue = formatCpuValue(spec.getCpuLimit().getValue()); + limits.put("cpu", cpuValue); + hasLimits = true; + } + if (hasLimits) { + resources.put("limits", limits); + } + + // Only add resources if we have at least requests or limits + if (!resources.isEmpty()) { + container.put("resources", resources); + } + + // Secrets (optional list) + if (specExtension != null && specExtension.getSpcsSecrets() != null && !specExtension.getSpcsSecrets().isEmpty()) { + List> secrets = new ArrayList<>(); + for (SpcsSecret secret : specExtension.getSpcsSecrets()) { + Map secretMap = new HashMap<>(); + + // Build snowflakeSecret object (objectName OR objectReference) + Map snowflakeSecret = new HashMap<>(); + if (secret.getObjectName() != null && !secret.getObjectName().isEmpty()) { + snowflakeSecret.put("objectName", secret.getObjectName()); + } else if (secret.getObjectReference() != null && !secret.getObjectReference().isEmpty()) { + snowflakeSecret.put("objectReference", secret.getObjectReference()); + } else { + // Skip this secret if neither objectName nor objectReference is specified + continue; + } + secretMap.put("snowflakeSecret", snowflakeSecret); + + // Add directoryPath OR envVarName (mutually exclusive) + if (secret.getDirectoryPath() != null && !secret.getDirectoryPath().isEmpty()) { + secretMap.put("directoryPath", secret.getDirectoryPath()); + } else if (secret.getEnvVarName() != null && !secret.getEnvVarName().isEmpty()) { + secretMap.put("envVarName", secret.getEnvVarName()); + // secretKeyRef is required when using envVarName + if (secret.getSecretKeyRef() != null && !secret.getSecretKeyRef().isEmpty()) { + secretMap.put("secretKeyRef", secret.getSecretKeyRef()); + } + } + // If neither directoryPath nor envVarName is specified, skip this secret + if (!secretMap.containsKey("directoryPath") && !secretMap.containsKey("envVarName")) { + continue; + } + + secrets.add(secretMap); + } + if (!secrets.isEmpty()) { + container.put("secrets", secrets); + } + } + + // Readiness probe (optional) + if (specExtension != null && specExtension.getSpcsReadinessProbe() != null) { + SpcsReadinessProbe readinessProbe = specExtension.getSpcsReadinessProbe(); + if (readinessProbe.getPort() != null && readinessProbe.getPath() != null && !readinessProbe.getPath().isEmpty()) { + Map readinessProbeMap = new HashMap<>(); + readinessProbeMap.put("port", readinessProbe.getPort()); + readinessProbeMap.put("path", readinessProbe.getPath()); + container.put("readinessProbe", readinessProbeMap); + } + } + + // Volume mounts (optional list) - parsed from ContainerSpec.volumes + if (spec.getVolumes() != null && spec.getVolumes().isPresent() && !spec.getVolumes().getValue().isEmpty()) { + List> volumeMounts = new ArrayList<>(); + for (String volumeMountString : spec.getVolumes().getValue()) { + SpcsVolumeMount volumeMount = parseVolumeMount(volumeMountString); + if (volumeMount != null) { + Map volumeMountMap = new HashMap<>(); + volumeMountMap.put("name", volumeMount.getName()); + volumeMountMap.put("mountPath", volumeMount.getMountPath()); + volumeMounts.add(volumeMountMap); + } + } + if (!volumeMounts.isEmpty()) { + container.put("volumeMounts", volumeMounts); + } + } + + return container; + } + + /** + * Builds a volume map structure for YAML serialization from SpcsVolume object. + * + * @param volume The SpcsVolume object + * @return Map representing the volume structure, or null if invalid + */ + private Map buildVolumeMap(SpcsVolume volume) { + if (volume == null || volume.getName() == null || volume.getSource() == null) { + return null; + } + + Map volumeMap = new HashMap<>(); + volumeMap.put("name", volume.getName()); + volumeMap.put("source", volume.getSource()); + + if (volume.getSize() != null && !volume.getSize().isEmpty()) { + // Normalize size format for block and memory volumes - Snowflake requires "Gi" suffix + String normalizedSize = normalizeVolumeSize(volume.getSize(), volume.getSource()); + volumeMap.put("size", normalizedSize); + } + + if (volume.getUid() != null) { + volumeMap.put("uid", volume.getUid()); + } + + if (volume.getGid() != null) { + volumeMap.put("gid", volume.getGid()); + } + + if (volume.getBlockConfig() != null) { + Map blockConfigMap = new HashMap<>(); + SpcsBlockConfig blockConfig = volume.getBlockConfig(); + + if (blockConfig.getInitialContents() != null && blockConfig.getInitialContents().getFromSnapshot() != null) { + Map initialContentsMap = new HashMap<>(); + initialContentsMap.put("fromSnapshot", blockConfig.getInitialContents().getFromSnapshot()); + blockConfigMap.put("initialContents", initialContentsMap); + } + + if (blockConfig.getIops() != null) { + blockConfigMap.put("iops", blockConfig.getIops()); + } + + if (blockConfig.getThroughput() != null) { + blockConfigMap.put("throughput", blockConfig.getThroughput()); + } + + if (blockConfig.getEncryption() != null) { + blockConfigMap.put("encryption", blockConfig.getEncryption()); + } + + // snapshotOnDelete: default to true for volumes managed by ShinyProxy + // This allows safe deletion of services with volumes + Boolean snapshotOnDelete = blockConfig.getSnapshotOnDelete(); + if (snapshotOnDelete == null) { + snapshotOnDelete = true; // Default to true for ShinyProxy-managed volumes + } + blockConfigMap.put("snapshotOnDelete", snapshotOnDelete); + + if (!blockConfigMap.isEmpty()) { + volumeMap.put("blockConfig", blockConfigMap); + } + } + + if (volume.getStageConfig() != null) { + Map stageConfigMap = new HashMap<>(); + SpcsStageConfig stageConfig = volume.getStageConfig(); + + if (stageConfig.getName() != null) { + stageConfigMap.put("name", stageConfig.getName()); + } + + if (stageConfig.getMetadataCache() != null) { + stageConfigMap.put("metadataCache", stageConfig.getMetadataCache()); + } + + if (stageConfig.getResources() != null) { + Map resourcesMap = new HashMap<>(); + boolean hasResources = false; + + if (stageConfig.getResources().getRequests() != null) { + Map requestsMap = new HashMap<>(); + if (stageConfig.getResources().getRequests().getMemory() != null) { + requestsMap.put("memory", stageConfig.getResources().getRequests().getMemory()); + hasResources = true; + } + if (stageConfig.getResources().getRequests().getCpu() != null) { + requestsMap.put("cpu", stageConfig.getResources().getRequests().getCpu()); + hasResources = true; + } + if (!requestsMap.isEmpty()) { + resourcesMap.put("requests", requestsMap); + } + } + + if (stageConfig.getResources().getLimits() != null) { + Map limitsMap = new HashMap<>(); + if (stageConfig.getResources().getLimits().getMemory() != null) { + limitsMap.put("memory", stageConfig.getResources().getLimits().getMemory()); + hasResources = true; + } + if (stageConfig.getResources().getLimits().getCpu() != null) { + limitsMap.put("cpu", stageConfig.getResources().getLimits().getCpu()); + hasResources = true; + } + if (!limitsMap.isEmpty()) { + resourcesMap.put("limits", limitsMap); + } + } + + if (hasResources && !resourcesMap.isEmpty()) { + stageConfigMap.put("resources", resourcesMap); + } + } + + if (!stageConfigMap.isEmpty()) { + volumeMap.put("stageConfig", stageConfigMap); + } + } + + return volumeMap; + } + + /** + * Normalizes volume size format for Snowflake SPCS requirements. + * For block and memory volumes, Snowflake requires the size to end with "Gi" suffix. + * If a plain number is provided (e.g., "20"), it will be converted to "20Gi". + * + * @param size The size value from configuration + * @param source The volume source type (block, memory, stage, local) + * @return Normalized size string with proper unit suffix + */ + private String normalizeVolumeSize(String size, String source) { + if (size == null || size.isEmpty()) { + return size; + } + + String trimmed = size.trim(); + + // For block and memory volumes, Snowflake requires "Gi" suffix + if ("block".equals(source) || "memory".equals(source)) { + // Check if it's already a valid format (ends with Gi, case-insensitive) + if (trimmed.toLowerCase().endsWith("gi")) { + return trimmed; // Already has Gi suffix + } + + // Check if it's a plain number (optionally with whitespace) + try { + // Try to parse as integer + String numberPart = trimmed.replaceAll("\\s+", ""); + Integer.parseInt(numberPart); + // If successful, it's a plain number - append "Gi" + return numberPart + "Gi"; + } catch (NumberFormatException e) { + // Not a plain number, might have other units - throw error with helpful message + throw new IllegalStateException(String.format( + "Invalid size format '%s' for %s volume. Block and memory volumes require size to be an integer with 'Gi' suffix (e.g., '20Gi'). Got: '%s'", + size, source, trimmed)); + } + } + + // For other volume types (local, stage), return as-is + return trimmed; + } + + /** + * Parses a volume mount string in ECS-style format: "volume-name:/mount/path" + * + * @param volumeMountString The volume mount string (format: "volume-name:/mount/path") + * @return SpcsVolumeMount object, or null if parsing fails + */ + private SpcsVolumeMount parseVolumeMount(String volumeMountString) { + if (volumeMountString == null || volumeMountString.isEmpty()) { + return null; + } + + int colonIndex = volumeMountString.indexOf(':'); + if (colonIndex <= 0 || colonIndex >= volumeMountString.length() - 1) { + log.warn("Invalid volume mount format (expected 'volume-name:/mount/path'): {}", volumeMountString); + return null; + } + + String volumeName = volumeMountString.substring(0, colonIndex).trim(); + String mountPath = volumeMountString.substring(colonIndex + 1).trim(); + + if (volumeName.isEmpty() || mountPath.isEmpty()) { + log.warn("Invalid volume mount format (volume name or mount path is empty): {}", volumeMountString); + return null; + } + + return SpcsVolumeMount.builder() + .name(volumeName) + .mountPath(mountPath) + .build(); + } + + /** + * Formats a Snowflake image name to the correct format. + * If the image contains a snowflakecomputing.com domain, removes it and extracts the path. + * Expected format: ////: + * + * @param image The image name (e.g., "org-account.registry.snowflakecomputing.com/path/to/image:tag" or "/path/to/image:tag") + * @return Formatted image name with domain removed (e.g., "/path/to/image:tag") + */ + private String formatSnowflakeImageName(String image) { + if (image == null || image.isEmpty()) { + return image; + } + + // If image contains snowflakecomputing.com, extract the path part after the domain + if (image.contains("snowflakecomputing.com")) { + // Find the path part after the domain (look for / after snowflakecomputing.com) + int domainIndex = image.indexOf("snowflakecomputing.com"); + int pathStart = image.indexOf('/', domainIndex); + if (pathStart >= 0) { + // Extract path starting from / + return image.substring(pathStart); + } + // If no / found after domain, return as-is (unlikely but handle gracefully) + return image; + } + + // If image already starts with /, it's already in the correct format + // Otherwise, return as-is (might be a different format) + return image; + } + + /** + * Formats a memory value for Snowflake SPCS. + * If the value already has a unit (g, gi, m, mi, t, ti), returns it as-is. + * Otherwise, assumes the value is in megabytes and converts to appropriate unit. + * + * Supported units: g, gi, m, mi, t, ti (Snowflake accepts capitalized forms like Gi, Mi) + * Converts large values to larger units (e.g., 2048m -> 2Gi, 1024m -> 1Gi) + * + * @param memoryValue The memory value (e.g., "2048" or "2Gi") + * @return Formatted memory value with capitalized unit (e.g., "2Gi" or "512Mi") + */ + private String formatMemoryValue(String memoryValue) { + if (memoryValue == null || memoryValue.isEmpty()) { + return memoryValue; + } + // Check if value already has a supported unit (case-insensitive) + // Supported units per Snowflake docs: M, Mi, G, Gi (uppercase first letter required) + String lowerValue = memoryValue.toLowerCase(); + if (lowerValue.matches(".*(m|mi|g|gi)$")) { + // Already has a unit, normalize to uppercase first letter + // Extract the numeric part and unit + java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("^(\\d+(?:\\.\\d+)?)([mM][iI]?|[gG][iI]?)$"); + java.util.regex.Matcher matcher = pattern.matcher(memoryValue); + if (matcher.matches()) { + String numberPart = matcher.group(1); + String unitPart = matcher.group(2).toLowerCase(); + // Normalize unit: m -> M, mi -> Mi, g -> G, gi -> Gi + String normalizedUnit; + if (unitPart.equals("m")) { + normalizedUnit = "M"; + } else if (unitPart.equals("mi")) { + normalizedUnit = "Mi"; + } else if (unitPart.equals("g")) { + normalizedUnit = "G"; + } else if (unitPart.equals("gi")) { + normalizedUnit = "Gi"; + } else { + normalizedUnit = unitPart; // Should not happen + } + return numberPart + normalizedUnit; + } + // If regex doesn't match, return as-is (shouldn't happen) + return memoryValue; + } + + // Parse the numeric value + try { + double value = Double.parseDouble(memoryValue); + + // Convert megabytes to appropriate unit with capitalized format + // 1024 MB = 1 GiB, 1000 MB = 1 GB + // Use binary units (Gi, Mi) for consistency with Kubernetes conventions + if (value >= 1024) { + // Convert to GiB (gibibytes) + double gib = value / 1024; + // Format to remove unnecessary decimals + if (gib == Math.floor(gib)) { + return String.valueOf((long) gib) + "Gi"; + } else { + // Round to 2 decimal places for large values + return String.format("%.2fGi", gib).replaceAll("\\.?0+$", ""); + } + } else { + // Use MiB (mebibytes) for values < 1024 MB + return (long) value + "Mi"; + } + } catch (NumberFormatException e) { + // If parsing fails, just append "Mi" as fallback + return memoryValue + "Mi"; + } + } + + /** + * Formats a CPU value for Snowflake SPCS. + * CPU can be specified as: + * - Millicores with "m" suffix (e.g., "500m", "1000m") - returned as-is + * According to Snowflake docs, fractional CPUs can be expressed as "m" (e.g., 500m = 0.5 CPUs) + * - Fractional CPUs directly (e.g., "0.5", "1", "2.5") - returned as-is + * - Whole numbers >= 1 without unit - treated as millicores and converted to fractional CPUs + * (e.g., "256" -> "0.256", "1000" -> "1", "1500" -> "1.5") + * + * Reference: https://docs.snowflake.com/en/developer-guide/snowpark-container-services/specification-reference#containers-resources-field + * + * @param cpuValue The CPU value (e.g., "256", "1000", "0.5", "500m", or "1000m") + * @return Formatted CPU value (e.g., "0.256", "1", "0.5", "500m", or "1000m") + */ + private String formatCpuValue(String cpuValue) { + if (cpuValue == null || cpuValue.isEmpty()) { + return cpuValue; + } + // Check if value already has "m" unit (millicores) + String lowerValue = cpuValue.toLowerCase(); + if (lowerValue.endsWith("m")) { + // Already has millicore unit, return as-is (Snowflake accepts "m" suffix for fractional CPUs) + return cpuValue; + } + + // Parse the numeric value + try { + double value = Double.parseDouble(cpuValue); + + // If value < 1, assume it's already in fractional CPU format (e.g., 0.5) + if (value < 1.0) { + return cpuValue; + } + + // Value >= 1, assume it's in millicores and convert to fractional CPUs + // (e.g., 256 millicores = 0.256 CPUs, 1000 millicores = 1 CPU) + double cpus = value / 1000.0; + // Format to remove unnecessary decimals + if (cpus == Math.floor(cpus)) { + return String.valueOf((long) cpus); + } else { + // Round to 3 decimal places and remove trailing zeros + return String.format("%.3f", cpus).replaceAll("\\.?0+$", ""); + } + } catch (NumberFormatException e) { + // If parsing fails, return as-is + return cpuValue; + } + } + + + @Override + public void pauseProxy(Proxy proxy) { + if (Thread.currentThread().isInterrupted()) { + return; + } + for (Container container : proxy.getContainers()) { + String fullServiceName = container.getRuntimeValue(BackendContainerNameKey.inst); + if (fullServiceName != null) { + // Parse full service name: database.schema.service + String[] parts = fullServiceName.split("\\."); + if (parts.length == 3) { + String serviceDb = parts[0]; + String serviceSchema = parts[1]; + String serviceName = parts[2]; + try { + snowflakeServiceAPI.suspendService(serviceDb, serviceSchema, serviceName, false).block(); + slog.info(proxy, String.format("Suspended Snowflake service: %s", fullServiceName)); + } catch (WebClientResponseException e) { + slog.warn(proxy, String.format("Error suspending Snowflake service %s: %s", fullServiceName, e.getMessage())); + throw new ContainerProxyException("Failed to suspend Snowflake service: " + e.getMessage(), e); + } + } + } + } + } + + @Override + public Proxy resumeProxy(Authentication user, Proxy proxy, ProxySpec proxySpec) throws ProxyFailedToStartException { + if (Thread.currentThread().isInterrupted()) { + throw new ProxyFailedToStartException("Thread interrupted", null, proxy); + } + + // All containers in a proxy share the same service, so we only need to resume once + Container firstContainer = proxy.getContainers().isEmpty() ? null : proxy.getContainers().get(0); + if (firstContainer == null) { + throw new ProxyFailedToStartException("Proxy has no containers", null, proxy); + } + + String fullServiceName = firstContainer.getRuntimeValue(BackendContainerNameKey.inst); + if (fullServiceName == null) { + throw new ProxyFailedToStartException("Service name not found in container runtime values", null, proxy); + } + + // Parse full service name: database.schema.service + String[] parts = fullServiceName.split("\\."); + if (parts.length != 3) { + throw new ProxyFailedToStartException("Invalid service name format: " + fullServiceName, null, proxy); + } + + String serviceDb = parts[0]; + String serviceSchema = parts[1]; + String serviceName = parts[2]; + + try { + // Resume the service + snowflakeServiceAPI.resumeService(serviceDb, serviceSchema, serviceName, false).block(); + slog.info(proxy, String.format("Resuming Snowflake service: %s", fullServiceName)); + + // Wait for service to be ready (similar to start container logic) + boolean serviceReady = Retrying.retry((currentAttempt, maxAttempts) -> { + try { + List containers = snowflakeServiceAPI.listServiceContainers(serviceDb, serviceSchema, serviceName).collectList().block(); + if (containers == null || containers.isEmpty()) { + return Retrying.FAILURE; + } + + // Check if all containers in the service are running/ready + boolean allRunning = true; + for (ServiceContainer serviceContainer : containers) { + String status = serviceContainer.getStatus(); + String serviceStatus = serviceContainer.getServiceStatus(); + if (status != null && (status.equals("RUNNING") || status.equals("UP") || status.equals("READY"))) { + continue; + } + if (serviceStatus != null && (serviceStatus.equals("RUNNING") || serviceStatus.equals("UP") || serviceStatus.equals("READY"))) { + continue; + } + if (status != null && (status.equals("FAILED") || status.equals("ERROR"))) { + slog.warn(proxy, String.format("SPCS container failed during resume: status=%s, message=%s", status, serviceContainer.getMessage())); + return new Retrying.Result(false, false); + } + // Container is not running yet + allRunning = false; + break; + } + + if (!allRunning) { + return Retrying.FAILURE; + } + + return Retrying.SUCCESS; + } catch (WebClientResponseException e) { + slog.warn(proxy, String.format("Error checking service containers during resume: %s", e.getMessage())); + return Retrying.FAILURE; + } + }, serviceWaitTime, "SPCS Service Resume", 10, proxy, slog); + + if (!serviceReady) { + throw new ProxyFailedToStartException("Service did not resume within timeout period", null, proxy); + } + + // On resume we only re-apply HTTP headers (e.g. fresh ingress Authorization). Ingress/private URL is not recalculated. + boolean needsEndpoints = !isRunningInsideSpcs(); + if (needsEndpoints) { + Map existingTargets = proxy.getTargets(); + if (existingTargets != null && !existingTargets.isEmpty()) { + Proxy.ProxyBuilder proxyBuilder = proxy.toBuilder(); + String endpointUrl = extractEndpointUrlFromTargets(existingTargets); + Map headers = setupProxyContainerHTTPHeaders(proxy, endpointUrl, user); + proxyBuilder.addRuntimeValue(new RuntimeValue(HttpHeadersKey.inst, new HttpHeaders(headers)), true); + slog.info(proxy, String.format("Setting up Authorization header for SPCS ingress access on resume (auth method: %s)", snowflakeTokenType != null ? snowflakeTokenType : authMethod.name())); + slog.info(proxy, String.format("Resumed Snowflake service: %s", fullServiceName)); + return proxyBuilder.build(); + } + } + slog.info(proxy, String.format("Resumed Snowflake service: %s", fullServiceName)); + return proxy; + + } catch (WebClientResponseException e) { + slog.warn(proxy, String.format("Error resuming Snowflake service %s: %s", fullServiceName, e.getMessage())); + throw new ProxyFailedToStartException("Failed to resume Snowflake service: " + e.getMessage(), e, proxy); + } + } + + @Override + public Boolean supportsPause() { + return true; + } + + @Override + protected void doStopProxy(Proxy proxy) { + if (Thread.currentThread().isInterrupted()) { + return; + } + for (Container container : proxy.getContainers()) { + String fullServiceName = container.getRuntimeValueOrNull(BackendContainerNameKey.inst); + if (fullServiceName != null) { + // Parse full service name: database.schema.service + String[] parts = fullServiceName.split("\\."); + if (parts.length == 3) { + String serviceDb = parts[0]; + String serviceSchema = parts[1]; + String serviceName = parts[2]; + try { + boolean forceDelete = getForceDeleteForService(serviceName); + deleteServiceWithForce(serviceDb, serviceSchema, serviceName, forceDelete); + slog.info(proxy, String.format("Deleted Snowflake service: %s (force=%s)", fullServiceName, forceDelete)); + } catch (WebClientResponseException e) { + slog.warn(proxy, String.format("Error deleting Snowflake service %s: %s", fullServiceName, e.getMessage())); + } + } + } + } + + // Wait for service to be stopped + boolean isInactive = Retrying.retry((currentAttempt, maxAttempts) -> { + for (Container container : proxy.getContainers()) { + String fullServiceName = container.getRuntimeValueOrNull(BackendContainerNameKey.inst); + if (fullServiceName != null) { + String[] parts = fullServiceName.split("\\."); + if (parts.length == 3) { + try { + List containers = snowflakeServiceAPI.listServiceContainers(parts[0], parts[1], parts[2]).collectList().block(); + // If we can list containers, service is not fully stopped + if (containers != null && !containers.isEmpty()) { + // Check if containers are stopped/suspended + boolean allStopped = true; + for (ServiceContainer serviceContainer : containers) { + String status = serviceContainer.getStatus(); + String serviceStatus = serviceContainer.getServiceStatus(); + if (status != null && !status.equals("SUSPENDED") && !status.equals("STOPPED") && !status.equals("DELETED")) { + allStopped = false; + break; + } + if (serviceStatus != null && !serviceStatus.equals("SUSPENDED") && !serviceStatus.equals("STOPPED") && !serviceStatus.equals("DELETED")) { + allStopped = false; + break; + } + } + if (!allStopped) { + return Retrying.FAILURE; + } + } + } catch (WebClientResponseException e) { + // Service might be deleted already + if (e.getStatusCode().value() == 404) { + return Retrying.SUCCESS; + } + } + } + } + } + return Retrying.SUCCESS; + }, serviceWaitTime, "Stopping SPCS Service", 0, proxy, slog); + + if (!isInactive) { + slog.warn(proxy, "Service did not get into stopping state"); + } + } + + @Override + public void stopProxies(Collection proxies) { + for (Proxy proxy : proxies) { + try { + stopProxy(proxy); + } catch (Exception e) { + log.error("Error stopping proxy", e); + } + } + } + + @Override + protected String getPropertyPrefix() { + return PROPERTY_PREFIX; + } + + @Override + public List scanExistingContainers() { + log.info("Scanning for existing SPCS services to recover in database schema {}.{}", database, schema); + ArrayList containers = new ArrayList<>(); + + try { + List services = snowflakeServiceAPI.listServices(database, schema, "SP_SERVICE__%", null, null, null).collectList().block(); + java.util.Set allServices = new java.util.HashSet<>(); + if (services != null) { + allServices.addAll(services); + } + + if (allServices.isEmpty()) { + log.info("No existing SPCS services found to recover"); + return containers; + } + + log.info("Found {} SPCS service(s) to scan for recovery", allServices.size()); + + for (Service service : allServices) { + String serviceName = service.getName(); + if (serviceName == null || !serviceName.startsWith("SP_SERVICE__")) { + continue; + } + + // Use service status to decide recovery; list is expected to return status + String status = service.getStatus(); + if (status == null) { + deleteServiceLogReason(serviceName, "Service status unknown (null)"); + continue; + } + String statusUpper = status.toUpperCase(java.util.Locale.ROOT); + if ("FAILED".equals(statusUpper) || "INTERNAL_ERROR".equals(statusUpper)) { + deleteServiceLogReason(serviceName, "Service status: " + status); + continue; + } + // DONE/DELETING/DELETED: service no longer exists (DONE is typically for job services) + if ("DONE".equals(statusUpper) || "DELETING".equals(statusUpper) || "DELETED".equals(statusUpper)) { + continue; + } + + // PENDING, RUNNING = up; SUSPENDED, SUSPENDING = paused + ProxyStatus recoveredStatus = ("SUSPENDED".equals(statusUpper) || "SUSPENDING".equals(statusUpper)) + ? ProxyStatus.Paused : null; + + // Fetch service and extract metadata + Map serviceMetadata = new HashMap<>(); + String specText = null; + + if (!fetchServiceImageAndMetadata(serviceName, serviceMetadata)) { + deleteServiceLogReason(serviceName, "Error fetching service metadata"); + continue; + } + + // Get spec text for container extraction + try { + Service fullService = snowflakeServiceAPI.fetchService(database, schema, serviceName).block(); + ServiceSpec serviceSpec = fullService.getSpec(); + if (serviceSpec instanceof ServiceSpecInlineText) { + specText = ((ServiceSpecInlineText) serviceSpec).getSpecText(); + } + } catch (WebClientResponseException e) { + log.warn("Error fetching service spec for recovery: {}", e.getMessage()); + } + + // Validate and delete if unrecoverable (uses comment metadata as primary source) + if (!validateAndDeleteIfUnrecoverable(serviceName, serviceMetadata)) { + continue; // Service was deleted + } + + // Extract container metadata from service comment (supports multiple proxies per service) + // Structure: {"proxies": {"proxyId": {"proxyRuntimeValues": {...}, "containers": {...}}}} + Map allContainersMetadata = new HashMap<>(); // All containers from all proxies + Map allProxyRuntimeValues = new HashMap<>(); // Proxy runtime values keyed by proxyId + try { + Service fullService = snowflakeServiceAPI.fetchService(database, schema, serviceName).block(); + String comment = fullService.getComment(); + if (comment != null && !comment.isEmpty()) { + Map commentMetadata = jsonMapper.readValue(comment, new TypeReference>() {}); + if (commentMetadata != null) { + // Extract proxies map + if (commentMetadata.containsKey("proxies")) { + @SuppressWarnings("unchecked") + Map proxies = (Map) commentMetadata.get("proxies"); + if (proxies != null) { + // Iterate through all proxies and extract their containers and runtime values + for (Map.Entry proxyEntry : proxies.entrySet()) { + String proxyId = proxyEntry.getKey(); + @SuppressWarnings("unchecked") + Map proxyData = (Map) proxyEntry.getValue(); + + // Extract proxy-level runtime values for this proxy + if (proxyData.containsKey("proxyRuntimeValues")) { + @SuppressWarnings("unchecked") + Map proxyValues = (Map) proxyData.get("proxyRuntimeValues"); + if (proxyValues != null) { + // Store with proxyId prefix to avoid conflicts + for (Map.Entry entry : proxyValues.entrySet()) { + allProxyRuntimeValues.put(proxyId + ":" + entry.getKey(), entry.getValue()); + } + } + } + + // Extract containers for this proxy + // Containers are keyed by container index (e.g., "0", "1") + // We need to map them to container names for lookup during recovery + if (proxyData.containsKey("containers")) { + @SuppressWarnings("unchecked") + Map proxyContainers = (Map) proxyData.get("containers"); + if (proxyContainers != null) { + // Convert container index keys to container names for lookup + // Container name format: sp--{proxyId}--{containerIndex} + for (Map.Entry containerEntry : proxyContainers.entrySet()) { + String containerIndex = containerEntry.getKey(); + // Build container name from proxyId and index (use same normalization as generateContainerName) + String normalizedProxyId = normalizeContainerName(proxyId); + String expectedContainerName = "sp--" + normalizedProxyId + "--" + containerIndex; + allContainersMetadata.put(expectedContainerName, containerEntry.getValue()); + } + } + } + } + } + } + } + } + } catch (Exception e) { + log.warn("Error extracting container metadata from comment for service {}: {}", serviceName, e.getMessage()); + } + + // Extract all containers from the service YAML + // Note: We pass all containers metadata, and extractContainersFromSpecText will match by container name + List> containerMetadataList = extractContainersFromSpecText(specText, allProxyRuntimeValues, allContainersMetadata); + + // recoveredStatus already set from service status above (SUSPENDED/SUSPENDING -> Paused) + + // Build ExistingContainerInfo for each container + for (Map containerMetadata : containerMetadataList) { + String containerName = containerMetadata.get("containerName"); + // Container name format: sp--{proxyId}--{containerIndex} + // Container metadata (including portMappings, runtimeValues) is already merged + // in extractContainersFromSpecText. containerId is a random UUID that can be regenerated. + String containerId = UUID.randomUUID().toString(); + + ExistingContainerInfo containerInfo = buildExistingContainerInfo(containerId, serviceName, containerMetadata, recoveredStatus); + containers.add(containerInfo); + String recoveredUserId = containerMetadata.get(UserIdKey.inst.getKeyAsLabel()); + String recoveredProxyId = containerMetadata.get(ProxyIdKey.inst.getKeyAsLabel()); + String recoveredSpecId = containerMetadata.get(ProxySpecIdKey.inst.getKeyAsLabel()); + log.info("Added container {} (id: {}) from service {} to recovery list (userId: {}, proxyId: {}, specId: {})", + containerName, containerId, serviceName, recoveredUserId, recoveredProxyId, recoveredSpecId); + } + } + + log.info("Completed scanning SPCS services: {} recoverable service(s) found", containers.size()); + } catch (WebClientResponseException e) { + log.error("Error listing services for scan: {}", e.getMessage(), e); + } + + return containers; + } + + /** + * Deletes a service with error handling and logging. + */ + private void deleteServiceLogReason(String serviceName, String reason) { + log.warn("Deleting service {} due to: {}", serviceName, reason); + try { + boolean forceDelete = getForceDeleteForService(serviceName); + deleteServiceWithForce(database, schema, serviceName, forceDelete); + log.info("Deleted Snowflake service: {}.{}.{} (force={})", database, schema, serviceName, forceDelete); + } catch (WebClientResponseException e) { + log.warn("Error deleting Snowflake service {}.{}.{}: {}", database, schema, serviceName, e.getMessage()); + } + } + + + /** + * Also calculates and stores Authorization header for SPCS ingress access + * Adds image, comment metadata, and endpoint URL to the metadata map. + * @param serviceName The service name to fetch + * @param metadata Map to populate with service metadata (will also contain "endpointUrl" key) + * @return true if successful, false on error + */ + private boolean fetchServiceImageAndMetadata(String serviceName, Map metadata) { + try { + // Get the Service object - polymorphic deserialization is now handled correctly by CustomTypeAdapterFactory + Service fullService = snowflakeServiceAPI.fetchService(database, schema, serviceName).block(); + ServiceSpec serviceSpec = fullService.getSpec(); + + // Extract spec_text (YAML string) from the properly deserialized ServiceSpecInlineText + String specText = null; + if (serviceSpec instanceof ServiceSpecInlineText) { + specText = ((ServiceSpecInlineText) serviceSpec).getSpecText(); + } + + // Extract comment (metadata) + // Comment format: {"proxies": {"proxyId": {"proxyRuntimeValues": {...}, "containers": {...}}}} + String comment = fullService.getComment(); + if (comment != null && !comment.isEmpty()) { + try { + Map commentRaw = jsonMapper.readValue(comment, new TypeReference>() {}); + if (commentRaw != null && commentRaw.containsKey("proxies") && commentRaw.get("proxies") instanceof Map) { + @SuppressWarnings("unchecked") + Map proxies = (Map) commentRaw.get("proxies"); + for (Object proxyDataObj : proxies.values()) { + if (proxyDataObj instanceof Map) { + @SuppressWarnings("unchecked") + Map proxyData = (Map) proxyDataObj; + Object pv = proxyData.get("proxyRuntimeValues"); + if (pv instanceof Map) { + @SuppressWarnings("unchecked") + Map proxyValues = (Map) pv; + if (proxyValues != null) { + metadata.putAll(proxyValues); + } + } + break; // one proxy's runtime values enough for instanceId/realmId validation + } + } + log.debug("Extracted proxy runtime values from comment for service {}", serviceName); + } + } catch (Exception e) { + log.warn("Error parsing metadata from comment for service {}: {}", serviceName, e.getMessage()); + } + } + + if (specText != null && !specText.isEmpty()) { + String image = extractImageFromSpecText(specText); + if (image != null && !image.isEmpty()) { + metadata.put("image", image); + } else { + log.warn("Failed to extract image from service spec for service {} (specText length: {})", serviceName, specText.length()); + } + } else { + log.warn("Service spec text is null or empty for service {}", serviceName); + } + + return true; + } catch (WebClientResponseException e) { + log.warn("Error fetching service spec for {}: {}", serviceName, e.getMessage()); + return false; + } + } + + /** + * Extracts all containers from service YAML spec text. + * Returns a list of metadata maps, one per container, including container name and image. + * Container-specific runtime values (like ContainerIndexKey and PortMappingsKey) are derived per-container. + * + * @param specText The service YAML spec text + * @param allProxyRuntimeValues Proxy-level runtime values from service comment (keyed by "proxyId:key" or just "key" for backward compatibility) + * @param allContainersMetadata Map of container names to container metadata objects (from all proxies in service comment) + * @return List of container metadata maps, each with container-specific values added + */ + @SuppressWarnings("unchecked") + private List> extractContainersFromSpecText(String specText, Map allProxyRuntimeValues, Map allContainersMetadata) { + List> containerList = new ArrayList<>(); + + if (specText == null || specText.isEmpty()) { + log.warn("extractContainersFromSpecText: specText is null or empty"); + return containerList; + } + + try { + // Parse YAML into Map structure + Map serviceSpec = yamlMapper.readValue(specText, Map.class); + Map specSection = (Map) serviceSpec.get("spec"); + if (specSection == null) { + log.warn("extractContainersFromSpecText: spec section not found in YAML"); + return containerList; + } + + List> containers = (List>) specSection.get("containers"); + if (containers == null) { + log.warn("extractContainersFromSpecText: containers list not found in YAML"); + return containerList; + } + + // Process each container + int containerIndex = 0; + for (Map containerMap : containers) { + Map currentContainer = new HashMap<>(); + + // Extract container name + Object nameObj = containerMap.get("name"); + if (nameObj == null) { + log.warn("extractContainersFromSpecText: container at index {} has no name", containerIndex); + containerIndex++; + continue; + } + String currentContainerName = nameObj.toString(); + currentContainer.put("containerName", currentContainerName); + + // Extract image + Object imageObj = containerMap.get("image"); + if (imageObj != null) { + currentContainer.put("image", imageObj.toString()); + } + + // Extract proxyId from container name (format: sp--{proxyId}--{containerIndex}) + String proxyId = null; + if (currentContainerName.startsWith("sp--") && currentContainerName.contains("--")) { + String[] parts = currentContainerName.split("--", 3); + if (parts.length == 3) { + proxyId = parts[1]; // Extract proxyId from container name + } + } + + // Add proxy-level runtime values for this proxy + if (proxyId != null) { + for (Map.Entry entry : allProxyRuntimeValues.entrySet()) { + String key = entry.getKey(); + if (key.startsWith(proxyId + ":")) { + // Extract the actual key name (remove proxyId prefix) + String actualKey = key.substring(proxyId.length() + 1); + currentContainer.put(actualKey, entry.getValue()); + } else if (!allProxyRuntimeValues.containsKey(proxyId + ":" + key)) { + // Only add unprefixed keys if there's no proxyId-prefixed version + currentContainer.put(key, entry.getValue()); + } + } + } else { + // Fallback: add all proxy runtime values if we can't extract proxyId + currentContainer.putAll(allProxyRuntimeValues); + } + + // Merge container-specific metadata from allContainersMetadata map + Map containerMeta = (Map) allContainersMetadata.get(currentContainerName); + if (containerMeta != null) { + // Add portMappings + if (containerMeta.containsKey("portMappings")) { + currentContainer.put(PortMappingsKey.inst.getKeyAsLabel(), containerMeta.get("portMappings").toString()); + } + + // Add container-specific runtime values + if (containerMeta.containsKey("runtimeValues")) { + Map containerRuntimeValues = (Map) containerMeta.get("runtimeValues"); + if (containerRuntimeValues != null) { + currentContainer.putAll(containerRuntimeValues); + } + } + } + + // Add container index (0-based) + currentContainer.put(ContainerIndexKey.inst.getKeyAsLabel(), String.valueOf(containerIndex)); + containerList.add(currentContainer); + containerIndex++; + } + } catch (IOException e) { + log.error("Failed to parse YAML spec text: {}", e.getMessage(), e); + } + + return containerList; + } + + /** + * Extracts image name from YAML spec text (legacy method, extracts first container's image). + * Expected YAML structure: + * spec: + * containers: + * - name: + * image: + */ + @SuppressWarnings("unchecked") + private String extractImageFromSpecText(String specText) { + if (specText == null || specText.isEmpty()) { + log.warn("extractImageFromSpecText: specText is null or empty"); + return null; + } + + try { + Map serviceSpec = yamlMapper.readValue(specText, Map.class); + Map specSection = (Map) serviceSpec.get("spec"); + if (specSection == null) { + return null; + } + + List> containers = (List>) specSection.get("containers"); + if (containers == null || containers.isEmpty()) { + return null; + } + + Map firstContainer = containers.get(0); + Object imageObj = firstContainer.get("image"); + if (imageObj != null) { + String image = imageObj.toString(); + log.debug("extractImageFromSpecText: extracted image '{}'", image); + return image; + } + } catch (IOException e) { + log.warn("extractImageFromSpecText: failed to parse YAML: {}", e.getMessage()); + } + + return null; + } + + /** + * Validates service metadata and deletes service if unrecoverable. Returns false if service was deleted. + * Uses comment metadata as primary source (label keys like "openanalytics.eu/sp-proxy-id"). + */ + private boolean validateAndDeleteIfUnrecoverable(String serviceName, Map metadata) { + // Get values from comment metadata using label keys + String instanceId = metadata.get(InstanceIdKey.inst.getKeyAsLabel()); + + // Check realm-id validation + // If current instance has realm-id configured but service doesn't, delete it (orphaned from before realm-id was used) + // If both have realm-id but they don't match, skip it (belongs to another ShinyProxy instance) + String storedRealmId = metadata.get(RealmIdKey.inst.getKeyAsLabel()); + String currentRealmId = identifierService.realmId; + if (currentRealmId != null && storedRealmId == null) { + // Current instance uses realm-id but service doesn't have it - delete orphaned service + deleteServiceLogReason(serviceName, "Missing realm-id"); + return false; + } + if (storedRealmId != null && currentRealmId != null && !storedRealmId.equals(currentRealmId)) { + // Both have realm-id but they don't match - skip it (belongs to another instance) + log.debug("Skipping service {} because realm-id mismatch (stored: {}, current: {})", + serviceName, storedRealmId, currentRealmId); + return false; + } + + // Check if we can recover this proxy based on instanceId + // This ensures we only recover containers started with the current config (unless recover-running-proxies-from-different-config is enabled) + if (!appRecoveryService.canRecoverProxy(instanceId)) { + deleteServiceLogReason(serviceName, String.format("InstanceId mismatch (stored: %s, current: %s)", + instanceId, identifierService.instanceId)); + return false; + } + + return true; + } + + /** + * Parses service comment JSON to extract runtime values (similar to Docker's parseLabelsAsRuntimeValues). + * This automatically extracts all runtime values that were stored in the comment during service creation. + * + * @param serviceName The service name (for logging) + * @param commentMetadata Map of label keys to string values from the service comment JSON + * @return Map of RuntimeValueKey to RuntimeValue, or null if parsing failed + */ + private Map, RuntimeValue> parseCommentAsRuntimeValues(String serviceName, Map commentMetadata) { + if (commentMetadata == null || commentMetadata.isEmpty()) { + log.warn("Comment metadata is null or empty for service {}", serviceName); + return new HashMap<>(); + } + + Map, RuntimeValue> runtimeValues = new HashMap<>(); + + for (RuntimeValueKey key : RuntimeValueKeyRegistry.getRuntimeValueKeys()) { + if (key.getIncludeAsLabel() || key.getIncludeAsAnnotation()) { + String value = commentMetadata.get(key.getKeyAsLabel()); + if (value != null) { + try { + runtimeValues.put(key, new RuntimeValue(key, key.deserializeFromString(value))); + } catch (Exception e) { + log.warn("Error deserializing runtime value {} for service {}: {}", key.getKeyAsLabel(), serviceName, e.getMessage()); + } + } else if (key.isRequired()) { + // value is null but is required - this might be a problem, but don't fail here + // Some required values might come from other sources (service name, service properties, etc.) + log.debug("Required runtime value {} not found in comment for service {}", key.getKeyAsLabel(), serviceName); + } + } + } + + return runtimeValues; + } + + /** + * Builds ExistingContainerInfo from metadata map containing all extracted service data. + * Uses parseCommentAsRuntimeValues to automatically extract runtime values from comment (similar to Docker labels). + * When proxyStatus is ProxyStatus.Paused, recovery will show the app as paused and use resume flow. + * + * @param containerId The container ID (UUID format) + * @param serviceName The service name (for constructing full service name) + * @param metadata Container metadata including image and runtime values + * @param proxyStatus Optional status for recovered proxy (e.g. Paused if service was suspended) + */ + private ExistingContainerInfo buildExistingContainerInfo(String containerId, String serviceName, Map metadata, ProxyStatus proxyStatus) { + // Full service name: database.schema.serviceName + String fullServiceName = database + "." + schema + "." + serviceName; + + // Extract values needed for validation/special handling + String image = metadata.get("image"); + + + // Parse runtime values from comment metadata (similar to Docker labels) + // This automatically extracts all runtime values that were stored in the comment + // Note: PortMappingsKey may already be in metadata if extracted from containerPortMappings during container extraction + Map, RuntimeValue> runtimeValues = parseCommentAsRuntimeValues(serviceName, metadata); + + // Add/override special values that can't be stored in comment (they have includeAsLabel/includeAsAnnotation=false): + + // 1. BackendContainerName - full service name (not stored in comment, derived from service name) + // BackendContainerNameKey has includeAsLabel=false, so it must be set manually (same as Docker backend does) + runtimeValues.put(BackendContainerNameKey.inst, new RuntimeValue(BackendContainerNameKey.inst, new BackendContainerName(fullServiceName))); + + // 2. ContainerImageKey - extracted from service spec (not stored in comment - has includeAsLabel=false) + // Always add ContainerImageKey (required by ShinyProxy AdminController) + if (image == null || image.isEmpty()) { + log.warn("Image not found for service {}, using empty string for ContainerImageKey", serviceName); + image = ""; + } + runtimeValues.put(ContainerImageKey.inst, new RuntimeValue(ContainerImageKey.inst, image)); + + // 2.5. PortMappingsKey - extracted from containerPortMappings map (if not already parsed) + // PortMappingsKey has includeAsAnnotation=true, but is container-specific, so stored per-container + String portMappingsJson = metadata.get(PortMappingsKey.inst.getKeyAsLabel()); + if (portMappingsJson != null && !portMappingsJson.isEmpty() && !runtimeValues.containsKey(PortMappingsKey.inst)) { + try { + PortMappings portMappings = PortMappingsKey.inst.deserializeFromString(portMappingsJson); + runtimeValues.put(PortMappingsKey.inst, new RuntimeValue(PortMappingsKey.inst, portMappings)); + } catch (Exception e) { + log.warn("Error deserializing PortMappingsKey for container {} in service {}: {}", containerId, serviceName, e.getMessage()); + } + } + + // 3. Add Authorization header to HttpHeaders + // Extract endpoint URL for authorization header (needed for keypair auth token exchange scope) + String endpointUrl = extractEndpointUrlFromService(serviceName); + if (endpointUrl != null) { + HttpHeaders existingHeaders = null; + RuntimeValue existingHeadersValue = runtimeValues.get(HttpHeadersKey.inst); + if (existingHeadersValue != null) { + existingHeaders = existingHeadersValue.getObject(); + } + Map headers = existingHeaders != null ? + new HashMap<>(existingHeaders.jsonValue()) : new HashMap<>(); + + // Get the ingress authorization header + String authorizationHeader = getIngressAuthorization(endpointUrl); + if (authorizationHeader != null && !authorizationHeader.isEmpty()) { + headers.put("Authorization", authorizationHeader); + log.debug("Added Authorization header for recovered SPCS service {} (auth method: {})", serviceName, authMethod); + } else if (authMethod == AuthMethod.KEYPAIR) { + log.warn("Ingress authorization header not available for recovered SPCS service {} (endpoint URL: {})", serviceName, endpointUrl); + } + + // Note: Sf-Context-Current-User-Token header is not available during recovery + // as we don't have access to the Authentication context. + // TODO: It will be added dynamically per request + + runtimeValues.put(HttpHeadersKey.inst, new RuntimeValue(HttpHeadersKey.inst, new HttpHeaders(headers))); + } + + // Empty port bindings (SPCS uses endpoints instead of Docker-style port bindings) + // Ports are exposed via SPCS service endpoints, not mapped to host ports + Map portBindings = new HashMap<>(); + + if (proxyStatus != null) { + return new ExistingContainerInfo(containerId, runtimeValues, image, portBindings, proxyStatus); + } + return new ExistingContainerInfo(containerId, runtimeValues, image, portBindings); + } + + @Override + public boolean isProxyHealthy(Proxy proxy) { + // Same as recovery: PENDING or RUNNING = healthy; otherwise not. Not called when proxy status is Paused. + for (Container container : proxy.getContainers()) { + String fullServiceName = container.getRuntimeValue(BackendContainerNameKey.inst); + if (fullServiceName == null) { + slog.warn(proxy, "SPCS container failed: service name not found"); + return false; + } + String[] parts = fullServiceName.split("\\."); + if (parts.length != 3) { + slog.warn(proxy, "SPCS container failed: invalid service name format"); + return false; + } + String serviceName = parts[2]; + try { + Service service = snowflakeServiceAPI.fetchService(database, schema, serviceName).block(); + String status = service != null ? service.getStatus() : null; + if (status == null) { + slog.warn(proxy, "SPCS container failed: service status unknown"); + return false; + } + String statusUpper = status.toUpperCase(java.util.Locale.ROOT); + if (!"PENDING".equals(statusUpper) && !"RUNNING".equals(statusUpper)) { + slog.warn(proxy, String.format("SPCS container not healthy: service status %s", status)); + return false; + } + } catch (WebClientResponseException e) { + slog.warn(proxy, String.format("SPCS container failed: error fetching service status: %s", e.getMessage())); + return false; + } + } + return true; + } + + /** + * Extracts the endpoint URL from target URIs for keypair auth token exchange scope. + * This is used when targets are already available (e.g., during startup). + * + * @param targets The target URIs (may be null or empty) + * @return The endpoint URL (scheme + host) or null if not available + */ + private String extractEndpointUrlFromTargets(Map targets) { + if (authMethod == AuthMethod.KEYPAIR && targets != null && !targets.isEmpty()) { + // Extract endpoint URL from the first target URI (already set to ingress URL by calculateTarget) + URI firstTarget = targets.values().iterator().next(); + if (firstTarget != null && "https".equals(firstTarget.getScheme())) { + // Extract base URL (scheme + host) for the scope + return firstTarget.getScheme() + "://" + firstTarget.getHost(); + } + } + return null; + } + + /** + * Extracts the endpoint URL from a service name by fetching its endpoints. + * Uses the same logic as calculateTarget to find the first public endpoint's ingress URL. + * This is used during recovery when we need the endpoint URL but don't have targets yet. + * + * @param serviceName The service name (short name, not fully qualified) + * @return The endpoint URL (scheme + host) or null if not available + */ + private String extractEndpointUrlFromService(String serviceName) { + + try { + // Fetch endpoints (same as calculateTarget does) + List endpoints = snowflakeServiceAPI.showServiceEndpoints(database, schema, serviceName).collectList().block(); + if (endpoints != null && !endpoints.isEmpty()) { + // Find the first public HTTP endpoint (same logic as calculateTarget) + for (ServiceEndpoint endpoint : endpoints) { + if (endpoint.getIsPublic() != null && endpoint.getIsPublic() && + endpoint.getIngressUrl() != null && !endpoint.getIngressUrl().isEmpty() && + "HTTP".equalsIgnoreCase(endpoint.getProtocol())) { + String ingressUrl = endpoint.getIngressUrl(); + + // Ingress URL format is typically: https://{endpoint}.snowflakecomputing.com + // Extract base URL (scheme + host) for the scope + if (!ingressUrl.startsWith("https://") && !ingressUrl.startsWith("http://")) { + ingressUrl = "https://" + ingressUrl; + } + + try { + URI uri = new URI(ingressUrl); + return uri.getScheme() + "://" + uri.getHost(); + } catch (java.net.URISyntaxException e) { + log.debug("Invalid ingress URL format for endpoint: {}", ingressUrl); + } + break; + } + } + } + } catch (WebClientResponseException e) { + log.debug("Could not fetch endpoints to get endpoint URL for keypair auth: {}", e.getMessage()); + } + + return null; + } + + /** + * Sets up HTTP headers for proxy container communication. + * Sets Authorization header only when running external to SPCS (for ingress access). + * Adds SPCS user context headers when authenticated via SPCS. + * + * @param proxy The proxy (used to get existing headers and container info) + * @param endpointUrl Optional endpoint URL for keypair auth token exchange scope (only used when external) + * @param authentication The authentication object (may be null, used to extract SPCS user token) + * @return Map of merged headers + */ + private Map setupProxyContainerHTTPHeaders(Proxy proxy, String endpointUrl, Authentication authentication) { + // Get existing headers from proxy and merge with new headers + HttpHeaders existingHeaders = proxy.getRuntimeObject(HttpHeadersKey.inst); + Map mergedHeaders = existingHeaders != null ? + new HashMap<>(existingHeaders.jsonValue()) : new HashMap<>(); + + // Set Authorization header only when running external to SPCS (needed for ingress access) + if (!isRunningInsideSpcs()) { + String authorizationHeader = getIngressAuthorization(endpointUrl); + + if (authorizationHeader != null && !authorizationHeader.isEmpty()) { + mergedHeaders.put("Authorization", authorizationHeader); + log.info("Setting up Authorization header for SPCS ingress access (auth method: {})", authMethod); + } else if (authMethod == AuthMethod.KEYPAIR && endpointUrl != null) { + log.warn("Ingress authorization header not available for SPCS access (endpoint URL: {})", endpointUrl); + } + } + + // Add SPCS user headers if authenticated via SPCS + // These headers are forwarded to proxy containers so they can use the caller's identity + // Username header is always added when SPCS authenticated; token header only if available + if (authentication instanceof SpcsAuthenticationToken) { + // Add username header (always present when SPCS authenticated) + Object principal = authentication.getPrincipal(); + if (principal != null) { + String username = principal.toString(); + if (!username.isBlank()) { + mergedHeaders.put("Sf-Context-Current-User", username); + log.debug("Added Sf-Context-Current-User to proxy HttpHeaders"); + } + } + + // Add user token header (only present when executeAsCaller=true on parent service) + Object credentials = authentication.getCredentials(); + if (credentials != null) { + String userToken = credentials.toString(); + if (!userToken.isBlank()) { + mergedHeaders.put("Sf-Context-Current-User-Token", userToken); + log.debug("Added Sf-Context-Current-User-Token to proxy HttpHeaders"); + } + } + } + + return mergedHeaders; + } + + protected URI calculateTarget(Container container, PortMappings.PortMappingEntry portMapping, Integer hostPort) throws Exception { + String fullServiceName = container.getRuntimeValue(BackendContainerNameKey.inst); + if (fullServiceName == null) { + throw new ContainerFailedToStartException("Service name not found while calculating target", null, container); + } + + // database.schema.service name + String[] parts = fullServiceName.split("\\."); + if (parts.length != 3) { + throw new ContainerFailedToStartException("Invalid service name format: " + fullServiceName, null, container); + } + + // Fetch service to get DNS name or ingress URL + try { + Service service = snowflakeServiceAPI.fetchService(parts[0], parts[1], parts[2]).block(); + + if (isRunningInsideSpcs()) { + // When running inside SPCS: use internal DNS name for communication + // The DNS name format is: service-name.unique-id.svc.spcs.internal + String serviceDnsName = service.getDnsName(); + if (serviceDnsName == null || serviceDnsName.isEmpty()) { + throw new ContainerFailedToStartException("Service DNS name not available from REST API", null, container); + } + + log.info("Proxy container DNS name: {}", serviceDnsName); + log.debug("calculateTarget: Service={}, DNS={}, Port={}, Path={}, Protocol={}", + fullServiceName, serviceDnsName, portMapping.getPort(), portMapping.getTargetPath(), getDefaultTargetProtocol()); + + int targetPort = portMapping.getPort(); + URI targetUri = new URI(String.format("%s://%s:%s%s", getDefaultTargetProtocol(), serviceDnsName, targetPort, portMapping.getTargetPath())); + log.debug("calculateTarget: Final target URI={}", targetUri); + return targetUri; + } else { + // When running external to SPCS: use ingress URL (HTTPS) for communication + // Note: Public endpoints have protocol HTTP, but ingress URLs use HTTPS scheme + // Need to get the ingress URL from public service endpoints that match the port + List endpoints = snowflakeServiceAPI.showServiceEndpoints(parts[0], parts[1], parts[2]).collectList().block(); + int targetPort = portMapping.getPort(); + + // Find public endpoint matching the port (when running external, we need public access) + // Public endpoints have protocol HTTP (not HTTPS), but ingress URLs use HTTPS + ServiceEndpoint matchingEndpoint = null; + for (ServiceEndpoint endpoint : endpoints) { + if (endpoint.getPort() != null && endpoint.getPort().equals(targetPort) && + endpoint.getIsPublic() != null && endpoint.getIsPublic() && + "HTTP".equalsIgnoreCase(endpoint.getProtocol())) { + matchingEndpoint = endpoint; + break; + } + } + + if (matchingEndpoint == null) { + throw new ContainerFailedToStartException("No public HTTP endpoint found for port " + targetPort + " in service " + fullServiceName, null, container); + } + + // Get ingress URL (should already be ready since we wait for endpoints during startup) + String ingressUrl = matchingEndpoint.getIngressUrl(); + log.debug("calculateTarget: Service={}, Port={}, Found matching endpoint: port={}, public={}, protocol={}, ingressUrl={}", + fullServiceName, targetPort, matchingEndpoint.getPort(), matchingEndpoint.getIsPublic(), + matchingEndpoint.getProtocol(), ingressUrl); + + if (ingressUrl == null || ingressUrl.isEmpty()) { + throw new ContainerFailedToStartException("Ingress URL not available for port " + targetPort + " in service " + fullServiceName, null, container); + } + + // Check if endpoint is still provisioning (should not happen, but validate anyway) + String lowerUrl = ingressUrl.toLowerCase(); + if (lowerUrl.contains("provisioning") || lowerUrl.contains("progress")) { + throw new ContainerFailedToStartException("Endpoint for port " + targetPort + " in service " + fullServiceName + " is still provisioning: " + ingressUrl, null, container); + } + + // Ingress URL format is typically: https://{endpoint}.snowflakecomputing.com + // Ensure it starts with https:// + String originalIngressUrl = ingressUrl; + if (!ingressUrl.startsWith("https://") && !ingressUrl.startsWith("http://")) { + ingressUrl = "https://" + ingressUrl; + log.debug("calculateTarget: Added https:// prefix to ingress URL: {} -> {}", originalIngressUrl, ingressUrl); + } + + // Validate and create URI + try { + // Append the target path if specified + String targetPath = portMapping.getTargetPath() != null ? portMapping.getTargetPath() : ""; + String fullUrl = ingressUrl + targetPath; + log.debug("calculateTarget: Service={}, Final URL={} (ingressUrl={}, targetPath={})", + fullServiceName, fullUrl, ingressUrl, targetPath); + URI uri = new URI(fullUrl); + log.debug("calculateTarget: Final target URI={}", uri); + return uri; + } catch (java.net.URISyntaxException e) { + throw new ContainerFailedToStartException("Invalid ingress URL format for port " + targetPort + ": " + ingressUrl, e, container); + } + } + } catch (WebClientResponseException e) { + throw new ContainerFailedToStartException("Failed to fetch service or endpoints: " + e.getMessage(), e, container); + } + } + + /** + * Gets the Authorization header value for use in HTTPS proxy forwarding via ingress. + * When running external to SPCS and forwarding HTTPS requests via ingress, + * this header value should be used for the Authorization header. + * + * For PAT and key-pair tokens: returns "Snowflake Token=\"\"" + * For SPCS session token: returns "Bearer " (token is read from session file) + * + * Reference: https://docs.snowflake.com/en/developer-guide/snowpark-container-services/tutorials/advanced/tutorial-8-access-public-endpoint-programmatically#option-2-send-requests-to-the-service-endpoint-programmatically-by-using-a-jwt + * + * @param endpointUrl Optional endpoint URL for key-pair token exchange scope. + * If null, a basic scope will be used. + * @return The Authorization header value (e.g., "Bearer " or "Snowflake Token=\"\""), or null if not available + */ + public String getIngressAuthorization(String endpointUrl) { + String token; + if (authMethod == AuthMethod.SPCS_SESSION_TOKEN) { + // For SPCS session token: use supplier to get token directly from session file + token = jwtTokenSupplier != null ? jwtTokenSupplier.get() : null; + if (token == null || token.isEmpty()) { + return null; + } + // Format: Snowflake Token="" + return "Snowflake Token=\"" + token + "\""; + } else if (authMethod == AuthMethod.PAT) { + // For PAT: use supplier to get token directly + token = jwtTokenSupplier != null ? jwtTokenSupplier.get() : null; + if (token == null || token.isEmpty()) { + return null; + } + // Format: Snowflake Token="" + return "Snowflake Token=\"" + token + "\""; + } else if (authMethod == AuthMethod.KEYPAIR) { + // For keypair: exchange JWT for Snowflake OAuth token + if (jwtTokenSupplier == null) { + return null; + } + String jwtToken = jwtTokenSupplier.get(); + try { + token = keypairAuth.exchangeJwtForSnowflakeToken(jwtToken, endpointUrl); + if (token == null || token.isEmpty()) { + return null; + } + // Format: Snowflake Token="" + return "Snowflake Token=\"" + token + "\""; + } catch (IOException e) { + log.error("Failed to exchange JWT for Snowflake OAuth token for ingress", e); + throw new RuntimeException("Failed to exchange JWT token for ingress authentication: " + e.getMessage(), e); + } + } + throw new IllegalStateException("Unknown authentication method: " + authMethod); + } + + /** + * Gets the username used for authentication. + * + * @return The username, or null if using SPCS session token + */ + public String getUsername() { + return username; + } + + /** + * Gets the authentication method currently being used. + * + * @return The authentication method + */ + public AuthMethod getAuthMethod() { + return authMethod; + } + + /** + * Checks if ShinyProxy is running inside SPCS. + * + * @return true if running inside SPCS, false if running external + */ + public boolean isRunningInsideSpcs() { + return authMethod == AuthMethod.SPCS_SESSION_TOKEN; + } + + private boolean getForceDeleteForService(String serviceName) { + return true; + } + + /** + * Deletes a Snowflake service, using SQL API for force deletion when needed. + * The REST API doesn't support force deletion, so we use SQL API when force=true. + * + * @param database Database name + * @param schema Schema name + * @param serviceName Service name + * @param force If true, uses SQL API to execute DROP SERVICE ... FORCE. If false, uses REST API. + * @throws WebClientResponseException If the deletion fails + */ + private void deleteServiceWithForce(String database, String schema, String serviceName, boolean force) throws WebClientResponseException { + if (force) { + // Use SQL API to execute DROP SERVICE ... FORCE + // The REST API doesn't support force deletion + String sql = String.format("DROP SERVICE %s.%s.%s FORCE", + escapeSqlIdentifier(database), + escapeSqlIdentifier(schema), + escapeSqlIdentifier(serviceName)); + + SubmitStatementRequest request = new SubmitStatementRequest(); + request.setStatement(sql); + // SQL API requires session context: set database and schema so DROP SERVICE runs in the correct namespace + request.setDatabase(database); + request.setSchema(schema); + // Warehouse is required by the SQL API + String computeWarehouse = getProperty(PROPERTY_COMPUTE_WAREHOUSE); + if (computeWarehouse != null && !computeWarehouse.isBlank()) { + request.setWarehouse(computeWarehouse.trim().toUpperCase()); + } + + // Service management (including force delete) uses the shared client with service token only (disk, keypair, or PAT). + try { + // Pass null for token type so only the client's default header is sent (avoid duplicate X-Snowflake-Authorization-Token-Type). + snowflakeStatementsAPI.submitStatement( + "ContainerProxy/1.0", // userAgent + request, + null, // requestId + false, // async + false, // nullable + "application/json", // accept - required by Snowflake SQL API + null // xSnowflakeAuthorizationTokenType - use client default to avoid duplicate header (391912) + ).block(); + log.debug("Successfully force deleted service {}.{}.{} using SQL API", database, schema, serviceName); + } catch (WebClientResponseException e) { + String responseBody = e.getResponseBodyAsString(); + log.warn("Failed to force delete service {}.{}.{} using SQL API: {}; response body: {}", + database, schema, serviceName, e.getMessage(), responseBody != null && !responseBody.isEmpty() ? responseBody : "(empty)"); + throw e; + } + } else { + // Use REST API for normal deletion + snowflakeServiceAPI.deleteService(database, schema, serviceName, false).block(); + } + } + + /** + * Escapes a SQL identifier by wrapping it in double quotes if needed. + * Simple implementation - just wraps in double quotes for safety. + */ + private String escapeSqlIdentifier(String identifier) { + if (identifier == null || identifier.isEmpty()) { + return "\"\""; + } + // Replace any double quotes with escaped double quotes + return "\"" + identifier.replace("\"", "\"\"") + "\""; + } + + /** + * Attempts to fetch service logs when a service fails to start. + * This is a best-effort attempt - if it fails, returns null and the error handling will provide SQL instructions instead. + * + * Reference: https://docs.snowflake.com/en/developer-guide/snowflake-rest-api/services/services-introduction + * REST API endpoint: GET /api/v2/databases/{database}/schemas/{schema}/services/{service_name}/logs + * + * @param database Database name + * @param schema Schema name + * @param serviceName Service name + * @return A summary of recent logs (last few lines), or null if logs cannot be fetched + */ + private String fetchServiceLogsForError(String database, String schema, String serviceName) { + try { + // First, try to get container info to get instance and container names + List containers = snowflakeServiceAPI.listServiceContainers(database, schema, serviceName).collectList().block(); + if (containers == null || containers.isEmpty()) { + return null; + } + + // Use the first container that has info + ServiceContainer container = containers.get(0); + String instanceIdStr = container.getInstanceId(); + String containerName = container.getContainerName(); + + if (instanceIdStr == null || containerName == null) { + return null; + } + + // Convert instanceId from String to Integer (API expects Integer) + Integer instanceId; + try { + instanceId = Integer.parseInt(instanceIdStr); + } catch (NumberFormatException e) { + log.debug("Invalid instanceId format: {}", instanceIdStr); + return null; + } + + // Use the generated API method to fetch logs + eu.openanalytics.containerproxy.backend.spcs.client.model.FetchServiceLogs200Response response = + snowflakeServiceAPI.fetchServiceLogs(database, schema, serviceName, instanceId, containerName, 50).block(); + + if (response == null || response.getSystem$getServiceLogs() == null) { + return null; + } + + String logContent = response.getSystem$getServiceLogs(); + if (logContent.isEmpty()) { + return null; + } + + // Extract last few lines (limit to avoid huge error messages) + String[] lines = logContent.split("\n"); + int maxLines = 10; + if (lines.length > maxLines) { + StringBuilder summary = new StringBuilder(); + summary.append("(last ").append(maxLines).append(" lines of ").append(lines.length).append(" total)\n"); + for (int i = lines.length - maxLines; i < lines.length; i++) { + summary.append(lines[i]).append("\n"); + } + return summary.toString().trim(); + } + return logContent.trim(); + } catch (WebClientResponseException e) { + log.debug("Could not fetch service logs via API: {}", e.getMessage()); + return null; + } catch (Exception e) { + log.debug("Could not fetch service logs for error reporting: {}", e.getMessage()); + return null; + } + } + +} diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsBlockConfig.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsBlockConfig.java new file mode 100644 index 00000000..72213f0d --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsBlockConfig.java @@ -0,0 +1,133 @@ +/* + * ContainerProxy + * + * Copyright (C) 2016-2025 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.backend.spcs; + +import eu.openanalytics.containerproxy.spec.expression.SpecExpressionContext; +import eu.openanalytics.containerproxy.spec.expression.SpecExpressionResolver; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +/** + * Configuration for block storage volumes in SPCS. + * + * Reference: https://docs.snowflake.com/en/developer-guide/snowpark-container-services/specification-reference + */ +@Data +@Builder(toBuilder = true) +@NoArgsConstructor(force = true, access = AccessLevel.PRIVATE) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class SpcsBlockConfig { + + /** + * Initial contents configuration for block volumes. + */ + private SpcsBlockInitialContents initialContents; + + /** + * IOPS (Input/Output Operations Per Second) for the block volume. + * Non-numeric or empty values are treated as optional (set to null). + */ + @Setter(AccessLevel.NONE) + @Getter + private Integer iops; + + /** + * Custom setter for iops that handles non-numeric values. + * Since this field is optional, non-numeric or empty values are set to null. + * This setter accepts String to handle cases where Spring Boot's binder passes the raw string value. + */ + public void setIops(String value) { + if (value == null) { + this.iops = null; + return; + } + + String trimmed = value.trim(); + // Try to parse as integer + try { + this.iops = Integer.parseInt(trimmed); + } catch (NumberFormatException e) { + // If parsing fails, set to null (optional field) + this.iops = null; + } + } + + /** + * Setter that accepts Integer (for when Spring Boot successfully converts the value). + * This is needed in addition to the String setter to handle both cases. + */ + public void setIops(Integer value) { + this.iops = value; + } + + /** + * Throughput in MiB per second for the block volume. + */ + private String throughput; + + /** + * Encryption type: SNOWFLAKE_SSE or SNOWFLAKE_FULL + */ + private String encryption; + + /** + * Whether to automatically snapshot the volume when the service is deleted. + * When true, volumes can be safely deleted with the service. + * Defaults to true for volumes managed by ShinyProxy. + */ + private Boolean snapshotOnDelete; + + public SpcsBlockConfig resolve(SpecExpressionResolver resolver, SpecExpressionContext context) { + SpcsBlockInitialContents resolvedInitialContents = null; + if (initialContents != null) { + String resolvedFromSnapshot = initialContents.getFromSnapshot() == null + ? null + : resolver.evaluateToString(initialContents.getFromSnapshot(), context); + resolvedInitialContents = SpcsBlockInitialContents.builder() + .fromSnapshot(resolvedFromSnapshot) + .build(); + } + return toBuilder() + .throughput(throughput == null ? null : resolver.evaluateToString(throughput, context)) + .encryption(encryption == null ? null : resolver.evaluateToString(encryption, context)) + .initialContents(resolvedInitialContents) + .build(); + } + + /** + * Initial contents configuration. + */ + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class SpcsBlockInitialContents { + /** + * Snapshot name to use as initial contents. + */ + private String fromSnapshot; + } +} diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsKeypairAuth.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsKeypairAuth.java new file mode 100644 index 00000000..9f89d8fe --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsKeypairAuth.java @@ -0,0 +1,294 @@ +/* + * ContainerProxy + * + * Copyright (C) 2016-2025 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.backend.spcs; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.nimbusds.jose.JWSAlgorithm; +import com.nimbusds.jose.JWSHeader; +import com.nimbusds.jose.JWSSigner; +import com.nimbusds.jose.crypto.RSASSASigner; +import com.nimbusds.jwt.JWTClaimsSet; +import com.nimbusds.jwt.SignedJWT; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.KeyFactory; +import java.security.MessageDigest; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.RSAPublicKeySpec; +import java.util.Base64; +import java.util.Date; +import java.net.URLEncoder; + +/** + * Handles keypair authentication for Snowflake SPCS. + * Generates JWT tokens from RSA private keys and exchanges them for OAuth tokens. + */ +public class SpcsKeypairAuth { + + private static final Logger log = LoggerFactory.getLogger(SpcsKeypairAuth.class); + + private final String accountIdentifier; + private final String username; + private final String accountUrl; + private final String privateRsaKeyPath; + private final ObjectMapper jsonMapper; + + /** + * Creates a new SpcsKeypairAuth instance. + * + * @param accountIdentifier The Snowflake account identifier (e.g., "ORG-ACCOUNT" or "ACCOUNT") + * @param username The Snowflake username + * @param accountUrl The Snowflake account URL (e.g., "https://account.snowflakecomputing.com") + * @param privateRsaKeyPath Path to the RSA private key file (PKCS#8 format) + */ + public SpcsKeypairAuth(String accountIdentifier, String username, String accountUrl, String privateRsaKeyPath) { + this.accountIdentifier = accountIdentifier; + this.username = username; + this.accountUrl = accountUrl; + this.privateRsaKeyPath = privateRsaKeyPath; + this.jsonMapper = new ObjectMapper(); + } + + /** + * Generates a JWT token from the RSA private key for keypair authentication. + * The JWT is signed with RS256 algorithm and includes standard Snowflake claims. + * + * JWT Claims: + * - iss: {ACCOUNT}.{USERNAME}.{KEY_SHA256} + * - sub: {ACCOUNT}.{USERNAME} + * - exp: current time + 30 seconds (short-lived token) + * + * @return The JWT token string + * @throws RuntimeException If JWT generation fails + */ + public String generateJwtToken() { + try { + // Read RSA private key + PrivateKey privateKey = loadPrivateKey(privateRsaKeyPath); + + // Use stored account identifier (convert hyphens to underscores for JWT claims) + String account = accountIdentifier.replace("-", "_"); + + // Calculate SHA256 of public key for issuer claim + String keySha256 = calculatePublicKeySha256((RSAPrivateKey) privateKey); + + // Build issuer: {ACCOUNT}.{USERNAME}.{KEY_SHA256} + String issuer = account.toUpperCase() + "." + username.toUpperCase() + "." + keySha256; + + // Build subject: {ACCOUNT}.{USERNAME} + String subject = account.toUpperCase() + "." + username.toUpperCase(); + + // Expiration: current time + 30 seconds + long now = System.currentTimeMillis() / 1000; // Unix timestamp in seconds + Date expiration = new Date((now + 30) * 1000); + + // Create JWT claims set + JWTClaimsSet claimsSet = new JWTClaimsSet.Builder() + .issuer(issuer) + .subject(subject) + .expirationTime(expiration) + .build(); + + // Create JWS header with RS256 algorithm + JWSHeader header = new JWSHeader(JWSAlgorithm.RS256); + + // Create signed JWT + SignedJWT signedJWT = new SignedJWT(header, claimsSet); + + // Sign the JWT + JWSSigner signer = new RSASSASigner(privateKey); + signedJWT.sign(signer); + + // Serialize to compact form + String jwt = signedJWT.serialize(); + + log.debug("Generated JWT token for keypair authentication (iss: {}, sub: {})", issuer, subject); + return jwt; + + } catch (Exception e) { + log.error("Error generating JWT token for keypair authentication", e); + throw new RuntimeException("Failed to generate JWT token: " + e.getMessage(), e); + } + } + + /** + * Exchanges a JWT (key-pair) token for a Snowflake OAuth token. + * This is required when forwarding HTTPS requests via ingress with key-pair authentication. + * + * Implementation note: This requires JWT encoding with RS256 algorithm and OAuth token exchange. + * Reference: https://medium.com/@vladimir.timofeenko/hands-on-with-spcs-container-networking-b347866279f9 + * + * @param jwtToken The JWT token to exchange + * @param endpointUrl Optional SPCS endpoint URL for the scope. If null, uses account URL. + * @return The Snowflake OAuth token + * @throws IOException If token exchange fails + */ + public String exchangeJwtForSnowflakeToken(String jwtToken, String endpointUrl) throws IOException { + try { + // Build OAuth token endpoint URL + String oauthTokenUrl = accountUrl + "/oauth/token"; + + // Build scope - format: session:role:{role} {endpointUrl} or just {endpointUrl} + // For now, if endpointUrl is provided, use it; otherwise use account URL + String scope = endpointUrl != null ? endpointUrl : accountUrl; + + // Build form-encoded request body + StringBuilder formData = new StringBuilder(); + formData.append("grant_type=").append(URLEncoder.encode("urn:ietf:params:oauth:grant-type:jwt-bearer", StandardCharsets.UTF_8)); + formData.append("&scope=").append(URLEncoder.encode(scope, StandardCharsets.UTF_8)); + formData.append("&assertion=").append(URLEncoder.encode(jwtToken, StandardCharsets.UTF_8)); + + // Create HTTP request + RequestBody requestBody = RequestBody.create( + formData.toString(), + MediaType.parse("application/x-www-form-urlencoded") + ); + + Request request = new Request.Builder() + .url(oauthTokenUrl) + .post(requestBody) + .header("Content-Type", "application/x-www-form-urlencoded") + .build(); + + // Execute request using OkHttpClient + OkHttpClient httpClient = new OkHttpClient(); + try (Response response = httpClient.newCall(request).execute()) { + if (!response.isSuccessful()) { + String errorBody = response.body() != null ? response.body().string() : "No error body"; + throw new IOException("OAuth token exchange failed with status " + response.code() + ": " + errorBody); + } + + if (response.body() == null) { + throw new IOException("OAuth token exchange returned empty response"); + } + + // Parse JSON response to extract access_token + String responseBody = response.body().string(); + // Format: {"access_token":"...","token_type":"Bearer","expires_in":3600} + try { + JsonNode jsonResponse = jsonMapper.readTree(responseBody); + if (!jsonResponse.has("access_token")) { + throw new IOException("OAuth token exchange response does not contain access_token: " + responseBody); + } + String oauthToken = jsonResponse.get("access_token").asText(); + log.debug("Successfully exchanged JWT for Snowflake OAuth token (scope: {})", scope); + return oauthToken; + } catch (com.fasterxml.jackson.core.JsonProcessingException e) { + throw new IOException("OAuth token exchange response is not valid JSON: " + responseBody, e); + } + } + } catch (Exception e) { + if (e instanceof IOException) { + throw e; + } + throw new IOException("Error exchanging JWT for Snowflake OAuth token: " + e.getMessage(), e); + } + } + + /** + * Loads an RSA private key from a file path. + * Supports both PKCS#8 (-----BEGIN PRIVATE KEY-----) and PKCS#1 (-----BEGIN RSA PRIVATE KEY-----) formats. + * + * @param keyPath Path to the private key file + * @return The PrivateKey object + * @throws Exception If the key cannot be loaded or parsed + */ + private PrivateKey loadPrivateKey(String keyPath) throws Exception { + String keyContent = Files.readString(Paths.get(keyPath)); + + // Remove header, footer, and whitespace + keyContent = keyContent + .replace("-----BEGIN PRIVATE KEY-----", "") + .replace("-----BEGIN RSA PRIVATE KEY-----", "") + .replace("-----END PRIVATE KEY-----", "") + .replace("-----END RSA PRIVATE KEY-----", "") + .replaceAll("\\s", ""); + + byte[] keyBytes = Base64.getDecoder().decode(keyContent); + + try { + // Try PKCS#8 format first (most common) + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); + return keyFactory.generatePrivate(keySpec); + } catch (Exception e) { + // If PKCS#8 fails, try PKCS#1 format + // PKCS#1 keys need to be converted to PKCS#8 format + // For simplicity, we'll throw an error suggesting conversion + throw new IllegalArgumentException("Unable to parse RSA private key. Please ensure the key is in PKCS#8 format (-----BEGIN PRIVATE KEY-----). " + + "If you have a PKCS#1 key (-----BEGIN RSA PRIVATE KEY-----), convert it using: openssl pkcs8 -topk8 -nocrypt -in key.pem -out key_pkcs8.pem", e); + } + } + + /** + * Calculates the SHA256 hash of the RSA public key. + * This is used in the issuer (iss) claim. + * + * For RSA keys, the public key consists of modulus and public exponent. + * The standard public exponent is 65537 (0x10001), which is used for most RSA keys. + * + * @param privateKey The RSA private key + * @return The SHA256 hash as a hexadecimal string (uppercase) + * @throws Exception If the hash cannot be calculated + */ + private String calculatePublicKeySha256(RSAPrivateKey privateKey) throws Exception { + // Use standard RSA public exponent (65537 = 0x10001) + // This is the most common value for RSA keys + java.math.BigInteger publicExponent = new java.math.BigInteger("65537"); + + // Create public key specification using modulus and public exponent + RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(privateKey.getModulus(), publicExponent); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PublicKey publicKey = keyFactory.generatePublic(publicKeySpec); + + // Get the DER-encoded public key + byte[] publicKeyBytes = publicKey.getEncoded(); + + // Calculate SHA256 hash + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + byte[] hash = digest.digest(publicKeyBytes); + + // Convert to hexadecimal string (uppercase) + StringBuilder hexString = new StringBuilder(); + for (byte b : hash) { + String hex = Integer.toHexString(0xff & b); + if (hex.length() == 1) { + hexString.append('0'); + } + hexString.append(hex); + } + return hexString.toString().toUpperCase(); + } +} diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsReadinessProbe.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsReadinessProbe.java new file mode 100644 index 00000000..aa3efbb1 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsReadinessProbe.java @@ -0,0 +1,59 @@ +/* + * ContainerProxy + * + * Copyright (C) 2016-2025 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.backend.spcs; + +import eu.openanalytics.containerproxy.spec.expression.SpecExpressionContext; +import eu.openanalytics.containerproxy.spec.expression.SpecExpressionResolver; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Represents a readiness probe configuration for SPCS containers. + * + * The readiness probe is used to determine when a container is ready to accept traffic. + * It checks an HTTP endpoint on the specified port and path. + */ +@Data +@Builder(toBuilder = true) +@NoArgsConstructor(force = true, access = AccessLevel.PRIVATE) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class SpcsReadinessProbe { + + /** + * The TCP port number to probe. + */ + private Integer port; + + /** + * The HTTP path to probe. + */ + private String path; + + public SpcsReadinessProbe resolve(SpecExpressionResolver resolver, SpecExpressionContext context) { + return toBuilder() + .port(port == null ? null : resolver.evaluateToInteger(String.valueOf(port), context)) + .path(path == null ? null : resolver.evaluateToString(path, context)) + .build(); + } +} diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsSecret.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsSecret.java new file mode 100644 index 00000000..9a0149cf --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsSecret.java @@ -0,0 +1,78 @@ +/* + * ContainerProxy + * + * Copyright (C) 2016-2025 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.backend.spcs; + +import eu.openanalytics.containerproxy.spec.expression.SpecExpressionContext; +import eu.openanalytics.containerproxy.spec.expression.SpecExpressionResolver; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Represents a Snowflake secret configuration for SPCS containers. + * + * Secrets can be mounted as files (directoryPath) or as environment variables (envVarName). + * When using envVarName, secretKeyRef specifies which key from the secret to use. + */ +@Data +@Builder(toBuilder = true) +@NoArgsConstructor(force = true, access = AccessLevel.PRIVATE) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class SpcsSecret { + + /** + * The secret object name (specify this or objectReference, not both). + */ + private String objectName; + + /** + * The secret object reference (specify this or objectName, not both). + */ + private String objectReference; + + /** + * Directory path where the secret should be mounted as a file (specify this or envVarName, not both). + */ + private String directoryPath; + + /** + * Environment variable name for the secret value (specify this or directoryPath, not both). + */ + private String envVarName; + + /** + * Secret key reference - required when using envVarName. + * Valid values: "username", "password", "secret_string" + */ + private String secretKeyRef; + + public SpcsSecret resolve(SpecExpressionResolver resolver, SpecExpressionContext context) { + return toBuilder() + .objectName(objectName == null ? null : resolver.evaluateToString(objectName, context)) + .objectReference(objectReference == null ? null : resolver.evaluateToString(objectReference, context)) + .directoryPath(directoryPath == null ? null : resolver.evaluateToString(directoryPath, context)) + .envVarName(envVarName == null ? null : resolver.evaluateToString(envVarName, context)) + .secretKeyRef(secretKeyRef == null ? null : resolver.evaluateToString(secretKeyRef, context)) + .build(); + } +} diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsSpecExtension.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsSpecExtension.java new file mode 100644 index 00000000..9b0866ba --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsSpecExtension.java @@ -0,0 +1,102 @@ +/* + * ContainerProxy + * + * Copyright (C) 2016-2025 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.backend.spcs; + +import eu.openanalytics.containerproxy.model.spec.AbstractSpecExtension; +import eu.openanalytics.containerproxy.model.spec.ISpecExtension; +import eu.openanalytics.containerproxy.spec.expression.SpecExpressionContext; +import eu.openanalytics.containerproxy.spec.expression.SpecExpressionResolver; +import eu.openanalytics.containerproxy.spec.expression.SpelField; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@EqualsAndHashCode(callSuper = true) +@Data +@Setter +@Getter +@Builder(toBuilder = true) +@AllArgsConstructor(access = AccessLevel.PRIVATE) // force Spring to not use constructor +@NoArgsConstructor(force = true, access = AccessLevel.PRIVATE) // Jackson deserialize compatibility +public class SpcsSpecExtension extends AbstractSpecExtension { + + @Builder.Default + SpelField.String spcsComputePool = new SpelField.String(); + + @Builder.Default + SpelField.String spcsDatabase = new SpelField.String(); + + @Builder.Default + SpelField.String spcsSchema = new SpelField.String(); + + /** + * Volumes for the SPCS service (defined at spec level; one service per proxy). + */ + @Builder.Default + java.util.List spcsVolumes = new java.util.ArrayList<>(); + + /** + * External access integrations for the SPCS service. + */ + @Builder.Default + java.util.List spcsExternalAccessIntegrations = new java.util.ArrayList<>(); + + @Builder.Default + java.util.List spcsSecrets = new java.util.ArrayList<>(); + + SpcsReadinessProbe spcsReadinessProbe; + + @Override + public ISpecExtension firstResolve(SpecExpressionResolver resolver, SpecExpressionContext context) { + return toBuilder() + .spcsComputePool(spcsComputePool.resolve(resolver, context)) + .spcsDatabase(spcsDatabase.resolve(resolver, context)) + .spcsSchema(spcsSchema.resolve(resolver, context)) + .spcsExternalAccessIntegrations( + spcsExternalAccessIntegrations != null + ? spcsExternalAccessIntegrations.stream() + .map(s -> resolver.evaluateToString(s, context)) + .toList() + : null) + .spcsVolumes(spcsVolumes != null + ? spcsVolumes.stream().map(v -> v.resolve(resolver, context)).toList() + : null) + .spcsSecrets(spcsSecrets != null + ? spcsSecrets.stream().map(s -> s.resolve(resolver, context)).toList() + : null) + .spcsReadinessProbe(spcsReadinessProbe != null + ? spcsReadinessProbe.resolve(resolver, context) + : null) + .build(); + } + + @Override + public ISpecExtension finalResolve(SpecExpressionResolver resolver, SpecExpressionContext context) { + return this; + } + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsSpecExtensionProvider.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsSpecExtensionProvider.java new file mode 100644 index 00000000..0f1b6e77 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsSpecExtensionProvider.java @@ -0,0 +1,40 @@ +/* + * ContainerProxy + * + * Copyright (C) 2016-2025 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.backend.spcs; + +import eu.openanalytics.containerproxy.spec.ISpecExtensionProvider; +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +import java.util.List; + +@Setter +@Getter +@Configuration +@ConfigurationProperties(prefix = "proxy") +public class SpcsSpecExtensionProvider implements ISpecExtensionProvider { + + private List specs; + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsStageConfig.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsStageConfig.java new file mode 100644 index 00000000..bac562ae --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsStageConfig.java @@ -0,0 +1,121 @@ +/* + * ContainerProxy + * + * Copyright (C) 2016-2025 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.backend.spcs; + +import eu.openanalytics.containerproxy.spec.expression.SpecExpressionContext; +import eu.openanalytics.containerproxy.spec.expression.SpecExpressionResolver; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Configuration for stage volumes in SPCS. + * + * Reference: https://docs.snowflake.com/en/developer-guide/snowpark-container-services/specification-reference + */ +@Data +@Builder(toBuilder = true) +@NoArgsConstructor(force = true, access = AccessLevel.PRIVATE) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class SpcsStageConfig { + + /** + * The stage name. + */ + private String name; + + /** + * Metadata cache time period. + */ + private String metadataCache; + + /** + * Resource requests and limits for the stage volume. + */ + private SpcsStageResources resources; + + public SpcsStageConfig resolve(SpecExpressionResolver resolver, SpecExpressionContext context) { + SpcsStageResources resolvedResources = null; + if (resources != null) { + SpcsResourceRequests resolvedRequests = null; + if (resources.getRequests() != null) { + resolvedRequests = SpcsResourceRequests.builder() + .memory(resources.getRequests().getMemory() == null ? null : resolver.evaluateToString(resources.getRequests().getMemory(), context)) + .cpu(resources.getRequests().getCpu() == null ? null : resolver.evaluateToString(resources.getRequests().getCpu(), context)) + .build(); + } + SpcsResourceLimits resolvedLimits = null; + if (resources.getLimits() != null) { + resolvedLimits = SpcsResourceLimits.builder() + .memory(resources.getLimits().getMemory() == null ? null : resolver.evaluateToString(resources.getLimits().getMemory(), context)) + .cpu(resources.getLimits().getCpu() == null ? null : resolver.evaluateToString(resources.getLimits().getCpu(), context)) + .build(); + } + resolvedResources = SpcsStageResources.builder() + .requests(resolvedRequests) + .limits(resolvedLimits) + .build(); + } + return toBuilder() + .name(name == null ? null : resolver.evaluateToString(name, context)) + .metadataCache(metadataCache == null ? null : resolver.evaluateToString(metadataCache, context)) + .resources(resolvedResources) + .build(); + } + + /** + * Resource configuration for stage volumes. + */ + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class SpcsStageResources { + private SpcsResourceRequests requests; + private SpcsResourceLimits limits; + } + + /** + * Resource requests. + */ + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class SpcsResourceRequests { + private String memory; + private String cpu; + } + + /** + * Resource limits. + */ + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class SpcsResourceLimits { + private String memory; + private String cpu; + } +} diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsVolume.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsVolume.java new file mode 100644 index 00000000..0093dc02 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsVolume.java @@ -0,0 +1,93 @@ +/* + * ContainerProxy + * + * Copyright (C) 2016-2025 Open Analytics + * + * Copyright (C) 2016-2025 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.backend.spcs; + +import eu.openanalytics.containerproxy.spec.expression.SpecExpressionContext; +import eu.openanalytics.containerproxy.spec.expression.SpecExpressionResolver; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Represents a volume definition for SPCS service specification. + * + * Volumes are defined at the service level and can be shared between containers. + * + * Reference: https://docs.snowflake.com/en/developer-guide/snowpark-container-services/specification-reference + */ +@Data +@Builder(toBuilder = true) +@NoArgsConstructor(force = true, access = AccessLevel.PRIVATE) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class SpcsVolume { + + /** + * The name of the volume (referenced in volumeMounts). + */ + private String name; + + /** + * Volume source type: local, stage, memory, or block + */ + private String source; + + /** + * Size in bytes (required for memory and block volumes). + * Supports units: K, Ki, M, Mi, G, Gi, etc. + */ + private String size; + + /** + * UID (User ID) for stage volumes (optional). + */ + private Integer uid; + + /** + * GID (Group ID) for stage volumes (optional). + */ + private Integer gid; + + /** + * Block storage configuration (optional, for block volumes). + */ + private SpcsBlockConfig blockConfig; + + /** + * Stage configuration (optional, for stage volumes). + */ + private SpcsStageConfig stageConfig; + + public SpcsVolume resolve(SpecExpressionResolver resolver, SpecExpressionContext context) { + return toBuilder() + .name(name == null ? null : resolver.evaluateToString(name, context)) + .source(source == null ? null : resolver.evaluateToString(source, context)) + .size(size == null ? null : resolver.evaluateToString(size, context)) + .uid(uid == null ? null : resolver.evaluateToInteger(String.valueOf(uid), context)) + .gid(gid == null ? null : resolver.evaluateToInteger(String.valueOf(gid), context)) + .blockConfig(blockConfig == null ? null : blockConfig.resolve(resolver, context)) + .stageConfig(stageConfig == null ? null : stageConfig.resolve(resolver, context)) + .build(); + } +} diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsVolumeMount.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsVolumeMount.java new file mode 100644 index 00000000..b7b05b7c --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsVolumeMount.java @@ -0,0 +1,48 @@ +/* + * ContainerProxy + * + * Copyright (C) 2016-2025 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.backend.spcs; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Represents a volume mount for an SPCS container. + * + * References a volume by name and specifies the mount path in the container. + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SpcsVolumeMount { + + /** + * The name of the volume to mount (must match a volume name in the service spec). + */ + private String name; + + /** + * The path where the volume should be mounted in the container. + */ + private String mountPath; +} diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client-code-generation/generate-all.bat b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client-code-generation/generate-all.bat new file mode 100644 index 00000000..fa0a6257 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client-code-generation/generate-all.bat @@ -0,0 +1,20 @@ +@echo off +setlocal enabledelayedexpansion + +echo Generating code for all OpenAPI specifications... +echo. + +for %%f in (specifications\*.yaml) do ( + echo Processing: %%f + openapi-generator-cli generate -i "%%f" -g java -c generator-config.json + if errorlevel 1 ( + echo ERROR: Failed to generate code for %%f + pause + exit /b 1 + ) + echo. +) + +echo All specifications processed successfully! +pause + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client-code-generation/generate-all.ps1 b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client-code-generation/generate-all.ps1 new file mode 100644 index 00000000..16da540e --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client-code-generation/generate-all.ps1 @@ -0,0 +1,18 @@ +Write-Host "Generating code for all OpenAPI specifications..." -ForegroundColor Green +Write-Host "" + +$specFiles = Get-ChildItem -Path "specifications" -Filter "*.yaml" + +foreach ($file in $specFiles) { + Write-Host "Processing: $($file.Name)" -ForegroundColor Cyan + openapi-generator-cli generate -i $file.FullName -g java -c generator-config.json + + if ($LASTEXITCODE -ne 0) { + Write-Host "ERROR: Failed to generate code for $($file.Name)" -ForegroundColor Red + exit 1 + } + Write-Host "" +} + +Write-Host "All specifications processed successfully!" -ForegroundColor Green + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client-code-generation/generate-all.sh b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client-code-generation/generate-all.sh new file mode 100644 index 00000000..d305ea3c --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client-code-generation/generate-all.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +echo "Generating code for all OpenAPI specifications..." +echo "" + +# Find all YAML files in specifications folder +for spec_file in specifications/*.yaml; do + if [ -f "$spec_file" ]; then + echo "Processing: $(basename "$spec_file")" + openapi-generator-cli generate -i "$spec_file" -g java -c generator-config.json + + if [ $? -ne 0 ]; then + echo "ERROR: Failed to generate code for $spec_file" + exit 1 + fi + echo "" + fi +done + +echo "All specifications processed successfully!" + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client-code-generation/generator-config.json b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client-code-generation/generator-config.json new file mode 100644 index 00000000..9a96ad08 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client-code-generation/generator-config.json @@ -0,0 +1,9 @@ +{ + "invokerPackage": "eu.openanalytics.containerproxy.backend.spcs.client", + "apiPackage": "eu.openanalytics.containerproxy.backend.spcs.client.api", + "modelPackage": "eu.openanalytics.containerproxy.backend.spcs.client.model", + "groupId": "eu.openanalytics", + "artifactId": "containerproxy-spcs-client", + "artifactVersion": "0.1.0", + "library": "webclient" +} \ No newline at end of file diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client-code-generation/readme.md b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client-code-generation/readme.md new file mode 100644 index 00000000..417a8150 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client-code-generation/readme.md @@ -0,0 +1,5 @@ +The SPCS Java client has been generated from the Snowflake REST API specifications +https://github.com/snowflakedb/snowflake-rest-api-specs + +The following tool was used to generate the java code with the Java "webclient" library. +https://openapi-generator.tech/docs/generators/java/ diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client-code-generation/specifications/common.yaml b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client-code-generation/specifications/common.yaml new file mode 100644 index 00000000..9037c2fd --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client-code-generation/specifications/common.yaml @@ -0,0 +1,613 @@ +components: + schemas: + Identifier: + type: string + description: A Snowflake object identifier. If the identifier contains spaces + or special characters, the entire string must be enclosed in double quotes. + Identifiers enclosed in double quotes are also case-sensitive. + pattern: ^"([^"]|"")+"|[a-zA-Z_][a-zA-Z0-9_$]*$ + example: TEST_NAME + ErrorResponse: + type: object + properties: + message: + type: string + description: Error message returned by the server + code: + type: string + description: Error code. + error_code: + type: string + description: Error code, same as `code` above. This property has been deprecated + and will be removed in a future release, but is temporarily supported + for for short-term backward compatibility. + request_id: + type: string + description: Unique request ID. + example: + message: Compilation error! + error_code: '390189' + request_id: 01afef9d-0607-0550-0001-dd270c3902d7 + SuccessResponse: + type: object + description: Schema for all the success responses returned by the server. + properties: + status: + type: string + description: Message returned by the server. + example: + status: Request successfully completed + SuccessAcceptedResponse: + type: object + description: Schema for a request in progress response returned by the server. + properties: + code: + type: string + description: Message code returned by the server. + message: + type: string + description: Message returned by the server + resultHandler: + type: string + description: Opaque result ID used for checking for request completion through + one or more subsequent completion check operations. + example: + code: '392604' + message: Request execution in progress. Use the provided location header or + result handler ID to perform query monitoring and management. + PointOfTime: + type: object + description: Point of time. + required: + - point_of_time_type + properties: + point_of_time_type: + description: 'Type of the point of time. Possible values include: + + - `timestamp`: Exact time using the standard timezone format. Example: + `TO_TIMESTAMP(1749423600)`. - `offset`: Interval relative to ''now.'' + in the form -N where N can be an integer or arithmetic expression. Example: + `-120` - `statement`: ID of a query statement to use as the reference + point for Time + Travel. + + For more information, see https://docs.snowflake.com/en/sql-reference/data-types-datetime.' + type: string + example: timestamp + reference: + type: string + description: Relation to the point of time. Currently, the API supports + `at` and `before`. + example: at + discriminator: + propertyName: point_of_time_type + mapping: + timestamp: PointOfTimeTimestamp + offset: PointOfTimeOffset + statement: PointOfTimeStatement + PointOfTimeTimestamp: + description: Point of time identified by a timestamp. + allOf: + - $ref: '#/components/schemas/PointOfTime' + properties: + timestamp: + type: string + description: Timestamp of the point of time (e.g. TO_TIMESTAMP(1749423600)) + example: TO_TIMESTAMP(1749423600) + PointOfTimeOffset: + description: Point of time identified by an offset in reference to the current + time + allOf: + - $ref: '#/components/schemas/PointOfTime' + properties: + offset: + type: string + description: The difference in seconds from the current time in the form + -N where N can be an integer or arithmetic expression (e.g. -120). + example: '-120' + PointOfTimeStatement: + description: Point of time indicating when a statement was executed. + allOf: + - $ref: '#/components/schemas/PointOfTime' + properties: + statement: + type: string + description: Query ID of a statement to use as the reference point (e.g. + 01bcf40d-0002-197f-0000-045701e2306e). + example: 01bcf40d-0002-197f-0000-045701e2306e + Parameter: + description: Snowflake parameter defined at the system, account, user, session, + or object level. + type: object + required: + - name + properties: + name: + type: string + description: Parameter name. + value: + type: string + description: Parameter value. + defaultValue: + type: string + description: Default parameter value. + dataType: + type: string + description: Data type of the parameter value. Either BOOLEAN, NUMBER, FLOAT, + or STRING. + level: + type: string + description: Level at which parameter is defined. + description: + type: string + description: Parameter description. + example: + name: SAMPLE_SNOWAPI_PARAM + value: true + defaultValue: false + dataType: boolean + level: ACCOUNT + description: Sample snowflake parameter. + TargetLag: + type: object + description: Specifies the schedule for periodically refreshing the dynamic + table. + properties: + type: + description: Type of lag, can be either USER_DEFINED or DOWNSTREAM. + type: string + discriminator: + propertyName: type + mapping: + USER_DEFINED: UserDefinedLag + DOWNSTREAM: DownstreamLag + UserDefinedLag: + description: User-defined target lag. + allOf: + - $ref: '#/components/schemas/TargetLag' + properties: + seconds: + type: integer + format: int64 + description: Target lag time in seconds. + example: + seconds: 3600 + required: + - seconds + DownstreamLag: + description: Downstream target lag + allOf: + - $ref: '#/components/schemas/TargetLag' + parameters: + database: + name: database + description: Identifier (i.e. name) for the database to which the resource belongs. + You can use the `/api/v2/databases` GET request to get a list of available + databases. + required: true + in: path + schema: + example: TEST_DB + $ref: ./common.yaml#/components/schemas/Identifier + schema: + name: schema + description: Identifier (i.e. name) for the schema to which the resource belongs. + You can use the `/api/v2/databases/{database}/schemas` GET request to get + a list of available schemas for the specified database. + required: true + in: path + schema: + example: TEST_SCHEMA + $ref: ./common.yaml#/components/schemas/Identifier + application: + name: application + description: Identifier (i.e. name) for the application to which the resource + belongs. You can use the `/api/v2/applications/{application}` GET request + to get a list of available applications. + required: true + in: path + schema: + example: TEST_APPLICATION + $ref: ./common.yaml#/components/schemas/Identifier + name: + name: name + description: Identifier (i.e. name) for the resource. + required: true + in: path + schema: + example: TEST_NAME + $ref: ./common.yaml#/components/schemas/Identifier + nameWithArgs: + name: nameWithArgs + description: Function's name with Args + required: true + in: path + schema: + type: string + example: foo(a number, b number) + createMode: + name: createMode + description: 'Parameter allowing support for different modes of resource creation. + Possible values include: + + - `errorIfExists`: Throws an error if you try to create a resource that already + exists. + + - `orReplace`: Automatically replaces the existing resource with the current + one. + + - `ifNotExists`: Creates a new resource when an alter is requested for a non-existent + resource.' + in: query + schema: + type: string + enum: + - errorIfExists + - orReplace + - ifNotExists + example: ifNotExists + default: errorIfExists + mode: + name: mode + description: 'Parameter determines whether the revoke operation succeeds or + fails for the privileges, based on the whether the privileges had been re-granted + to another role. + + - restrict: If the privilege being revoked has been re-granted to another + role, the REVOKE command fails. + + - cascade: If the privilege being revoked has been re-granted, the REVOKE + command recursively revokes these dependent grants. If the same privilege + on an object has been granted to the target role by a different grantor (parallel + grant), that grant is not affected and the target role retains the privilege.' + in: query + schema: + type: string + enum: + - restrict + - cascade + example: restrict + ifExists: + name: ifExists + description: 'Parameter that specifies how to handle the request for a resource + that does not exist: + + - `true`: The endpoint does not throw an error if the resource does not exist. + It returns a 200 success response, but does not take any action on the resource. + + - `false`: The endpoint throws an error if the resource doesn''t exist.' + in: query + schema: + type: boolean + example: true + default: false + like: + name: like + description: Parameter to filter the command output by resource name. Uses case-insensitive + pattern matching, with support for SQL wildcard characters. + in: query + schema: + type: string + example: test_% + pattern: + name: pattern + description: Parameter that filters the command output by a regular expression + pattern. + in: query + schema: + type: string + example: .*data_0.* + startsWith: + name: startsWith + description: Parameter to filter the command output based on the string of characters + that appear at the beginning of the object name. Uses case-sensitive pattern + matching. + in: query + schema: + type: string + example: test + rootOnly: + name: rootOnly + description: Parameter to filter the command output to return only root resources + (resources with no predecessors). + in: query + schema: + type: boolean + example: false + default: false + showLimit: + name: showLimit + description: Parameter to limit the maximum number of rows returned by a command. + in: query + schema: + type: integer + example: 10 + minimum: 1 + maximum: 10000 + fromName: + name: fromName + description: Parameter to enable fetching rows only following the first row + whose object name matches the specified string. Case-sensitive and does not + have to be the full name. + in: query + schema: + type: string + example: from_test + copyGrants: + name: copyGrants + description: Parameter to enable copy grants when creating the object. + in: query + schema: + type: boolean + example: false + default: false + asyncExec: + name: asyncExec + in: query + description: Asynchronous execution enable/disable. Default is disable. + schema: + type: boolean + default: false + sessionId: + name: sessionId + description: Unique ID for the current session. + required: true + in: path + schema: + type: integer + format: uuid + example: 524514326772799 + content-type: + name: Content-Type + description: Type of content for the resource. Currently supports `application/json`. + in: header + schema: + type: string + enum: + - application/json + accept: + name: Accept + description: Type of data format accepted by the resource. Currently supports + `application/json`. + in: header + schema: + type: string + enum: + - application/json + x-snowflake-authorization-token-type: + name: X-Snowflake-Authorization-Token-Type + description: Type of the Snowflake authorization token. Currently, keypair-jwt + (`KEYPAIR_JWT`) and OAuth tokens are supported. + in: header + schema: + type: string + enum: + - KEYPAIR_JWT + - OAUTH + x-sfc-session: + name: X-Sfc-Session + description: Token for the current Snowflake session. + in: header + required: false + schema: + type: string + description: Snowflake session token. + example: ver:3-hint:1000-ABCD= + headers: + X-Snowflake-Request-ID: + description: Unique ID of the API request. + schema: + type: string + format: uuid + Link: + description: Links to the page of results (e.g. the first page, the last page, + etc.). The header can include multiple 'url' entries with different 'rel' + attribute values that specify the page to return ('first', 'next', 'prev', + and 'last'). + schema: + type: string + example: ; rel="first",; + rel="next",; + rel="last" + securitySchemes: + KeyPair: + type: http + scheme: bearer + bearerFormat: JWT + description: Set `X-Snowflake-Authorization-Token-Type` to `KEYPAIR_JWT` if + the token is a key-pair authentication JWT. + ExternalOAuth: + type: http + scheme: bearer + bearerFormat: JWT + description: Configure External Oauth with Snowflake (see External + OAuth overview.) Set `X-Snowflake-Authorization-Token-Type` to `OAUTH` + and set the Token to the auth token received from the external Auth server. + SnowflakeOAuth: + type: oauth2 + flows: + implicit: + authorizationUrl: /oauth/authorize + scopes: {} + description: Set `X-Snowflake-Authorization-Token-Type` to `OAUTH` if the token + is snowflakeOAuth + responses: + 200SuccessResponse: + description: Successful request. + headers: + X-Snowflake-Request-ID: + $ref: '#/components/headers/X-Snowflake-Request-ID' + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse' + 201SuccessCreatedResponse: + description: Successfully created a new resource on the server. + headers: + X-Snowflake-Request-ID: + $ref: '#/components/headers/X-Snowflake-Request-ID' + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse' + 202SuccessAcceptedResponse: + headers: + Location: + schema: + type: string + description: Relative path for checking request status or getting the + result, if available. + X-Snowflake-Request-ID: + $ref: '#/components/headers/X-Snowflake-Request-ID' + description: Successfully accepted the request, but it is not completed yet. + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessAcceptedResponse' + 400BadRequest: + description: Bad Request. The request payload is invalid or malformed. This + happens if the application didn't send the correct request payload. The response + body may include the error code and message indicating the actual cause. The + application must reconstruct the request body for retry. + headers: + X-Snowflake-Request-ID: + $ref: '#/components/headers/X-Snowflake-Request-ID' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + 401Unauthorized: + description: Unauthorized. The request is not authorized. This happens if the + attached access token is invalid or missing. The response body may include + the error code and message indicating the actual cause, e.g., expired, invalid + token. The application must obtain a new access token for retry. + headers: + X-Snowflake-Request-ID: + $ref: '#/components/headers/X-Snowflake-Request-ID' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + 403Forbidden: + description: Forbidden. The request is forbidden. This can also happen if the + request is made even if the API is not enabled. + headers: + X-Snowflake-Request-ID: + $ref: '#/components/headers/X-Snowflake-Request-ID' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + 404NotFound: + description: Not Found. The request endpoint is not valid. This happens if the + API endpoint does not exist, or if the API is not enabled. + headers: + X-Snowflake-Request-ID: + $ref: '#/components/headers/X-Snowflake-Request-ID' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + 405MethodNotAllowed: + description: Method Not Allowed. The request method doesn't match the supported + API. This happens, for example, if the application calls the API with GET + method but the endpoint accepts only POST. + headers: + X-Snowflake-Request-ID: + $ref: '#/components/headers/X-Snowflake-Request-ID' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + 408RequestTimeout: + description: Request Timeout. This indicates that the request from the client + timed out and was not completed by the server. + headers: + X-Snowflake-Request-ID: + $ref: '#/components/headers/X-Snowflake-Request-ID' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + 409Conflict: + description: Conflict. The requested operation could not be performed due to + a conflicting state that could not be resolved. This usually happens when + a CREATE request was performed when there is a pre-existing resource with + the same name, and also without one of the options orReplace/ifNotExists. + headers: + X-Snowflake-Request-ID: + $ref: '#/components/headers/X-Snowflake-Request-ID' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + 410Gone: + description: Gone. This error is primarily intended to assist the task of web + maintenance by notifying the recipient that the resource is intentionally + unavailable. + headers: + X-Snowflake-Request-ID: + $ref: '#/components/headers/X-Snowflake-Request-ID' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + 415UnsupportedMediaType: + description: The request header Content-Type includes an unsupported media type. + The API supports application/json only. If none specified, the request payload + is taken as JSON, but if any other media type is specified, this error is + returned. + headers: + X-Snowflake-Request-ID: + $ref: '#/components/headers/X-Snowflake-Request-ID' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + 429LimitExceeded: + description: Limit Exceeded. The number of requests hit the rate limit. The + application must slow down the frequency of hitting the API endpoints. + headers: + X-Snowflake-Request-ID: + $ref: '#/components/headers/X-Snowflake-Request-ID' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + 500InternalServerError: + description: Internal Server Error. The server hit an unrecoverable system error. + The response body may include the error code and message for further guidance. + The application owner may need to reach out the customer support. + headers: + X-Snowflake-Request-ID: + $ref: '#/components/headers/X-Snowflake-Request-ID' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + 503ServiceUnavailable: + description: Service Unavailable. The request was not processed due to server + side timeouts. The application may retry with backoff. The jittered backoff + is recommended. + headers: + X-Snowflake-Request-ID: + $ref: '#/components/headers/X-Snowflake-Request-ID' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + 504GatewayTimeout: + description: Gateway Timeout. The request was not processed due to server side + timeouts. The application may retry with backoff. The jittered backoff is + recommended. + headers: + X-Snowflake-Request-ID: + $ref: '#/components/headers/X-Snowflake-Request-ID' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' +security: +- KeyPair: [] +- ExternalOAuth: [] +- SnowflakeOAuth: [] diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client-code-generation/specifications/service.yaml b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client-code-generation/specifications/service.yaml new file mode 100644 index 00000000..877c0531 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client-code-generation/specifications/service.yaml @@ -0,0 +1,1193 @@ +openapi: 3.0.0 +servers: +- description: Snowflake Services API + url: https://org-account.snowflakecomputing.com +info: + version: 0.0.1 + title: Snowflake Services API + description: The Snowflake Services API is a REST API that you can use to access, + update, and perform certain actions on Services resource in a Snowflake database. + contact: + name: Snowflake, Inc. + url: https://snowflake.com + email: support@snowflake.com +paths: + /api/v2/databases/{database}/schemas/{schema}/services: + get: + summary: List services + tags: + - service + description: Lists the services under the database and schema. + operationId: listServices + parameters: + - $ref: common.yaml#/components/parameters/database + - $ref: common.yaml#/components/parameters/schema + - $ref: common.yaml#/components/parameters/like + - $ref: common.yaml#/components/parameters/startsWith + - $ref: common.yaml#/components/parameters/showLimit + - $ref: common.yaml#/components/parameters/fromName + responses: + '200': + description: successful + headers: + X-Snowflake-Request-ID: + $ref: common.yaml#/components/headers/X-Snowflake-Request-ID + Link: + $ref: common.yaml#/components/headers/Link + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Service' + '202': + $ref: common.yaml#/components/responses/202SuccessAcceptedResponse + '400': + $ref: common.yaml#/components/responses/400BadRequest + '401': + $ref: common.yaml#/components/responses/401Unauthorized + '403': + $ref: common.yaml#/components/responses/403Forbidden + '404': + $ref: common.yaml#/components/responses/404NotFound + '405': + $ref: common.yaml#/components/responses/405MethodNotAllowed + '429': + $ref: common.yaml#/components/responses/429LimitExceeded + '500': + $ref: common.yaml#/components/responses/500InternalServerError + '503': + $ref: common.yaml#/components/responses/503ServiceUnavailable + '504': + $ref: common.yaml#/components/responses/504GatewayTimeout + post: + summary: Create a service + tags: + - service + description: Create a service, with standard create modifiers as query parameters. + See the Service component definition for what is required to be provided in + the request body. + operationId: createService + parameters: + - $ref: common.yaml#/components/parameters/database + - $ref: common.yaml#/components/parameters/schema + - name: createMode + description: 'Query parameter allowing support for different modes of resource + creation. Possible values include: - `errorIfExists`: Throws an error if + you try to create a resource that already exists. - `ifNotExists`: Creates + a new resource when an alter is requested for a non-existent resource.' + in: query + schema: + type: string + enum: + - errorIfExists + - ifNotExists + example: errorIfExists + default: errorIfExists + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Service' + responses: + '200': + $ref: common.yaml#/components/responses/200SuccessResponse + '202': + $ref: common.yaml#/components/responses/202SuccessAcceptedResponse + '400': + $ref: common.yaml#/components/responses/400BadRequest + '401': + $ref: common.yaml#/components/responses/401Unauthorized + '403': + $ref: common.yaml#/components/responses/403Forbidden + '404': + $ref: common.yaml#/components/responses/404NotFound + '405': + $ref: common.yaml#/components/responses/405MethodNotAllowed + '408': + $ref: common.yaml#/components/responses/408RequestTimeout + '409': + $ref: common.yaml#/components/responses/409Conflict + '429': + $ref: common.yaml#/components/responses/429LimitExceeded + '500': + $ref: common.yaml#/components/responses/500InternalServerError + '503': + $ref: common.yaml#/components/responses/503ServiceUnavailable + '504': + $ref: common.yaml#/components/responses/504GatewayTimeout + /api/v2/databases/{database}/schemas/{schema}/services:execute-job: + post: + summary: Execute a job service + tags: + - service + description: Create and execute a job service. See the JobService component + definition for what is required to be provided in the request body. + operationId: executeJobService + parameters: + - $ref: common.yaml#/components/parameters/database + - $ref: common.yaml#/components/parameters/schema + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/JobService' + responses: + '200': + $ref: common.yaml#/components/responses/200SuccessResponse + '202': + $ref: common.yaml#/components/responses/202SuccessAcceptedResponse + '400': + $ref: common.yaml#/components/responses/400BadRequest + '401': + $ref: common.yaml#/components/responses/401Unauthorized + '403': + $ref: common.yaml#/components/responses/403Forbidden + '404': + $ref: common.yaml#/components/responses/404NotFound + '405': + $ref: common.yaml#/components/responses/405MethodNotAllowed + '409': + $ref: common.yaml#/components/responses/409Conflict + '429': + $ref: common.yaml#/components/responses/429LimitExceeded + '500': + $ref: common.yaml#/components/responses/500InternalServerError + '503': + $ref: common.yaml#/components/responses/503ServiceUnavailable + '504': + $ref: common.yaml#/components/responses/504GatewayTimeout + /api/v2/databases/{database}/schemas/{schema}/services/{name}: + get: + description: Fetch a service. + tags: + - service + operationId: fetchService + parameters: + - $ref: common.yaml#/components/parameters/database + - $ref: common.yaml#/components/parameters/schema + - $ref: common.yaml#/components/parameters/name + responses: + '200': + description: successful + headers: + X-Snowflake-Request-ID: + $ref: common.yaml#/components/headers/X-Snowflake-Request-ID + Link: + $ref: common.yaml#/components/headers/Link + content: + application/json: + schema: + $ref: '#/components/schemas/Service' + '202': + $ref: common.yaml#/components/responses/202SuccessAcceptedResponse + '400': + $ref: common.yaml#/components/responses/400BadRequest + '401': + $ref: common.yaml#/components/responses/401Unauthorized + '403': + $ref: common.yaml#/components/responses/403Forbidden + '404': + $ref: common.yaml#/components/responses/404NotFound + '405': + $ref: common.yaml#/components/responses/405MethodNotAllowed + '429': + $ref: common.yaml#/components/responses/429LimitExceeded + '500': + $ref: common.yaml#/components/responses/500InternalServerError + '503': + $ref: common.yaml#/components/responses/503ServiceUnavailable + '504': + $ref: common.yaml#/components/responses/504GatewayTimeout + put: + summary: Create a (or alter an existing) service. + tags: + - service + description: Create a (or alter an existing) service. Even if the operation + is just an alter, the full property set must be provided. + operationId: createOrAlterService + parameters: + - $ref: common.yaml#/components/parameters/database + - $ref: common.yaml#/components/parameters/schema + - $ref: common.yaml#/components/parameters/name + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Service' + responses: + '200': + description: Successful request + headers: + X-Snowflake-Request-ID: + $ref: common.yaml#/components/headers/X-Snowflake-Request-ID + Link: + $ref: common.yaml#/components/headers/Link + content: + application/json: + schema: + $ref: common.yaml#/components/schemas/SuccessResponse + '202': + $ref: common.yaml#/components/responses/202SuccessAcceptedResponse + '400': + $ref: common.yaml#/components/responses/400BadRequest + '401': + $ref: common.yaml#/components/responses/401Unauthorized + '403': + $ref: common.yaml#/components/responses/403Forbidden + '404': + $ref: common.yaml#/components/responses/404NotFound + '405': + $ref: common.yaml#/components/responses/405MethodNotAllowed + '500': + $ref: common.yaml#/components/responses/500InternalServerError + '503': + $ref: common.yaml#/components/responses/503ServiceUnavailable + '504': + $ref: common.yaml#/components/responses/504GatewayTimeout + delete: + parameters: + - $ref: common.yaml#/components/parameters/database + - $ref: common.yaml#/components/parameters/schema + - $ref: common.yaml#/components/parameters/name + - $ref: common.yaml#/components/parameters/ifExists + summary: Delete a service + tags: + - service + description: Delete a service with the given name. If ifExists is used, the + operation will succeed even if the object does not exist. Otherwise, there + will be a failure if the drop is unsuccessful. + operationId: deleteService + responses: + '200': + $ref: common.yaml#/components/responses/200SuccessResponse + '202': + $ref: common.yaml#/components/responses/202SuccessAcceptedResponse + '400': + $ref: common.yaml#/components/responses/400BadRequest + '401': + $ref: common.yaml#/components/responses/401Unauthorized + '403': + $ref: common.yaml#/components/responses/403Forbidden + '404': + $ref: common.yaml#/components/responses/404NotFound + '405': + $ref: common.yaml#/components/responses/405MethodNotAllowed + '429': + $ref: common.yaml#/components/responses/429LimitExceeded + '500': + $ref: common.yaml#/components/responses/500InternalServerError + '503': + $ref: common.yaml#/components/responses/503ServiceUnavailable + '504': + $ref: common.yaml#/components/responses/504GatewayTimeout + /api/v2/databases/{database}/schemas/{schema}/services/{name}/logs: + get: + description: Fetch the logs for a given service. + tags: + - service + operationId: fetchServiceLogs + parameters: + - $ref: common.yaml#/components/parameters/database + - $ref: common.yaml#/components/parameters/schema + - $ref: common.yaml#/components/parameters/name + - in: query + name: instanceId + description: ID of the service instance, starting with 0. + required: true + schema: + type: integer + - in: query + name: containerName + description: Container name as specified in the service specification file. + required: true + schema: + type: string + - in: query + name: numLines + schema: + type: integer + description: Number of trailing log lines to retrieve. + responses: + '200': + description: successful + headers: + X-Snowflake-Request-ID: + $ref: common.yaml#/components/headers/X-Snowflake-Request-ID + Link: + $ref: common.yaml#/components/headers/Link + content: + application/json: + schema: + type: object + properties: + system$get_service_logs: + type: string + '202': + $ref: common.yaml#/components/responses/202SuccessAcceptedResponse + '400': + $ref: common.yaml#/components/responses/400BadRequest + '401': + $ref: common.yaml#/components/responses/401Unauthorized + '403': + $ref: common.yaml#/components/responses/403Forbidden + '404': + $ref: common.yaml#/components/responses/404NotFound + '405': + $ref: common.yaml#/components/responses/405MethodNotAllowed + '429': + $ref: common.yaml#/components/responses/429LimitExceeded + '500': + $ref: common.yaml#/components/responses/500InternalServerError + '503': + $ref: common.yaml#/components/responses/503ServiceUnavailable + '504': + $ref: common.yaml#/components/responses/504GatewayTimeout + /api/v2/databases/{database}/schemas/{schema}/services/{name}/status: + get: + deprecated: true + description: Fetch the status for a given service. Deprecated - use listServiceContainers + instead. + tags: + - service + operationId: fetchServiceStatus + parameters: + - $ref: common.yaml#/components/parameters/database + - $ref: common.yaml#/components/parameters/schema + - $ref: common.yaml#/components/parameters/name + - in: query + name: timeout + schema: + type: integer + description: Number of seconds to wait for the service to reach a steady state + (for example, READY) before returning the status. If the service does not + reach a steady state within the specified time, Snowflake returns the current + state. + responses: + '200': + description: successful + headers: + X-Snowflake-Request-ID: + $ref: common.yaml#/components/headers/X-Snowflake-Request-ID + Link: + $ref: common.yaml#/components/headers/Link + content: + application/json: + schema: + type: object + properties: + system$get_service_status: + type: string + '202': + $ref: common.yaml#/components/responses/202SuccessAcceptedResponse + '400': + $ref: common.yaml#/components/responses/400BadRequest + '401': + $ref: common.yaml#/components/responses/401Unauthorized + '403': + $ref: common.yaml#/components/responses/403Forbidden + '404': + $ref: common.yaml#/components/responses/404NotFound + '405': + $ref: common.yaml#/components/responses/405MethodNotAllowed + '429': + $ref: common.yaml#/components/responses/429LimitExceeded + '500': + $ref: common.yaml#/components/responses/500InternalServerError + '503': + $ref: common.yaml#/components/responses/503ServiceUnavailable + '504': + $ref: common.yaml#/components/responses/504GatewayTimeout + /api/v2/databases/{database}/schemas/{schema}/services/{name}/containers: + get: + description: List all the containers of the service + tags: + - service + operationId: listServiceContainers + parameters: + - $ref: common.yaml#/components/parameters/database + - $ref: common.yaml#/components/parameters/schema + - $ref: common.yaml#/components/parameters/name + responses: + '200': + description: successful + headers: + X-Snowflake-Request-ID: + $ref: common.yaml#/components/headers/X-Snowflake-Request-ID + Link: + $ref: common.yaml#/components/headers/Link + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ServiceContainer' + '202': + $ref: common.yaml#/components/responses/202SuccessAcceptedResponse + '400': + $ref: common.yaml#/components/responses/400BadRequest + '401': + $ref: common.yaml#/components/responses/401Unauthorized + '403': + $ref: common.yaml#/components/responses/403Forbidden + '404': + $ref: common.yaml#/components/responses/404NotFound + '405': + $ref: common.yaml#/components/responses/405MethodNotAllowed + '429': + $ref: common.yaml#/components/responses/429LimitExceeded + '500': + $ref: common.yaml#/components/responses/500InternalServerError + '503': + $ref: common.yaml#/components/responses/503ServiceUnavailable + '504': + $ref: common.yaml#/components/responses/504GatewayTimeout + /api/v2/databases/{database}/schemas/{schema}/services/{name}/instances: + get: + description: List all the instances of the service + tags: + - service + operationId: listServiceInstances + parameters: + - $ref: common.yaml#/components/parameters/database + - $ref: common.yaml#/components/parameters/schema + - $ref: common.yaml#/components/parameters/name + responses: + '200': + description: successful + headers: + X-Snowflake-Request-ID: + $ref: common.yaml#/components/headers/X-Snowflake-Request-ID + Link: + $ref: common.yaml#/components/headers/Link + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ServiceInstance' + '202': + $ref: common.yaml#/components/responses/202SuccessAcceptedResponse + '400': + $ref: common.yaml#/components/responses/400BadRequest + '401': + $ref: common.yaml#/components/responses/401Unauthorized + '403': + $ref: common.yaml#/components/responses/403Forbidden + '404': + $ref: common.yaml#/components/responses/404NotFound + '405': + $ref: common.yaml#/components/responses/405MethodNotAllowed + '429': + $ref: common.yaml#/components/responses/429LimitExceeded + '500': + $ref: common.yaml#/components/responses/500InternalServerError + '503': + $ref: common.yaml#/components/responses/503ServiceUnavailable + '504': + $ref: common.yaml#/components/responses/504GatewayTimeout + /api/v2/databases/{database}/schemas/{schema}/services/{name}/roles: + get: + description: List all the service roles of the service + tags: + - service + operationId: listServiceRoles + parameters: + - $ref: common.yaml#/components/parameters/database + - $ref: common.yaml#/components/parameters/schema + - $ref: common.yaml#/components/parameters/name + responses: + '200': + description: successful + headers: + X-Snowflake-Request-ID: + $ref: common.yaml#/components/headers/X-Snowflake-Request-ID + Link: + $ref: common.yaml#/components/headers/Link + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ServiceRole' + '202': + $ref: common.yaml#/components/responses/202SuccessAcceptedResponse + '400': + $ref: common.yaml#/components/responses/400BadRequest + '401': + $ref: common.yaml#/components/responses/401Unauthorized + '403': + $ref: common.yaml#/components/responses/403Forbidden + '404': + $ref: common.yaml#/components/responses/404NotFound + '405': + $ref: common.yaml#/components/responses/405MethodNotAllowed + '429': + $ref: common.yaml#/components/responses/429LimitExceeded + '500': + $ref: common.yaml#/components/responses/500InternalServerError + '503': + $ref: common.yaml#/components/responses/503ServiceUnavailable + '504': + $ref: common.yaml#/components/responses/504GatewayTimeout + /api/v2/databases/{database}/schemas/{schema}/services/{service}/roles/{name}/grants-of: + get: + description: List all the grants of the service role + tags: + - service + operationId: listServiceRoleGrantsOf + parameters: + - $ref: common.yaml#/components/parameters/database + - $ref: common.yaml#/components/parameters/schema + - $ref: '#/components/parameters/service' + - $ref: common.yaml#/components/parameters/name + responses: + '200': + description: successful + headers: + X-Snowflake-Request-ID: + $ref: common.yaml#/components/headers/X-Snowflake-Request-ID + Link: + $ref: common.yaml#/components/headers/Link + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/GrantOf' + '202': + $ref: common.yaml#/components/responses/202SuccessAcceptedResponse + '400': + $ref: common.yaml#/components/responses/400BadRequest + '401': + $ref: common.yaml#/components/responses/401Unauthorized + '403': + $ref: common.yaml#/components/responses/403Forbidden + '404': + $ref: common.yaml#/components/responses/404NotFound + '405': + $ref: common.yaml#/components/responses/405MethodNotAllowed + '429': + $ref: common.yaml#/components/responses/429LimitExceeded + '500': + $ref: common.yaml#/components/responses/500InternalServerError + '503': + $ref: common.yaml#/components/responses/503ServiceUnavailable + '504': + $ref: common.yaml#/components/responses/504GatewayTimeout + /api/v2/databases/{database}/schemas/{schema}/services/{service}/roles/{name}/grants: + get: + description: List all the grants given to the service role + tags: + - service + operationId: listServiceRoleGrantsTo + parameters: + - $ref: common.yaml#/components/parameters/database + - $ref: common.yaml#/components/parameters/schema + - $ref: '#/components/parameters/service' + - $ref: common.yaml#/components/parameters/name + responses: + '200': + description: successful + headers: + X-Snowflake-Request-ID: + $ref: common.yaml#/components/headers/X-Snowflake-Request-ID + Link: + $ref: common.yaml#/components/headers/Link + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ServiceRoleGrantTo' + '202': + $ref: common.yaml#/components/responses/202SuccessAcceptedResponse + '400': + $ref: common.yaml#/components/responses/400BadRequest + '401': + $ref: common.yaml#/components/responses/401Unauthorized + '403': + $ref: common.yaml#/components/responses/403Forbidden + '404': + $ref: common.yaml#/components/responses/404NotFound + '405': + $ref: common.yaml#/components/responses/405MethodNotAllowed + '429': + $ref: common.yaml#/components/responses/429LimitExceeded + '500': + $ref: common.yaml#/components/responses/500InternalServerError + '503': + $ref: common.yaml#/components/responses/503ServiceUnavailable + '504': + $ref: common.yaml#/components/responses/504GatewayTimeout + /api/v2/databases/{database}/schemas/{schema}/services/{name}:resume: + post: + description: Resume a service. + tags: + - service + operationId: resumeService + parameters: + - $ref: common.yaml#/components/parameters/database + - $ref: common.yaml#/components/parameters/schema + - $ref: common.yaml#/components/parameters/name + - $ref: common.yaml#/components/parameters/ifExists + responses: + '200': + $ref: common.yaml#/components/responses/200SuccessResponse + '202': + $ref: common.yaml#/components/responses/202SuccessAcceptedResponse + '400': + $ref: common.yaml#/components/responses/400BadRequest + '401': + $ref: common.yaml#/components/responses/401Unauthorized + '403': + $ref: common.yaml#/components/responses/403Forbidden + '404': + $ref: common.yaml#/components/responses/404NotFound + '405': + $ref: common.yaml#/components/responses/405MethodNotAllowed + '429': + $ref: common.yaml#/components/responses/429LimitExceeded + '500': + $ref: common.yaml#/components/responses/500InternalServerError + '503': + $ref: common.yaml#/components/responses/503ServiceUnavailable + '504': + $ref: common.yaml#/components/responses/504GatewayTimeout + /api/v2/databases/{database}/schemas/{schema}/services/{name}:suspend: + post: + description: Suspend a service. + tags: + - service + operationId: suspendService + parameters: + - $ref: common.yaml#/components/parameters/database + - $ref: common.yaml#/components/parameters/schema + - $ref: common.yaml#/components/parameters/name + - $ref: common.yaml#/components/parameters/ifExists + responses: + '200': + $ref: common.yaml#/components/responses/200SuccessResponse + '202': + $ref: common.yaml#/components/responses/202SuccessAcceptedResponse + '400': + $ref: common.yaml#/components/responses/400BadRequest + '401': + $ref: common.yaml#/components/responses/401Unauthorized + '403': + $ref: common.yaml#/components/responses/403Forbidden + '404': + $ref: common.yaml#/components/responses/404NotFound + '405': + $ref: common.yaml#/components/responses/405MethodNotAllowed + '429': + $ref: common.yaml#/components/responses/429LimitExceeded + '500': + $ref: common.yaml#/components/responses/500InternalServerError + '503': + $ref: common.yaml#/components/responses/503ServiceUnavailable + '504': + $ref: common.yaml#/components/responses/504GatewayTimeout + /api/v2/databases/{database}/schemas/{schema}/services/{name}/endpoints: + get: + summary: List the endpoints in a service. + description: Lists the endpoints in a Snowpark Container Services service (or + a job service). + tags: + - service + operationId: showServiceEndpoints + parameters: + - $ref: common.yaml#/components/parameters/database + - $ref: common.yaml#/components/parameters/schema + - $ref: common.yaml#/components/parameters/name + responses: + '200': + description: successful + headers: + X-Snowflake-Request-ID: + $ref: common.yaml#/components/headers/X-Snowflake-Request-ID + Link: + $ref: common.yaml#/components/headers/Link + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ServiceEndpoint' + '202': + $ref: common.yaml#/components/responses/202SuccessAcceptedResponse + '400': + $ref: common.yaml#/components/responses/400BadRequest + '401': + $ref: common.yaml#/components/responses/401Unauthorized + '403': + $ref: common.yaml#/components/responses/403Forbidden + '404': + $ref: common.yaml#/components/responses/404NotFound + '405': + $ref: common.yaml#/components/responses/405MethodNotAllowed + '429': + $ref: common.yaml#/components/responses/429LimitExceeded + '500': + $ref: common.yaml#/components/responses/500InternalServerError + '503': + $ref: common.yaml#/components/responses/503ServiceUnavailable + '504': + $ref: common.yaml#/components/responses/504GatewayTimeout +components: + parameters: + service: + name: service + description: Name of the service that contains the service role. + required: true + in: path + schema: + $ref: ./common.yaml#/components/schemas/Identifier + schemas: + ServiceSpecInlineText: + description: Specifies service specification with inline text. + allOf: + - $ref: '#/components/schemas/ServiceSpec' + properties: + spec_text: + type: string + description: Specifies service specification. You can use a pair of dollar + signs ($$) to delimit the beginning and ending of the specification string. + required: + - spec_text + ServiceSpecStageFile: + description: Specifies service specification with a stage file. + allOf: + - $ref: '#/components/schemas/ServiceSpec' + properties: + stage: + type: string + description: Specifies the Snowflake internal stage where the specification + file is stored; for example, @tutorial_stage. + spec_file: + type: string + description: Specifies the path to the service specification file on the + stage; for example, 'some-dir/echo_spec.yaml'. + required: + - stage + - spec_file + ServiceSpec: + type: object + description: Specifies service specification. + properties: + spec_type: + type: string + description: Type of the service specification, can be `from_file` or `from_inline`. + discriminator: + propertyName: spec_type + mapping: + from_file: ServiceSpecStageFile + from_inline: ServiceSpecInlineText + writeOnly: true + Service: + allOf: + - $ref: '#/components/schemas/JobService' + - type: object + description: A Snowflake service object. + properties: + auto_resume: + type: boolean + description: Specifies whether to automatically resume a service when + a service function or ingress is called. + current_instances: + type: integer + description: The current number of instances for the service. + readOnly: true + target_instances: + type: integer + description: The target number of service instances that should be running + as determined by Snowflake. + readOnly: true + min_ready_instances: + type: integer + description: The minimum number of ready service instances to declare + the service as READY. + min_instances: + type: integer + description: Specifies the minimum number of service instances to run. + max_instances: + type: integer + description: Specifies the maximum number of service instances to run. + database_name: + $ref: ./common.yaml#/components/schemas/Identifier + description: The name of the parent database for the service. + readOnly: true + schema_name: + $ref: ./common.yaml#/components/schemas/Identifier + description: The name of the parent schema for the service. + readOnly: true + owner: + type: string + description: Role that owns the service. + readOnly: true + dns_name: + type: string + description: Snowflake-assiged DNS name of the service. The DNS name enables + service-to-service communications. + readOnly: true + created_on: + type: string + description: Timestamp when the service was created. + format: date-time + readOnly: true + updated_on: + type: string + description: Timestamp when the service was last updated. + format: date-time + readOnly: true + resumed_on: + type: string + description: Timestamp when the service was last resumed. + format: date-time + readOnly: true + suspended_on: + type: string + description: Timestamp when the service was last suspended. + format: date-time + readOnly: true + auto_suspend_secs: + type: integer + description: Number of seconds of inactivity after which the service will + be automatically suspended. The default value is 0 which represents + the service will not be automatically suspended. + format: int64 + owner_role_type: + type: string + description: The role type of the service owner. + readOnly: true + is_job: + type: boolean + description: True if the service is a job service; false otherwise. + readOnly: true + spec_digest: + type: string + description: The unique and immutable identifier representing the service + spec content. + readOnly: true + is_upgrading: + type: boolean + description: TRUE, if Snowflake is in the process of upgrading the service. + readOnly: true + managing_object_domain: + type: string + description: The domain of the managing object (for example, the domain + of the notebook that manages the service). NULL if the service is not + managed by a Snowflake entity. + readOnly: true + managing_object_name: + type: string + description: The name of the managing object (for example, the name of + the notebook that manages the service). NULL if the service is not managed + by a Snowflake entity. + readOnly: true + example: + min_ready_instances: 1 + min_instances: 2 + max_instances: 5 + database_name: testdb + schema_name: testschema + owner: SYSADMIN + is_job: false + JobService: + type: object + description: A Snowflake job service object. + writeOnly: true + properties: + name: + $ref: ./common.yaml#/components/schemas/Identifier + description: String that specifies the identifier (that is, the name) for + the service. + status: + type: string + description: The current status of the service. + compute_pool: + type: string + description: Specifies the name of the compute pool in your account on which + to run the service. + spec: + $ref: '#/components/schemas/ServiceSpec' + description: Specifies service specification. + external_access_integrations: + type: array + description: Specifies the names of the external access integrations that + allow your service to access external sites. + items: + type: string + query_warehouse: + $ref: ./common.yaml#/components/schemas/Identifier + description: Warehouse to use if a service container connects to Snowflake + to execute a query but does not explicitly specify a warehouse to use. + comment: + type: string + description: Specifies a comment for the service. + is_async_job: + type: boolean + description: True if the service is an async job service; false otherwise. + required: + - name + - compute_pool + - spec + example: + name: service_name + compute_pool: compute_pool_name + spec: + spec_type: from_file + stage: '@stage_name' + spec_file: spec_file.yaml + ServiceEndpoint: + type: object + properties: + name: + type: string + description: User-friendly endpoint name that represents the corresponding + port. + port: + type: integer + description: The network port the service is listening on. NULL, when portRange + is specified. + portRange: + type: string + description: The network port range the service is listening on. NULL, when + port is specified. + protocol: + type: string + description: Supported network protocol (TCP, HTTP, or HTTPS). + default: HTTP + is_public: + type: boolean + description: True, if the endpoint is public, accessible from internet. + default: false + ingress_url: + type: string + description: Endpoint URL accessible from the internet. + readOnly: true + example: + name: endpoint + port: 8080 + protocol: HTTPS + is_public: true + ingress_url: abcd-org-acc.snowflakecomputing.app + ServiceContainer: + type: object + properties: + database_name: + $ref: ./common.yaml#/components/schemas/Identifier + description: Database in which the service is created. + readOnly: true + schema_name: + $ref: ./common.yaml#/components/schemas/Identifier + description: Schema in which the service is created. + readOnly: true + service_name: + $ref: ./common.yaml#/components/schemas/Identifier + description: The name of the service. + readOnly: true + service_status: + type: string + description: The current status of the service. + readOnly: true + instance_id: + type: string + description: ID of the service instance (this is the index of the service + instance starting from 0). + readOnly: true + instance_status: + type: string + description: The current status of the service instance. + readOnly: true + container_name: + type: string + description: Name of the container. + readOnly: true + status: + type: string + description: Service container status. + readOnly: true + message: + type: string + description: Additional clarification about status. + readOnly: true + image_name: + type: string + description: Image name used to create the service container. + readOnly: true + image_digest: + type: string + description: The unique and immutable identifier representing the image + content. + readOnly: true + restart_count: + type: integer + description: Number of times Snowflake restarted the service. + readOnly: true + start_time: + type: string + description: Date and time when the container started. + readOnly: true + example: + database_name: testdb + schema_name: testschema + service_name: myservice + instance_id: '0' + container_name: main + status: PENDING + message: Pending scheduling. + image_name: /db/schema/repo/image:1.0 + image_digest: abcdefd + restart_count: 0 + start_time: 2023-01-01 00:00:00+00:00 + ServiceInstance: + type: object + properties: + database_name: + $ref: ./common.yaml#/components/schemas/Identifier + description: Database in which the service is created. + readOnly: true + schema_name: + $ref: ./common.yaml#/components/schemas/Identifier + description: Schema in which the service is created. + readOnly: true + service_name: + $ref: ./common.yaml#/components/schemas/Identifier + description: The name of the service. + readOnly: true + service_status: + type: string + description: The current status of the service. + readOnly: true + instance_id: + type: string + description: ID of the service instance (this is the index of the service + instance starting from 0). + readOnly: true + status: + type: string + description: The current status of the service instance. + readOnly: true + spec_digest: + type: string + description: The unique and immutable identifier that represents the service + specification content. + readOnly: true + creation_time: + type: string + description: The time when Snowflake started creating the service instance. + readOnly: true + start_time: + type: string + description: The time when Snowflake acknowledged the service instance is + running on a node. + readOnly: true + example: + database_name: testdb + schema_name: testschema + service_name: myservice + instance_id: '0' + status: PENDING + spec_digest: abcdefg + creation_time: 2023-01-01 00:00:00+00:00 + start_time: 2023-01-01 00:00:00+00:00 + ServiceRole: + type: object + properties: + created_on: + type: string + format: date-time + description: Date and time when the service role was created + readOnly: true + name: + type: string + description: Service role name + readOnly: true + comment: + type: string + description: Comment, if any, for the service role + readOnly: true + example: + created_on: 2023-01-01 00:00:00+00:00 + name: testrole + comment: This is a service role. + GrantOf: + type: object + properties: + created_on: + type: string + format: date-time + readOnly: true + description: Date and time when the grant was created + role: + type: string + readOnly: true + description: The name of the service role + granted_to: + type: string + readOnly: true + description: The type of the grantee, can be USER or ROLE + grantee_name: + type: string + readOnly: true + description: The name of the grantee + granted_by: + type: string + readOnly: true + description: The name of role that granted the service role to the grantee + example: + created_on: 2023-01-01 00:00:00+00:00 + role: db.schema.service.svc_role + granted_to: role + grantee_name: test_role + granted_by: sysadmin + ServiceRoleGrantTo: + type: object + properties: + created_on: + type: string + format: date-time + readOnly: true + description: Date and time when the grant was created + privilege: + type: string + readOnly: true + description: The name of the privilege + granted_on: + type: string + readOnly: true + description: The type of of the securable + name: + type: string + readOnly: true + description: The name of the securable + granted_to: + type: string + readOnly: true + description: The type of the grantee + grantee_name: + type: string + readOnly: true + description: The name of the grantee + example: + created_on: 2023-01-01 00:00:00+00:00 + privilege: usage + granted_on: service_endpoint + name: db.schema.service!svc_role + granted_to: service role + grantee_name: all_endpoints_usage + securitySchemes: + KeyPair: + $ref: common.yaml#/components/securitySchemes/KeyPair + ExternalOAuth: + $ref: common.yaml#/components/securitySchemes/ExternalOAuth + SnowflakeOAuth: + $ref: common.yaml#/components/securitySchemes/SnowflakeOAuth +security: +- KeyPair: [] +- ExternalOAuth: [] +- SnowflakeOAuth: [] diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client-code-generation/specifications/sqlapi.yaml b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client-code-generation/specifications/sqlapi.yaml new file mode 100644 index 00000000..04d62acc --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client-code-generation/specifications/sqlapi.yaml @@ -0,0 +1,795 @@ +openapi: 3.0.0 +servers: +- description: Snowflake SQL API V2 + url: https://org-account.snowflakecomputing.com +info: + version: 2.0.0 + title: Snowflake SQL API + description: 'The Snowflake SQL API is a REST API that you can use to access and + update data in a Snowflake database. ' + contact: + name: Snowflake, Inc. + url: https://snowflake.com + email: support@snowflake.com +paths: + /api/v2/statements: + parameters: + - $ref: '#/components/parameters/requestId' + - $ref: '#/components/parameters/async' + - $ref: '#/components/parameters/nullable' + - $ref: '#/components/parameters/accept' + - $ref: '#/components/parameters/userAgent' + - $ref: '#/components/parameters/snowflakeAuthorizationTokenType' + post: + operationId: SubmitStatement + summary: Submits a SQL statement for execution. + description: Submits one or more statements for execution. You can specify that + the statement should be executed asynchronously. + tags: + - statements + security: + - KeyPair: [] + - ExternalOAuth: [] + - SnowflakeOAuth: [] + requestBody: + required: true + description: Specifies the SQL statement to execute and the statement context. + content: + application/json: + schema: + type: object + properties: + statement: + description: 'SQL statement or batch of SQL statements to execute. + You can specify query, DML and DDL statements. The following statements + are not supported: PUT, GET, USE, ALTER SESSION, BEGIN, COMMIT, + ROLLBACK, statements that set session variables, and statements + that create temporary tables and stages.' + type: string + timeout: + description: Timeout in seconds for statement execution. If the + execution of a statement takes longer than the specified timeout, + the execution is automatically canceled. To set the timeout to + the maximum value (604800 seconds), set timeout to 0. + type: integer + format: int64 + minimum: 0 + example: 10 + database: + description: Database in which the statement should be executed. + The value in this field is case-sensitive. + type: string + example: TESTDB + schema: + description: Schema in which the statement should be executed. The + value in this field is case-sensitive. + type: string + example: TESTSCHEMA + warehouse: + description: Warehouse to use when executing the statement. The + value in this field is case-sensitive. + type: string + example: TESTWH + role: + description: Role to use when executing the statement. The value + in this field is case-sensitive. + type: string + example: TESTROLE + bindings: + description: Values of bind variables in the SQL statement. When + executing the statement, Snowflake replaces placeholders ('?' + and ':name') in the statement with these specified values. + type: object + properties: {} + example: + '1': + type: FIXED + value: '123' + '2': + type: TEXT + value: teststring + parameters: + description: Session parameters that should be set before executing + the statement. + type: object + properties: + timezone: + description: Time zone to use when executing the statement. + type: string + example: america/los_angeles + query_tag: + description: Query tag that you want to associate with the SQL + statement. + type: string + example: tag-1234 + binary_output_format: + description: Output format for binary values. + type: string + example: HEX + date_output_format: + description: Output format for DATE values. + type: string + example: YYYY-MM-DD + time_output_format: + description: Output format for TIME values. + type: string + example: HH24:MI:SS.FF6 + timestamp_output_format: + description: Output format for TIMESTAMP values. + type: string + example: YYYY-MM-DDTHH24:MI:SS.FF6 + timestamp_ltz_output_format: + description: Output format for TIMESTAMP_LTZ values. + type: string + example: YYYY-MM-DDTHH24:MI:SS.FF6 + timestamp_ntz_output_format: + description: Output format for TIMESTAMP_NTZ values. + type: string + example: YYYY-MM-DDTHH24:MI:SS.FF6 + timestamp_tz_output_format: + description: Output format for TIMESTAMP_TZ values. + type: string + example: YYYY-MM-DDTHH24:MI:SS.FF6 TZHTZM + multi_statement_count: + description: Number of statements to execute when using multi-statement + capability. 0 implies variable number of statements. Negative + numbers are not allowed. + type: integer + example: 4 + default: 1 + example: + statement: select * from T where c1=? + timeout: 10 + database: TESTDB + schema: TESTSCHEMA + warehouse: TESTWH + bindings: + '1': + type: FIXED + value: '123' + responses: + '200': + description: The statement was executed successfully, and the response includes + any data requested. + content: + application/json: + schema: + $ref: '#/components/schemas/ResultSet' + headers: + link: + $ref: '#/components/headers/Link' + links: + GetStatementStatus: + operationId: GetStatementStatus + parameters: + statementHandle: $response.body#/resultMetaData.statementHandle + CancelStatement: + operationId: CancelStatement + parameters: + statementHandle: $response.body#/resultMetaData.statementHandle + '202': + description: The execution of the statement is still in progress. Use GET + /statements/ and specify the statement handle to check the status of the + statement execution. + content: + application/json: + schema: + $ref: '#/components/schemas/QueryStatus' + '400': + $ref: '#/components/responses/400BadRequest' + '401': + $ref: '#/components/responses/401Unauthorized' + '403': + $ref: '#/components/responses/403Forbidden' + '404': + $ref: '#/components/responses/404NotFound' + '405': + $ref: '#/components/responses/405MethodNotAllowed' + '408': + description: The execution of the statement exceeded the timeout period. + The execution of the statement was cancelled. + content: + application/json: + schema: + $ref: '#/components/schemas/QueryStatus' + '415': + $ref: '#/components/responses/415UnsupportedMediaType' + '422': + description: An error occurred when executing the statement. Check the error + code and error message for details. + content: + application/json: + schema: + $ref: '#/components/schemas/QueryFailureStatus' + '429': + $ref: '#/components/responses/429LimitExceeded' + '500': + $ref: '#/components/responses/500InternalServerError' + '503': + $ref: '#/components/responses/503ServiceUnavailable' + '504': + $ref: '#/components/responses/504GatewayTimeout' + /api/v2/statements/{statementHandle}: + parameters: + - $ref: '#/components/parameters/statementHandle' + - $ref: '#/components/parameters/requestId' + - $ref: '#/components/parameters/partition' + - $ref: '#/components/parameters/accept' + - $ref: '#/components/parameters/userAgent' + - $ref: '#/components/parameters/snowflakeAuthorizationTokenType' + get: + operationId: GetStatementStatus + summary: Checks the status of the execution of a statement + description: Checks the status of the execution of the statement with the specified + statement handle. If the statement was executed successfully, the operation + returns the requested partition of the result set. + tags: + - statements + security: + - KeyPair: [] + - ExternalOAuth: [] + - SnowflakeOAuth: [] + responses: + '200': + description: The statement was executed successfully, and the response includes + any data requested. + headers: + link: + $ref: '#/components/headers/Link' + content: + application/json: + schema: + $ref: '#/components/schemas/ResultSet' + '202': + description: The execution of the statement is still in progress. Use this + method again to check the status of the statement execution. + content: + application/json: + schema: + $ref: '#/components/schemas/QueryStatus' + '400': + $ref: '#/components/responses/400BadRequest' + '401': + $ref: '#/components/responses/401Unauthorized' + '403': + $ref: '#/components/responses/403Forbidden' + '404': + $ref: '#/components/responses/404NotFound' + '405': + $ref: '#/components/responses/405MethodNotAllowed' + '415': + $ref: '#/components/responses/415UnsupportedMediaType' + '422': + description: An error occurred when executing the statement. Check the error + code and error message for details. + content: + application/json: + schema: + $ref: '#/components/schemas/QueryFailureStatus' + '429': + $ref: '#/components/responses/429LimitExceeded' + '500': + $ref: '#/components/responses/500InternalServerError' + '503': + $ref: '#/components/responses/503ServiceUnavailable' + '504': + $ref: '#/components/responses/504GatewayTimeout' + /api/v2/statements/{statementHandle}/cancel: + parameters: + - $ref: '#/components/parameters/statementHandle' + - $ref: '#/components/parameters/requestId' + - $ref: '#/components/parameters/accept' + - $ref: '#/components/parameters/userAgent' + - $ref: '#/components/parameters/snowflakeAuthorizationTokenType' + post: + operationId: CancelStatement + summary: Cancels the execution of a statement. + security: + - KeyPair: [] + - ExternalOAuth: [] + - SnowflakeOAuth: [] + description: Cancels the execution of the statement with the specified statement + handle. + tags: + - statements + responses: + '200': + description: The execution of the statement was successfully canceled. + content: + application/json: + schema: + $ref: '#/components/schemas/CancelStatus' + '400': + $ref: '#/components/responses/400BadRequest' + '401': + $ref: '#/components/responses/401Unauthorized' + '403': + $ref: '#/components/responses/403Forbidden' + '404': + $ref: '#/components/responses/404NotFound' + '405': + $ref: '#/components/responses/405MethodNotAllowed' + '422': + description: An error occurred when cancelling the execution of the statement. + Check the error code and error message for details. + content: + application/json: + schema: + $ref: '#/components/schemas/CancelStatus' + '500': + $ref: '#/components/responses/500InternalServerError' + '503': + $ref: '#/components/responses/503ServiceUnavailable' + '504': + $ref: '#/components/responses/504GatewayTimeout' +components: + schemas: + QueryStatus: + type: object + properties: + code: + type: string + sqlState: + type: string + message: + type: string + statementHandle: + type: string + format: uuid + createdOn: + type: integer + format: int64 + description: Timestamp that specifies when the statement execution started. + The timestamp is expressed in milliseconds since the epoch. + example: 1597090533987 + statementStatusUrl: + type: string + format: uri + description: URL that you can use to check the status of the execution of + the statement and the result set. + required: + - statementHandle + example: + code: '000000' + sqlState: '00000' + message: successfully executed + statementHandle: e4ce975e-f7ff-4b5e-b15e-bf25f59371ae + createdOn: 1597090533987 + QueryFailureStatus: + type: object + properties: + code: + type: string + sqlState: + type: string + message: + type: string + statementHandle: + type: string + format: uuid + createdOn: + type: integer + format: int64 + description: "Timestamp that specifies when the statement execution started.\u200C\ + \ The timestamp is expressed in milliseconds since the epoch." + example: 1597090533987 + statementStatusUrl: + type: string + format: uri + required: + - message + - statementHandle + example: + code: '000123' + sqlState: '42601' + message: SQL compilation error + statementHandle: e4ce975e-f7ff-4b5e-b15e-bf25f59371ae + createdOn: 1597090533987 + CancelStatus: + type: object + properties: + code: + type: string + sqlState: + type: string + message: + type: string + statementHandle: + type: string + format: uuid + statementStatusUrl: + type: string + format: uri + required: + - statementHandle + example: + message: successfully canceled + statementHandle: 536fad38-b564-4dc5-9892-a4543504df6c + ResultSet: + type: object + properties: + code: + type: string + example: '000123' + sqlState: + type: string + example: '42601' + message: + type: string + example: successfully executed + statementHandle: + type: string + format: uuid + example: 536fad38-b564-4dc5-9892-a4543504df6c + createdOn: + type: integer + format: int64 + description: "Timestamp that specifies when the statement execution started.\u200C\ + \ The timestamp is expressed in milliseconds since the epoch.\u200C" + example: 1597090533987 + statementStatusUrl: + type: string + format: uri + resultSetMetaData: + type: object + properties: + format: + type: string + enum: + - jsonv2 + description: For v2 endpoints the only possible value for this field + is jsonv2. + example: jsonv2 + numRows: + type: integer + format: int64 + description: The total number of rows of results. + example: 100 + rowType: + type: array + minItems: 1 + items: + type: object + properties: + name: + type: string + type: + type: string + length: + type: integer + format: int64 + minimum: 0 + precision: + type: integer + format: int64 + minimum: 0 + scale: + type: integer + format: int64 + minimum: 0 + nullable: + type: boolean + example: + - name: ROWNUM + type: FIXED + length: 0 + precision: 38 + scale: 0 + nullable: false + - name: ACCOUNT_ID + type: FIXED + length: 0 + precision: 38 + scale: 0 + nullable: false + - name: ACCOUNT_NAME + type: TEXT + length: 1024 + precision: 0 + scale: 0 + nullable: false + - name: ADDRESS + type: TEXT + length: 16777216 + precision: 0 + scale: 0 + nullable: true + - name: ZIP + type: TEXT + length: 100 + precision: 0 + scale: 0 + nullable: true + - name: CREATED_ON + type: TIMESTAMP_NTZ + length: 0 + precision: 0 + scale: 3 + nullable: false + partitionInfo: + description: Partition information + type: array + minItems: 0 + items: + type: object + properties: + rowCount: + type: integer + format: int64 + description: Number of rows in the partition. + minimum: 0 + example: 1324 + compressedSize: + type: integer + format: int64 + description: the partition size before the decompression. This + may or may not be present in the partitionInfo. Uncompressed + size would always be there. + minimum: 0 + example: 37436824 + uncompressedSize: + type: integer + format: int64 + description: the partition size after the decompression + minimum: 0 + example: 1343787384 + nullable: + description: false if null is replaced with a string 'null' otherwise + false + type: boolean + parameters: + type: object + properties: + binary_output_format: + type: string + example: HEX + date_output_format: + type: string + example: YYYY-MM-DD + time_output_format: + type: string + example: HH24:MI:SS + timestamp_output_format: + type: string + example: YYYY-MM-DD HH24:MI:SS.FF6 + timestamp_ltz_output_format: + type: string + example: YYYY-MM-DD HH24:MI:SS.FF6 + timestamp_ntz_output_format: + type: string + example: YYYY-MM-DD HH24:MI:SS.FF6 + timestamp_tz_output_format: + type: string + example: YYYY-MM-DDTHH24:MI:SS.FF6 TZHTZM + multi_statement_count: + type: integer + example: 4 + data: + description: Result set data. + type: array + minItems: 0 + items: + type: array + minItems: 0 + items: + type: string + nullable: true + minItems: 0 + example: + - - customer1 + - 1234 A Avenue + - '98765' + - '2019-08-10 23:56:34.123' + - - customer2 + - 987 B Street + - '98765' + - '2019-08-11 09:45:12.890' + - - customer3 + - 8777 C Blvd + - '98765' + - '2019-08-12 10:23:51.999' + - - customer4 + - 64646 D Circle + - '98765' + - '2019-08-13 01:54:32.000' + stats: + type: object + description: these stats might not be available for each request. + properties: + numRowsInserted: + type: integer + format: int64 + description: Number of rows that were inserted. + minimum: 0 + example: 12 + numRowsUpdated: + type: integer + format: int64 + description: Number of rows that were updated. + minimum: 0 + example: 9 + numRowsDeleted: + type: integer + format: int64 + description: Number of rows that were deleted. + minimum: 0 + example: 8 + numDuplicateRowsUpdated: + type: integer + format: int64 + description: Number of duplicate rows that were updated. + minimum: 0 + example: 20 + parameters: + requestId: + name: requestId + in: query + schema: + type: string + format: uuid + required: false + allowEmptyValue: false + description: Unique ID of the API request. This ensures that the execution is + idempotent. If not specified, a new UUID is generated and assigned. + async: + name: async + in: query + schema: + type: boolean + example: true + required: false + description: Set to true to execute the statement asynchronously and return + the statement handle. If the parameter is not specified or is set to false, + a statement is executed and the first result is returned if the execution + is completed in 45 seconds. If the statement execution takes longer to complete, + the statement handle is returned. + partition: + name: partition + in: query + schema: + type: integer + format: int64 + minimum: 0 + example: 2 + required: false + description: Number of the partition of results to return. The number can range + from 0 to the total number of partitions minus 1. + nullable: + name: nullable + in: query + schema: + type: boolean + example: true + required: false + description: Set to true to execute the statement to generate the result set + including null. If the parameter is set to false, the result set value null + will be replaced with a string 'null'. + statementHandle: + name: statementHandle + in: path + schema: + type: string + format: uuid + example: e4ce975e-f7ff-4b5e-b15e-bf25f59371ae + required: true + allowEmptyValue: false + description: The handle of the statement that you want to use (e.g. to fetch + the result set or cancel execution). + userAgent: + name: User-Agent + in: header + schema: + type: string + example: myApplication/1.0 + required: true + allowEmptyValue: false + description: "Set this to the name and version of your application (e.g. \u201C\ + applicationName/applicationVersion\u201D). You must use a value that complies\ + \ with RFC 7231." + accept: + name: Accept + in: header + schema: + type: string + example: application/json + required: false + allowEmptyValue: false + description: The response payload format. The schema should be specified in + resultSetMetaData in the request payload. + acceptEncoding: + name: Accept-Encoding + in: header + schema: + type: string + example: gzip + required: false + allowEmptyValue: false + description: The response payload encoding. Optional. + snowflakeAuthorizationTokenType: + name: X-Snowflake-Authorization-Token-Type + in: header + schema: + type: string + example: KEYPAIR_JWT + required: false + allowEmptyValue: true + description: Specify the authorization token type for the Authorization header. + KEYPAIR_JWT is for Keypair JWT or OAUTH for oAuth token. If not specified, + OAUTH is assumed. + securitySchemes: + KeyPair: + type: http + scheme: bearer + bearerFormat: JWT + description: Set X-Snowflake-Authorization-Token-Type to KEYPAIR_JWT if the + token is a key pair authn JWT. + ExternalOAuth: + type: http + scheme: bearer + bearerFormat: JWT + description: Configure External Oauth with Snowflake (refer to docs). Set X-Snowflake-Authorization-Token-Type + to OAUTH and set the Token to auth token received from the external Auth server. + SnowflakeOAuth: + type: oauth2 + flows: + implicit: + authorizationUrl: /oauth/authorize + scopes: {} + responses: + 400BadRequest: + description: Bad Request. The request payload is invalid or malformed. This + happens if the application didn't send the correct request payload. The response + body may include the error code and message indicating the actual cause. The + application must reconstruct the request body for retry. + 401Unauthorized: + description: Unauthorized. The request is not authorized. This happens if the + attached access token is invalid or missing. The response body may include + the error code and message indicating the actual cause, e.g., expired, invalid + token. The application must obtain a new access token for retry. + 403Forbidden: + description: Forbidden. The request is forbidden. This happens if the request + is made even if the API is not enabled. + 404NotFound: + description: Not Found. The request endpoint is not valid. This happens if the + API endpoint is wrong. For example, if the application hits /api/api/hello + which doesn't exist, it will receive this code. + 405MethodNotAllowed: + description: Method Not Allowed. The request method doesn't match the supported + API. This happens, for example, if the application calls the API with GET + method but the endpoint accepts only POST. The application must change a method + for retry. + 415UnsupportedMediaType: + description: The request header Content-Type includes unsupported media type. + The API supports application/json only. If none specified, the request payload + is taken as JSON, but if any other media type is specified, this error is + returned. + 429LimitExceeded: + description: Limit Exceeded. The number of requests hit the rate limit. The + application must slow down the frequency of hitting the API endpoints. + 500InternalServerError: + description: Internal Server Error. The server hits an unrecoverable system + error. The response body may include the error code and message for further + guidance. The application owner may need to reach out the customer support. + 503ServiceUnavailable: + description: Service Unavailable. The request was not processed due to server + side timeouts. The application may retry with backoff. The jittered backoff + is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ + 504GatewayTimeout: + description: Gateway Timeout. The request was not processed due to server side + timeouts. The application may retry with backoff. The jittered backoff is + recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ + headers: + Link: + schema: + type: string + description: Links to the partition of results (e.g. the first partition, + the last partition, etc.). The header can include multiple 'url' entries + with different 'rel' attribute values that specify the partition to return + ('first', 'next', 'prev', and 'last'). + example: ;rel="last",;rel="next",;rel="first" +security: +- KeyPair: [] +- ExternalOAuth: [] +- SnowflakeOAuth: [] +externalDocs: + url: https://docs.snowflake.com/en/developer-guide/sql-api/index.html diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/ApiClient.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/ApiClient.java new file mode 100644 index 00000000..a892acef --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/ApiClient.java @@ -0,0 +1,789 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.openapitools.jackson.nullable.JsonNullableModule; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpRequest; +import org.springframework.http.HttpStatus; +import org.springframework.http.InvalidMediaTypeException; +import org.springframework.http.MediaType; +import org.springframework.http.RequestEntity; +import org.springframework.http.RequestEntity.BodyBuilder; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.BufferingClientHttpRequestFactory; +import org.springframework.http.client.ClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.http.client.reactive.ClientHttpRequest; +import org.springframework.http.codec.json.Jackson2JsonDecoder; +import org.springframework.http.codec.json.Jackson2JsonEncoder; +import org.springframework.util.CollectionUtils; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.util.StringUtils; +import org.springframework.web.client.RestClientException; +import org.springframework.web.util.UriComponentsBuilder; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.WebClient.ResponseSpec; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.BodyInserter; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.reactive.function.client.ExchangeStrategies; +import reactor.core.publisher.Mono; +import reactor.core.publisher.Flux; +import java.util.Optional; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.text.DateFormat; +import java.text.ParseException; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.TimeZone; + +import javax.annotation.Nullable; + +import java.time.OffsetDateTime; + +import eu.openanalytics.containerproxy.backend.spcs.client.auth.Authentication; +import eu.openanalytics.containerproxy.backend.spcs.client.auth.HttpBasicAuth; +import eu.openanalytics.containerproxy.backend.spcs.client.auth.HttpBearerAuth; +import eu.openanalytics.containerproxy.backend.spcs.client.auth.ApiKeyAuth; +import eu.openanalytics.containerproxy.backend.spcs.client.auth.OAuth; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:42:29.597406700+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ApiClient extends JavaTimeFormatter { + public enum CollectionFormat { + CSV(","), TSV("\t"), SSV(" "), PIPES("|"), MULTI(null); + + protected final String separator; + CollectionFormat(String separator) { + this.separator = separator; + } + + protected String collectionToString(Collection collection) { + return StringUtils.collectionToDelimitedString(collection, separator); + } + } + + protected static final String URI_TEMPLATE_ATTRIBUTE = WebClient.class.getName() + ".uriTemplate"; + + protected HttpHeaders defaultHeaders = new HttpHeaders(); + protected MultiValueMap defaultCookies = new LinkedMultiValueMap(); + + protected String basePath = "https://org-account.snowflakecomputing.com"; + + protected final WebClient webClient; + protected final DateFormat dateFormat; + protected final ObjectMapper objectMapper; + + protected Map authentications; + + + public ApiClient() { + this.dateFormat = createDefaultDateFormat(); + this.objectMapper = createDefaultObjectMapper(this.dateFormat); + this.webClient = buildWebClient(this.objectMapper); + this.init(); + } + + public ApiClient(WebClient webClient) { + this(Optional.ofNullable(webClient).orElseGet(() -> buildWebClient()), createDefaultDateFormat()); + } + + public ApiClient(ObjectMapper mapper, DateFormat format) { + this(buildWebClient(mapper.copy()), format); + } + + public ApiClient(WebClient webClient, ObjectMapper mapper, DateFormat format) { + this(Optional.ofNullable(webClient).orElseGet(() -> buildWebClient(mapper.copy())), format); + } + + protected ApiClient(WebClient webClient, DateFormat format) { + this.webClient = webClient; + this.dateFormat = format; + this.objectMapper = createDefaultObjectMapper(format); + this.init(); + } + + public static DateFormat createDefaultDateFormat() { + DateFormat dateFormat = new RFC3339DateFormat(); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + return dateFormat; + } + + public static ObjectMapper createDefaultObjectMapper(@Nullable DateFormat dateFormat) { + if (null == dateFormat) { + dateFormat = createDefaultDateFormat(); + } + ObjectMapper mapper = new ObjectMapper(); + mapper.setDateFormat(dateFormat); + mapper.registerModule(new JavaTimeModule()); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + JsonNullableModule jnm = new JsonNullableModule(); + mapper.registerModule(jnm); + return mapper; + } + + protected void init() { + // Setup authentications (key: authentication name, value: authentication). + authentications = new HashMap(); + authentications.put("KeyPair", new HttpBearerAuth("bearer")); + authentications.put("ExternalOAuth", new HttpBearerAuth("bearer")); + authentications.put("SnowflakeOAuth", new OAuth()); + // Prevent the authentications from being modified. + authentications = Collections.unmodifiableMap(authentications); + } + + /** + * Build the WebClientBuilder used to make WebClient. + * @param mapper ObjectMapper used for serialize/deserialize + * @return WebClient + */ + public static WebClient.Builder buildWebClientBuilder(ObjectMapper mapper) { + ExchangeStrategies strategies = ExchangeStrategies + .builder() + .codecs(clientDefaultCodecsConfigurer -> { + clientDefaultCodecsConfigurer.defaultCodecs().jackson2JsonEncoder(new Jackson2JsonEncoder(mapper, MediaType.APPLICATION_JSON)); + clientDefaultCodecsConfigurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(mapper, MediaType.APPLICATION_JSON)); + }).build(); + WebClient.Builder webClientBuilder = WebClient.builder().exchangeStrategies(strategies); + return webClientBuilder; + } + + /** + * Build the WebClientBuilder used to make WebClient. + * @return WebClient + */ + public static WebClient.Builder buildWebClientBuilder() { + return buildWebClientBuilder(createDefaultObjectMapper(null)); + } + + /** + * Build the WebClient used to make HTTP requests. + * @param mapper ObjectMapper used for serialize/deserialize + * @return WebClient + */ + public static WebClient buildWebClient(ObjectMapper mapper) { + return buildWebClientBuilder(mapper).build(); + } + + /** + * Build the WebClient used to make HTTP requests. + * @return WebClient + */ + public static WebClient buildWebClient() { + return buildWebClientBuilder(createDefaultObjectMapper(null)).build(); + } + + /** + * Get the current base path + * @return String the base path + */ + public String getBasePath() { + return basePath; + } + + /** + * Set the base path, which should include the host + * @param basePath the base path + * @return ApiClient this client + */ + public ApiClient setBasePath(String basePath) { + this.basePath = basePath; + return this; + } + + /** + * Get authentications (key: authentication name, value: authentication). + * @return Map the currently configured authentication types + */ + public Map getAuthentications() { + return authentications; + } + + /** + * Get authentication for the given name. + * + * @param authName The authentication name + * @return The authentication, null if not found + */ + public Authentication getAuthentication(String authName) { + return authentications.get(authName); + } + + /** + * Helper method to set access token for the first Bearer authentication. + * @param bearerToken Bearer token + */ + public void setBearerToken(String bearerToken) { + for (Authentication auth : authentications.values()) { + if (auth instanceof HttpBearerAuth) { + ((HttpBearerAuth) auth).setBearerToken(bearerToken); + return; + } + } + throw new RuntimeException("No Bearer authentication configured!"); + } + + /** + * Helper method to set username for the first HTTP basic authentication. + * @param username the username + */ + public void setUsername(String username) { + for (Authentication auth : authentications.values()) { + if (auth instanceof HttpBasicAuth) { + ((HttpBasicAuth) auth).setUsername(username); + return; + } + } + throw new RuntimeException("No HTTP basic authentication configured!"); + } + + /** + * Helper method to set password for the first HTTP basic authentication. + * @param password the password + */ + public void setPassword(String password) { + for (Authentication auth : authentications.values()) { + if (auth instanceof HttpBasicAuth) { + ((HttpBasicAuth) auth).setPassword(password); + return; + } + } + throw new RuntimeException("No HTTP basic authentication configured!"); + } + + /** + * Helper method to set API key value for the first API key authentication. + * @param apiKey the API key + */ + public void setApiKey(String apiKey) { + for (Authentication auth : authentications.values()) { + if (auth instanceof ApiKeyAuth) { + ((ApiKeyAuth) auth).setApiKey(apiKey); + return; + } + } + throw new RuntimeException("No API key authentication configured!"); + } + + /** + * Helper method to set API key prefix for the first API key authentication. + * @param apiKeyPrefix the API key prefix + */ + public void setApiKeyPrefix(String apiKeyPrefix) { + for (Authentication auth : authentications.values()) { + if (auth instanceof ApiKeyAuth) { + ((ApiKeyAuth) auth).setApiKeyPrefix(apiKeyPrefix); + return; + } + } + throw new RuntimeException("No API key authentication configured!"); + } + + /** + * Helper method to set access token for the first OAuth2 authentication. + * @param accessToken the access token + */ + public void setAccessToken(String accessToken) { + for (Authentication auth : authentications.values()) { + if (auth instanceof OAuth) { + ((OAuth) auth).setAccessToken(accessToken); + return; + } + } + throw new RuntimeException("No OAuth2 authentication configured!"); + } + + /** + * Set the User-Agent header's value (by adding to the default header map). + * @param userAgent the user agent string + * @return ApiClient this client + */ + public ApiClient setUserAgent(String userAgent) { + addDefaultHeader("User-Agent", userAgent); + return this; + } + + /** + * Add a default header. + * + * @param name The header's name + * @param value The header's value + * @return ApiClient this client + */ + public ApiClient addDefaultHeader(String name, String value) { + defaultHeaders.set(name, value); + return this; + } + + /** + * Add a default cookie. + * + * @param name The cookie's name + * @param value The cookie's value + * @return ApiClient this client + */ + public ApiClient addDefaultCookie(String name, String value) { + if (defaultCookies.containsKey(name)) { + defaultCookies.remove(name); + } + defaultCookies.add(name, value); + return this; + } + + /** + * Get the date format used to parse/format date parameters. + * @return DateFormat format + */ + public DateFormat getDateFormat() { + return dateFormat; + } + + /** + * Parse the given string into Date object. + */ + public Date parseDate(String str) { + try { + return dateFormat.parse(str); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + + /** + * Format the given Date object into string. + */ + public String formatDate(Date date) { + return dateFormat.format(date); + } + + /** + * Get the ObjectMapper used to make HTTP requests. + * @return ObjectMapper objectMapper + */ + public ObjectMapper getObjectMapper() { + return objectMapper; + } + + /** + * Get the WebClient used to make HTTP requests. + * @return WebClient webClient + */ + public WebClient getWebClient() { + return webClient; + } + + /** + * Format the given parameter object into string. + * @param param the object to convert + * @return String the parameter represented as a String + */ + public String parameterToString(Object param) { + if (param == null) { + return ""; + } else if (param instanceof Date) { + return formatDate( (Date) param); + } else if (param instanceof OffsetDateTime) { + return formatOffsetDateTime((OffsetDateTime) param); + } else if (param instanceof Collection) { + StringBuilder b = new StringBuilder(); + for(Object o : (Collection) param) { + if(b.length() > 0) { + b.append(","); + } + b.append(String.valueOf(o)); + } + return b.toString(); + } else { + return String.valueOf(param); + } + } + + /** + * Converts a parameter to a {@link MultiValueMap} containing Json-serialized values for use in REST requests + * @param collectionFormat The format to convert to + * @param name The name of the parameter + * @param value The parameter's value + * @return a Map containing the Json-serialized String value(s) of the input parameter + */ + public MultiValueMap parameterToMultiValueMapJson(CollectionFormat collectionFormat, String name, Object value) { + Collection valueCollection; + if (value instanceof Collection) { + valueCollection = (Collection) value; + } else { + try { + return parameterToMultiValueMap(collectionFormat, name, objectMapper.writeValueAsString(value)); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + List values = new ArrayList<>(); + for(Object o : valueCollection) { + try { + values.add(objectMapper.writeValueAsString(o)); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + return parameterToMultiValueMap(collectionFormat, name, "[" + StringUtils.collectionToDelimitedString(values, collectionFormat.separator) + "]"); + } + + /** + * Converts a parameter to a {@link MultiValueMap} for use in REST requests + * @param collectionFormat The format to convert to + * @param name The name of the parameter + * @param value The parameter's value + * @return a Map containing the String value(s) of the input parameter + */ + public MultiValueMap parameterToMultiValueMap(CollectionFormat collectionFormat, String name, Object value) { + final MultiValueMap params = new LinkedMultiValueMap(); + + if (name == null || name.isEmpty() || value == null) { + return params; + } + + if(collectionFormat == null) { + collectionFormat = CollectionFormat.CSV; + } + + if (value instanceof Map) { + @SuppressWarnings("unchecked") + final Map valuesMap = (Map) value; + for (final Entry entry : valuesMap.entrySet()) { + params.add(entry.getKey(), parameterToString(entry.getValue())); + } + return params; + } + + Collection valueCollection = null; + if (value instanceof Collection) { + valueCollection = (Collection) value; + } else { + params.add(name, parameterToString(value)); + return params; + } + + if (valueCollection.isEmpty()){ + return params; + } + + if (collectionFormat.equals(CollectionFormat.MULTI)) { + for (Object item : valueCollection) { + params.add(name, parameterToString(item)); + } + return params; + } + + List values = new ArrayList(); + for(Object o : valueCollection) { + values.add(parameterToString(o)); + } + params.add(name, collectionFormat.collectionToString(values)); + + return params; + } + + /** + * Check if the given {@code String} is a JSON MIME. + * @param mediaType the input MediaType + * @return boolean true if the MediaType represents JSON, false otherwise + */ + public boolean isJsonMime(String mediaType) { + // "* / *" is default to JSON + if ("*/*".equals(mediaType)) { + return true; + } + + try { + return isJsonMime(MediaType.parseMediaType(mediaType)); + } catch (InvalidMediaTypeException e) { + } + return false; + } + + /** + * Check if the given MIME is a JSON MIME. + * JSON MIME examples: + * application/json + * application/json; charset=UTF8 + * APPLICATION/JSON + * @param mediaType the input MediaType + * @return boolean true if the MediaType represents JSON, false otherwise + */ + public boolean isJsonMime(MediaType mediaType) { + return mediaType != null && (MediaType.APPLICATION_JSON.isCompatibleWith(mediaType) || mediaType.getSubtype().matches("^.*(\\+json|ndjson)[;]?\\s*$")); + } + + /** + * Check if the given {@code String} is a Problem JSON MIME (RFC-7807). + * @param mediaType the input MediaType + * @return boolean true if the MediaType represents Problem JSON, false otherwise + */ + public boolean isProblemJsonMime(String mediaType) { + return "application/problem+json".equalsIgnoreCase(mediaType); + } + + /** + * Select the Accept header's value from the given accepts array: + * if JSON exists in the given array, use it; + * otherwise use all of them (joining into a string) + * + * @param accepts The accepts array to select from + * @return List The list of MediaTypes to use for the Accept header + */ + public List selectHeaderAccept(String[] accepts) { + if (accepts.length == 0) { + return null; + } + for (String accept : accepts) { + MediaType mediaType = MediaType.parseMediaType(accept); + if (isJsonMime(mediaType) && !isProblemJsonMime(accept)) { + return Collections.singletonList(mediaType); + } + } + return MediaType.parseMediaTypes(StringUtils.arrayToCommaDelimitedString(accepts)); + } + + /** + * Select the Content-Type header's value from the given array: + * if JSON exists in the given array, use it; + * otherwise use the first one of the array. + * + * @param contentTypes The Content-Type array to select from + * @return MediaType The Content-Type header to use. If the given array is empty, null will be returned. + */ + public MediaType selectHeaderContentType(String[] contentTypes) { + if (contentTypes.length == 0) { + return null; + } + for (String contentType : contentTypes) { + MediaType mediaType = MediaType.parseMediaType(contentType); + if (isJsonMime(mediaType)) { + return mediaType; + } + } + return MediaType.parseMediaType(contentTypes[0]); + } + + /** + * Select the body to use for the request + * @param obj the body object + * @param formParams the form parameters + * @param contentType the content type of the request + * @return Object the selected body + */ + protected BodyInserter selectBody(Object obj, MultiValueMap formParams, MediaType contentType) { + if(MediaType.APPLICATION_FORM_URLENCODED.equals(contentType)) { + MultiValueMap map = new LinkedMultiValueMap<>(); + + formParams + .toSingleValueMap() + .entrySet() + .forEach(es -> map.add(es.getKey(), String.valueOf(es.getValue()))); + + return BodyInserters.fromFormData(map); + } else if(MediaType.MULTIPART_FORM_DATA.equals(contentType)) { + return BodyInserters.fromMultipartData(formParams); + } else { + return obj != null ? BodyInserters.fromValue(obj) : null; + } + } + + /** + * Invoke API by sending HTTP request with the given options. + * + * @param the return type to use + * @param path The sub-path of the HTTP URL + * @param method The request method + * @param pathParams The path parameters + * @param queryParams The query parameters + * @param body The request body object + * @param headerParams The header parameters + * @param formParams The form parameters + * @param accept The request's Accept header + * @param contentType The request's Content-Type header + * @param authNames The authentications to apply + * @param returnType The return type into which to deserialize the response + * @return The response body in chosen type + */ + public ResponseSpec invokeAPI(String path, HttpMethod method, Map pathParams, MultiValueMap queryParams, Object body, HttpHeaders headerParams, MultiValueMap cookieParams, MultiValueMap formParams, List accept, MediaType contentType, String[] authNames, ParameterizedTypeReference returnType) throws RestClientException { + final WebClient.RequestBodySpec requestBuilder = prepareRequest(path, method, pathParams, queryParams, body, headerParams, cookieParams, formParams, accept, contentType, authNames); + return requestBuilder.retrieve(); + } + + /** + * Include queryParams in uriParams taking into account the paramName + * @param queryParams The query parameters + * @param uriParams The path parameters + * return templatized query string + */ + protected String generateQueryUri(MultiValueMap queryParams, Map uriParams) { + StringBuilder queryBuilder = new StringBuilder(); + queryParams.forEach((name, values) -> { + if (CollectionUtils.isEmpty(values)) { + if (queryBuilder.length() != 0) { + queryBuilder.append('&'); + } + queryBuilder.append(name); + } else { + int valueItemCounter = 0; + for (Object value : values) { + if (queryBuilder.length() != 0) { + queryBuilder.append('&'); + } + queryBuilder.append(name); + if (value != null) { + String templatizedKey = name + valueItemCounter++; + uriParams.put(templatizedKey, value.toString()); + queryBuilder.append('=').append("{").append(templatizedKey).append("}"); + } + } + } + }); + return queryBuilder.toString(); + } + + protected WebClient.RequestBodySpec prepareRequest(String path, HttpMethod method, Map pathParams, + MultiValueMap queryParams, Object body, HttpHeaders headerParams, + MultiValueMap cookieParams, MultiValueMap formParams, List accept, + MediaType contentType, String[] authNames) { + updateParamsForAuth(authNames, queryParams, headerParams, cookieParams); + + final UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(basePath).path(path); + + String finalUri = builder.build(false).toUriString(); + Map uriParams = new HashMap<>(); + uriParams.putAll(pathParams); + + if (queryParams != null && !queryParams.isEmpty()) { + //Include queryParams in uriParams taking into account the paramName + String queryUri = generateQueryUri(queryParams, uriParams); + //Append to finalUri the templatized query string like "?param1={param1Value}&....... + finalUri += "?" + queryUri; + } + + final WebClient.RequestBodySpec requestBuilder = webClient.method(method).uri(finalUri, uriParams); + + if (accept != null) { + requestBuilder.accept(accept.toArray(new MediaType[accept.size()])); + } + if(contentType != null) { + requestBuilder.contentType(contentType); + } + + addHeadersToRequest(headerParams, requestBuilder); + addHeadersToRequest(defaultHeaders, requestBuilder); + addCookiesToRequest(cookieParams, requestBuilder); + addCookiesToRequest(defaultCookies, requestBuilder); + + requestBuilder.attribute(URI_TEMPLATE_ATTRIBUTE, path); + + requestBuilder.body(selectBody(body, formParams, contentType)); + return requestBuilder; + } + + /** + * Add headers to the request that is being built + * @param headers The headers to add + * @param requestBuilder The current request + */ + protected void addHeadersToRequest(HttpHeaders headers, WebClient.RequestBodySpec requestBuilder) { + for (Entry> entry : headers.entrySet()) { + List values = entry.getValue(); + for(String value : values) { + if (value != null) { + requestBuilder.header(entry.getKey(), value); + } + } + } + } + + /** + * Add cookies to the request that is being built + * @param cookies The cookies to add + * @param requestBuilder The current request + */ + protected void addCookiesToRequest(MultiValueMap cookies, WebClient.RequestBodySpec requestBuilder) { + for (Entry> entry : cookies.entrySet()) { + List values = entry.getValue(); + for(String value : values) { + if (value != null) { + requestBuilder.cookie(entry.getKey(), value); + } + } + } + } + + /** + * Update query and header parameters based on authentication settings. + * + * @param authNames The authentications to apply + * @param queryParams The query parameters + * @param headerParams The header parameters + * @param cookieParams the cookie parameters + */ + protected void updateParamsForAuth(String[] authNames, MultiValueMap queryParams, HttpHeaders headerParams, MultiValueMap cookieParams) { + for (String authName : authNames) { + Authentication auth = authentications.get(authName); + if (auth == null) { + throw new RestClientException("Authentication undefined: " + authName); + } + auth.applyToParams(queryParams, headerParams, cookieParams); + } + } + + /** + * Formats the specified collection path parameter to a string value. + * + * @param collectionFormat The collection format of the parameter. + * @param values The values of the parameter. + * @return String representation of the parameter + */ + public String collectionPathParameterToString(CollectionFormat collectionFormat, Collection values) { + // create the value based on the collection format + if (CollectionFormat.MULTI.equals(collectionFormat)) { + // not valid for path params + return parameterToString(values); + } + + // collectionFormat is assumed to be "csv" by default + if(collectionFormat == null) { + collectionFormat = CollectionFormat.CSV; + } + + return collectionFormat.collectionToString(values); + } +} diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/JavaTimeFormatter.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/JavaTimeFormatter.java new file mode 100644 index 00000000..8f7ca6d6 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/JavaTimeFormatter.java @@ -0,0 +1,68 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +package eu.openanalytics.containerproxy.backend.spcs.client; + +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; + +/** + * Class that add parsing/formatting support for Java 8+ {@code OffsetDateTime} class. + * It's generated for java clients when {@code AbstractJavaCodegen#dateLibrary} specified as {@code java8}. + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:42:29.597406700+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class JavaTimeFormatter { + private DateTimeFormatter offsetDateTimeFormatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME; + + /** + * Get the date format used to parse/format {@code OffsetDateTime} parameters. + * + * @return DateTimeFormatter + */ + public DateTimeFormatter getOffsetDateTimeFormatter() { + return offsetDateTimeFormatter; + } + + /** + * Set the date format used to parse/format {@code OffsetDateTime} parameters. + * + * @param offsetDateTimeFormatter {@code DateTimeFormatter} + */ + public void setOffsetDateTimeFormatter(DateTimeFormatter offsetDateTimeFormatter) { + this.offsetDateTimeFormatter = offsetDateTimeFormatter; + } + + /** + * Parse the given string into {@code OffsetDateTime} object. + * + * @param str String + * @return {@code OffsetDateTime} + */ + public OffsetDateTime parseOffsetDateTime(String str) { + try { + return OffsetDateTime.parse(str, offsetDateTimeFormatter); + } catch (DateTimeParseException e) { + throw new RuntimeException(e); + } + } + + /** + * Format the given {@code OffsetDateTime} object into string. + * + * @param offsetDateTime {@code OffsetDateTime} + * @return {@code OffsetDateTime} in string format + */ + public String formatOffsetDateTime(OffsetDateTime offsetDateTime) { + return offsetDateTimeFormatter.format(offsetDateTime); + } +} \ No newline at end of file diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/RFC3339DateFormat.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/RFC3339DateFormat.java new file mode 100644 index 00000000..cbfe8696 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/RFC3339DateFormat.java @@ -0,0 +1,58 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +package eu.openanalytics.containerproxy.backend.spcs.client; + +import com.fasterxml.jackson.databind.util.StdDateFormat; + +import java.text.DateFormat; +import java.text.FieldPosition; +import java.text.ParsePosition; +import java.util.Date; +import java.text.DecimalFormat; +import java.util.GregorianCalendar; +import java.util.TimeZone; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:42:29.597406700+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class RFC3339DateFormat extends DateFormat { + private static final long serialVersionUID = 1L; + private static final TimeZone TIMEZONE_Z = TimeZone.getTimeZone("UTC"); + + private final StdDateFormat fmt = new StdDateFormat() + .withTimeZone(TIMEZONE_Z) + .withColonInTimeZone(true); + + public RFC3339DateFormat() { + this.calendar = new GregorianCalendar(); + this.numberFormat = new DecimalFormat(); + } + + @Override + public Date parse(String source) { + return parse(source, new ParsePosition(0)); + } + + @Override + public Date parse(String source, ParsePosition pos) { + return fmt.parse(source, pos); + } + + @Override + public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) { + return fmt.format(date, toAppendTo, fieldPosition); + } + + @Override + public Object clone() { + return super.clone(); + } +} diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/api/ServiceApi.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/api/ServiceApi.java new file mode 100644 index 00000000..66563373 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/api/ServiceApi.java @@ -0,0 +1,2295 @@ +package eu.openanalytics.containerproxy.backend.spcs.client.api; + +import eu.openanalytics.containerproxy.backend.spcs.client.ApiClient; + +import eu.openanalytics.containerproxy.backend.spcs.client.model.ErrorResponse; +import eu.openanalytics.containerproxy.backend.spcs.client.model.FetchServiceLogs200Response; +import eu.openanalytics.containerproxy.backend.spcs.client.model.FetchServiceStatus200Response; +import eu.openanalytics.containerproxy.backend.spcs.client.model.GrantOf; +import eu.openanalytics.containerproxy.backend.spcs.client.model.JobService; +import eu.openanalytics.containerproxy.backend.spcs.client.model.Service; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceContainer; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceEndpoint; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceInstance; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceRole; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceRoleGrantTo; +import eu.openanalytics.containerproxy.backend.spcs.client.model.SuccessAcceptedResponse; +import eu.openanalytics.containerproxy.backend.spcs.client.model.SuccessResponse; +import java.util.UUID; + +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.Arrays; +import java.util.stream.Collectors; + +import org.springframework.core.io.FileSystemResource; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.reactive.function.client.WebClient.ResponseSpec; +import org.springframework.web.reactive.function.client.WebClientResponseException; +import reactor.core.publisher.Mono; +import reactor.core.publisher.Flux; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:41:25.529847700+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ServiceApi { + private ApiClient apiClient; + + public ServiceApi() { + this(new ApiClient()); + } + + public ServiceApi(ApiClient apiClient) { + this.apiClient = apiClient; + } + + public ApiClient getApiClient() { + return apiClient; + } + + public void setApiClient(ApiClient apiClient) { + this.apiClient = apiClient; + } + + /** + * Create a (or alter an existing) service. + * Create a (or alter an existing) service. Even if the operation is just an alter, the full property set must be provided. + *

200 - Successful request + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @param service The service parameter + * @return SuccessResponse + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + private ResponseSpec createOrAlterServiceRequestCreation(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nonnull Service service) throws WebClientResponseException { + Object postBody = service; + // verify the required parameter 'database' is set + if (database == null) { + throw new WebClientResponseException("Missing the required parameter 'database' when calling createOrAlterService", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'schema' is set + if (schema == null) { + throw new WebClientResponseException("Missing the required parameter 'schema' when calling createOrAlterService", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'name' is set + if (name == null) { + throw new WebClientResponseException("Missing the required parameter 'name' when calling createOrAlterService", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'service' is set + if (service == null) { + throw new WebClientResponseException("Missing the required parameter 'service' when calling createOrAlterService", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // create path and map variables + final Map pathParams = new HashMap(); + + pathParams.put("database", database); + pathParams.put("schema", schema); + pathParams.put("name", name); + + final MultiValueMap queryParams = new LinkedMultiValueMap(); + final HttpHeaders headerParams = new HttpHeaders(); + final MultiValueMap cookieParams = new LinkedMultiValueMap(); + final MultiValueMap formParams = new LinkedMultiValueMap(); + + final String[] localVarAccepts = { + "application/json" + }; + final List localVarAccept = apiClient.selectHeaderAccept(localVarAccepts); + final String[] localVarContentTypes = { + "application/json" + }; + final MediaType localVarContentType = apiClient.selectHeaderContentType(localVarContentTypes); + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return apiClient.invokeAPI("/api/v2/databases/{database}/schemas/{schema}/services/{name}", HttpMethod.PUT, pathParams, queryParams, postBody, headerParams, cookieParams, formParams, localVarAccept, localVarContentType, localVarAuthNames, localVarReturnType); + } + + /** + * Create a (or alter an existing) service. + * Create a (or alter an existing) service. Even if the operation is just an alter, the full property set must be provided. + *

200 - Successful request + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @param service The service parameter + * @return SuccessResponse + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono createOrAlterService(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nonnull Service service) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return createOrAlterServiceRequestCreation(database, schema, name, service).bodyToMono(localVarReturnType); + } + + /** + * Create a (or alter an existing) service. + * Create a (or alter an existing) service. Even if the operation is just an alter, the full property set must be provided. + *

200 - Successful request + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @param service The service parameter + * @return ResponseEntity<SuccessResponse> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono> createOrAlterServiceWithHttpInfo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nonnull Service service) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return createOrAlterServiceRequestCreation(database, schema, name, service).toEntity(localVarReturnType); + } + + /** + * Create a (or alter an existing) service. + * Create a (or alter an existing) service. Even if the operation is just an alter, the full property set must be provided. + *

200 - Successful request + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @param service The service parameter + * @return ResponseSpec + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public ResponseSpec createOrAlterServiceWithResponseSpec(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nonnull Service service) throws WebClientResponseException { + return createOrAlterServiceRequestCreation(database, schema, name, service); + } + + /** + * Create a service + * Create a service, with standard create modifiers as query parameters. See the Service component definition for what is required to be provided in the request body. + *

200 - Successful request. + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

408 - Request Timeout. This indicates that the request from the client timed out and was not completed by the server. + *

409 - Conflict. The requested operation could not be performed due to a conflicting state that could not be resolved. This usually happens when a CREATE request was performed when there is a pre-existing resource with the same name, and also without one of the options orReplace/ifNotExists. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param service The service parameter + * @param createMode Query parameter allowing support for different modes of resource creation. Possible values include: - `errorIfExists`: Throws an error if you try to create a resource that already exists. - `ifNotExists`: Creates a new resource when an alter is requested for a non-existent resource. + * @return SuccessResponse + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + private ResponseSpec createServiceRequestCreation(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull Service service, @javax.annotation.Nullable String createMode) throws WebClientResponseException { + Object postBody = service; + // verify the required parameter 'database' is set + if (database == null) { + throw new WebClientResponseException("Missing the required parameter 'database' when calling createService", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'schema' is set + if (schema == null) { + throw new WebClientResponseException("Missing the required parameter 'schema' when calling createService", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'service' is set + if (service == null) { + throw new WebClientResponseException("Missing the required parameter 'service' when calling createService", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // create path and map variables + final Map pathParams = new HashMap(); + + pathParams.put("database", database); + pathParams.put("schema", schema); + + final MultiValueMap queryParams = new LinkedMultiValueMap(); + final HttpHeaders headerParams = new HttpHeaders(); + final MultiValueMap cookieParams = new LinkedMultiValueMap(); + final MultiValueMap formParams = new LinkedMultiValueMap(); + + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "createMode", createMode)); + + final String[] localVarAccepts = { + "application/json" + }; + final List localVarAccept = apiClient.selectHeaderAccept(localVarAccepts); + final String[] localVarContentTypes = { + "application/json" + }; + final MediaType localVarContentType = apiClient.selectHeaderContentType(localVarContentTypes); + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return apiClient.invokeAPI("/api/v2/databases/{database}/schemas/{schema}/services", HttpMethod.POST, pathParams, queryParams, postBody, headerParams, cookieParams, formParams, localVarAccept, localVarContentType, localVarAuthNames, localVarReturnType); + } + + /** + * Create a service + * Create a service, with standard create modifiers as query parameters. See the Service component definition for what is required to be provided in the request body. + *

200 - Successful request. + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

408 - Request Timeout. This indicates that the request from the client timed out and was not completed by the server. + *

409 - Conflict. The requested operation could not be performed due to a conflicting state that could not be resolved. This usually happens when a CREATE request was performed when there is a pre-existing resource with the same name, and also without one of the options orReplace/ifNotExists. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param service The service parameter + * @param createMode Query parameter allowing support for different modes of resource creation. Possible values include: - `errorIfExists`: Throws an error if you try to create a resource that already exists. - `ifNotExists`: Creates a new resource when an alter is requested for a non-existent resource. + * @return SuccessResponse + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono createService(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull Service service, @javax.annotation.Nullable String createMode) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return createServiceRequestCreation(database, schema, service, createMode).bodyToMono(localVarReturnType); + } + + /** + * Create a service + * Create a service, with standard create modifiers as query parameters. See the Service component definition for what is required to be provided in the request body. + *

200 - Successful request. + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

408 - Request Timeout. This indicates that the request from the client timed out and was not completed by the server. + *

409 - Conflict. The requested operation could not be performed due to a conflicting state that could not be resolved. This usually happens when a CREATE request was performed when there is a pre-existing resource with the same name, and also without one of the options orReplace/ifNotExists. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param service The service parameter + * @param createMode Query parameter allowing support for different modes of resource creation. Possible values include: - `errorIfExists`: Throws an error if you try to create a resource that already exists. - `ifNotExists`: Creates a new resource when an alter is requested for a non-existent resource. + * @return ResponseEntity<SuccessResponse> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono> createServiceWithHttpInfo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull Service service, @javax.annotation.Nullable String createMode) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return createServiceRequestCreation(database, schema, service, createMode).toEntity(localVarReturnType); + } + + /** + * Create a service + * Create a service, with standard create modifiers as query parameters. See the Service component definition for what is required to be provided in the request body. + *

200 - Successful request. + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

408 - Request Timeout. This indicates that the request from the client timed out and was not completed by the server. + *

409 - Conflict. The requested operation could not be performed due to a conflicting state that could not be resolved. This usually happens when a CREATE request was performed when there is a pre-existing resource with the same name, and also without one of the options orReplace/ifNotExists. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param service The service parameter + * @param createMode Query parameter allowing support for different modes of resource creation. Possible values include: - `errorIfExists`: Throws an error if you try to create a resource that already exists. - `ifNotExists`: Creates a new resource when an alter is requested for a non-existent resource. + * @return ResponseSpec + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public ResponseSpec createServiceWithResponseSpec(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull Service service, @javax.annotation.Nullable String createMode) throws WebClientResponseException { + return createServiceRequestCreation(database, schema, service, createMode); + } + + /** + * Delete a service + * Delete a service with the given name. If ifExists is used, the operation will succeed even if the object does not exist. Otherwise, there will be a failure if the drop is unsuccessful. + *

200 - Successful request. + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @param ifExists Parameter that specifies how to handle the request for a resource that does not exist: - `true`: The endpoint does not throw an error if the resource does not exist. It returns a 200 success response, but does not take any action on the resource. - `false`: The endpoint throws an error if the resource doesn't exist. + * @return SuccessResponse + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + private ResponseSpec deleteServiceRequestCreation(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Boolean ifExists) throws WebClientResponseException { + Object postBody = null; + // verify the required parameter 'database' is set + if (database == null) { + throw new WebClientResponseException("Missing the required parameter 'database' when calling deleteService", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'schema' is set + if (schema == null) { + throw new WebClientResponseException("Missing the required parameter 'schema' when calling deleteService", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'name' is set + if (name == null) { + throw new WebClientResponseException("Missing the required parameter 'name' when calling deleteService", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // create path and map variables + final Map pathParams = new HashMap(); + + pathParams.put("database", database); + pathParams.put("schema", schema); + pathParams.put("name", name); + + final MultiValueMap queryParams = new LinkedMultiValueMap(); + final HttpHeaders headerParams = new HttpHeaders(); + final MultiValueMap cookieParams = new LinkedMultiValueMap(); + final MultiValueMap formParams = new LinkedMultiValueMap(); + + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "ifExists", ifExists)); + + final String[] localVarAccepts = { + "application/json" + }; + final List localVarAccept = apiClient.selectHeaderAccept(localVarAccepts); + final String[] localVarContentTypes = { }; + final MediaType localVarContentType = apiClient.selectHeaderContentType(localVarContentTypes); + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return apiClient.invokeAPI("/api/v2/databases/{database}/schemas/{schema}/services/{name}", HttpMethod.DELETE, pathParams, queryParams, postBody, headerParams, cookieParams, formParams, localVarAccept, localVarContentType, localVarAuthNames, localVarReturnType); + } + + /** + * Delete a service + * Delete a service with the given name. If ifExists is used, the operation will succeed even if the object does not exist. Otherwise, there will be a failure if the drop is unsuccessful. + *

200 - Successful request. + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @param ifExists Parameter that specifies how to handle the request for a resource that does not exist: - `true`: The endpoint does not throw an error if the resource does not exist. It returns a 200 success response, but does not take any action on the resource. - `false`: The endpoint throws an error if the resource doesn't exist. + * @return SuccessResponse + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono deleteService(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Boolean ifExists) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return deleteServiceRequestCreation(database, schema, name, ifExists).bodyToMono(localVarReturnType); + } + + /** + * Delete a service + * Delete a service with the given name. If ifExists is used, the operation will succeed even if the object does not exist. Otherwise, there will be a failure if the drop is unsuccessful. + *

200 - Successful request. + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @param ifExists Parameter that specifies how to handle the request for a resource that does not exist: - `true`: The endpoint does not throw an error if the resource does not exist. It returns a 200 success response, but does not take any action on the resource. - `false`: The endpoint throws an error if the resource doesn't exist. + * @return ResponseEntity<SuccessResponse> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono> deleteServiceWithHttpInfo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Boolean ifExists) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return deleteServiceRequestCreation(database, schema, name, ifExists).toEntity(localVarReturnType); + } + + /** + * Delete a service + * Delete a service with the given name. If ifExists is used, the operation will succeed even if the object does not exist. Otherwise, there will be a failure if the drop is unsuccessful. + *

200 - Successful request. + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @param ifExists Parameter that specifies how to handle the request for a resource that does not exist: - `true`: The endpoint does not throw an error if the resource does not exist. It returns a 200 success response, but does not take any action on the resource. - `false`: The endpoint throws an error if the resource doesn't exist. + * @return ResponseSpec + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public ResponseSpec deleteServiceWithResponseSpec(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Boolean ifExists) throws WebClientResponseException { + return deleteServiceRequestCreation(database, schema, name, ifExists); + } + + /** + * Execute a job service + * Create and execute a job service. See the JobService component definition for what is required to be provided in the request body. + *

200 - Successful request. + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

409 - Conflict. The requested operation could not be performed due to a conflicting state that could not be resolved. This usually happens when a CREATE request was performed when there is a pre-existing resource with the same name, and also without one of the options orReplace/ifNotExists. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param jobService The jobService parameter + * @return SuccessResponse + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + private ResponseSpec executeJobServiceRequestCreation(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull JobService jobService) throws WebClientResponseException { + Object postBody = jobService; + // verify the required parameter 'database' is set + if (database == null) { + throw new WebClientResponseException("Missing the required parameter 'database' when calling executeJobService", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'schema' is set + if (schema == null) { + throw new WebClientResponseException("Missing the required parameter 'schema' when calling executeJobService", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'jobService' is set + if (jobService == null) { + throw new WebClientResponseException("Missing the required parameter 'jobService' when calling executeJobService", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // create path and map variables + final Map pathParams = new HashMap(); + + pathParams.put("database", database); + pathParams.put("schema", schema); + + final MultiValueMap queryParams = new LinkedMultiValueMap(); + final HttpHeaders headerParams = new HttpHeaders(); + final MultiValueMap cookieParams = new LinkedMultiValueMap(); + final MultiValueMap formParams = new LinkedMultiValueMap(); + + final String[] localVarAccepts = { + "application/json" + }; + final List localVarAccept = apiClient.selectHeaderAccept(localVarAccepts); + final String[] localVarContentTypes = { + "application/json" + }; + final MediaType localVarContentType = apiClient.selectHeaderContentType(localVarContentTypes); + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return apiClient.invokeAPI("/api/v2/databases/{database}/schemas/{schema}/services:execute-job", HttpMethod.POST, pathParams, queryParams, postBody, headerParams, cookieParams, formParams, localVarAccept, localVarContentType, localVarAuthNames, localVarReturnType); + } + + /** + * Execute a job service + * Create and execute a job service. See the JobService component definition for what is required to be provided in the request body. + *

200 - Successful request. + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

409 - Conflict. The requested operation could not be performed due to a conflicting state that could not be resolved. This usually happens when a CREATE request was performed when there is a pre-existing resource with the same name, and also without one of the options orReplace/ifNotExists. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param jobService The jobService parameter + * @return SuccessResponse + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono executeJobService(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull JobService jobService) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return executeJobServiceRequestCreation(database, schema, jobService).bodyToMono(localVarReturnType); + } + + /** + * Execute a job service + * Create and execute a job service. See the JobService component definition for what is required to be provided in the request body. + *

200 - Successful request. + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

409 - Conflict. The requested operation could not be performed due to a conflicting state that could not be resolved. This usually happens when a CREATE request was performed when there is a pre-existing resource with the same name, and also without one of the options orReplace/ifNotExists. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param jobService The jobService parameter + * @return ResponseEntity<SuccessResponse> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono> executeJobServiceWithHttpInfo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull JobService jobService) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return executeJobServiceRequestCreation(database, schema, jobService).toEntity(localVarReturnType); + } + + /** + * Execute a job service + * Create and execute a job service. See the JobService component definition for what is required to be provided in the request body. + *

200 - Successful request. + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

409 - Conflict. The requested operation could not be performed due to a conflicting state that could not be resolved. This usually happens when a CREATE request was performed when there is a pre-existing resource with the same name, and also without one of the options orReplace/ifNotExists. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param jobService The jobService parameter + * @return ResponseSpec + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public ResponseSpec executeJobServiceWithResponseSpec(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull JobService jobService) throws WebClientResponseException { + return executeJobServiceRequestCreation(database, schema, jobService); + } + + /** + * + * Fetch a service. + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @return Service + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + private ResponseSpec fetchServiceRequestCreation(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name) throws WebClientResponseException { + Object postBody = null; + // verify the required parameter 'database' is set + if (database == null) { + throw new WebClientResponseException("Missing the required parameter 'database' when calling fetchService", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'schema' is set + if (schema == null) { + throw new WebClientResponseException("Missing the required parameter 'schema' when calling fetchService", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'name' is set + if (name == null) { + throw new WebClientResponseException("Missing the required parameter 'name' when calling fetchService", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // create path and map variables + final Map pathParams = new HashMap(); + + pathParams.put("database", database); + pathParams.put("schema", schema); + pathParams.put("name", name); + + final MultiValueMap queryParams = new LinkedMultiValueMap(); + final HttpHeaders headerParams = new HttpHeaders(); + final MultiValueMap cookieParams = new LinkedMultiValueMap(); + final MultiValueMap formParams = new LinkedMultiValueMap(); + + final String[] localVarAccepts = { + "application/json" + }; + final List localVarAccept = apiClient.selectHeaderAccept(localVarAccepts); + final String[] localVarContentTypes = { }; + final MediaType localVarContentType = apiClient.selectHeaderContentType(localVarContentTypes); + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return apiClient.invokeAPI("/api/v2/databases/{database}/schemas/{schema}/services/{name}", HttpMethod.GET, pathParams, queryParams, postBody, headerParams, cookieParams, formParams, localVarAccept, localVarContentType, localVarAuthNames, localVarReturnType); + } + + /** + * + * Fetch a service. + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @return Service + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono fetchService(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return fetchServiceRequestCreation(database, schema, name).bodyToMono(localVarReturnType); + } + + /** + * + * Fetch a service. + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @return ResponseEntity<Service> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono> fetchServiceWithHttpInfo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return fetchServiceRequestCreation(database, schema, name).toEntity(localVarReturnType); + } + + /** + * + * Fetch a service. + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @return ResponseSpec + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public ResponseSpec fetchServiceWithResponseSpec(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name) throws WebClientResponseException { + return fetchServiceRequestCreation(database, schema, name); + } + + /** + * + * Fetch the logs for a given service. + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @param instanceId ID of the service instance, starting with 0. + * @param containerName Container name as specified in the service specification file. + * @param numLines Number of trailing log lines to retrieve. + * @return FetchServiceLogs200Response + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + private ResponseSpec fetchServiceLogsRequestCreation(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nonnull Integer instanceId, @javax.annotation.Nonnull String containerName, @javax.annotation.Nullable Integer numLines) throws WebClientResponseException { + Object postBody = null; + // verify the required parameter 'database' is set + if (database == null) { + throw new WebClientResponseException("Missing the required parameter 'database' when calling fetchServiceLogs", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'schema' is set + if (schema == null) { + throw new WebClientResponseException("Missing the required parameter 'schema' when calling fetchServiceLogs", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'name' is set + if (name == null) { + throw new WebClientResponseException("Missing the required parameter 'name' when calling fetchServiceLogs", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'instanceId' is set + if (instanceId == null) { + throw new WebClientResponseException("Missing the required parameter 'instanceId' when calling fetchServiceLogs", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'containerName' is set + if (containerName == null) { + throw new WebClientResponseException("Missing the required parameter 'containerName' when calling fetchServiceLogs", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // create path and map variables + final Map pathParams = new HashMap(); + + pathParams.put("database", database); + pathParams.put("schema", schema); + pathParams.put("name", name); + + final MultiValueMap queryParams = new LinkedMultiValueMap(); + final HttpHeaders headerParams = new HttpHeaders(); + final MultiValueMap cookieParams = new LinkedMultiValueMap(); + final MultiValueMap formParams = new LinkedMultiValueMap(); + + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "instanceId", instanceId)); + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "containerName", containerName)); + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "numLines", numLines)); + + final String[] localVarAccepts = { + "application/json" + }; + final List localVarAccept = apiClient.selectHeaderAccept(localVarAccepts); + final String[] localVarContentTypes = { }; + final MediaType localVarContentType = apiClient.selectHeaderContentType(localVarContentTypes); + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return apiClient.invokeAPI("/api/v2/databases/{database}/schemas/{schema}/services/{name}/logs", HttpMethod.GET, pathParams, queryParams, postBody, headerParams, cookieParams, formParams, localVarAccept, localVarContentType, localVarAuthNames, localVarReturnType); + } + + /** + * + * Fetch the logs for a given service. + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @param instanceId ID of the service instance, starting with 0. + * @param containerName Container name as specified in the service specification file. + * @param numLines Number of trailing log lines to retrieve. + * @return FetchServiceLogs200Response + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono fetchServiceLogs(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nonnull Integer instanceId, @javax.annotation.Nonnull String containerName, @javax.annotation.Nullable Integer numLines) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return fetchServiceLogsRequestCreation(database, schema, name, instanceId, containerName, numLines).bodyToMono(localVarReturnType); + } + + /** + * + * Fetch the logs for a given service. + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @param instanceId ID of the service instance, starting with 0. + * @param containerName Container name as specified in the service specification file. + * @param numLines Number of trailing log lines to retrieve. + * @return ResponseEntity<FetchServiceLogs200Response> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono> fetchServiceLogsWithHttpInfo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nonnull Integer instanceId, @javax.annotation.Nonnull String containerName, @javax.annotation.Nullable Integer numLines) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return fetchServiceLogsRequestCreation(database, schema, name, instanceId, containerName, numLines).toEntity(localVarReturnType); + } + + /** + * + * Fetch the logs for a given service. + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @param instanceId ID of the service instance, starting with 0. + * @param containerName Container name as specified in the service specification file. + * @param numLines Number of trailing log lines to retrieve. + * @return ResponseSpec + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public ResponseSpec fetchServiceLogsWithResponseSpec(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nonnull Integer instanceId, @javax.annotation.Nonnull String containerName, @javax.annotation.Nullable Integer numLines) throws WebClientResponseException { + return fetchServiceLogsRequestCreation(database, schema, name, instanceId, containerName, numLines); + } + + /** + * + * Fetch the status for a given service. Deprecated - use listServiceContainers instead. + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @param timeout Number of seconds to wait for the service to reach a steady state (for example, READY) before returning the status. If the service does not reach a steady state within the specified time, Snowflake returns the current state. + * @return FetchServiceStatus200Response + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + * @deprecated + */ + @Deprecated + private ResponseSpec fetchServiceStatusRequestCreation(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Integer timeout) throws WebClientResponseException { + Object postBody = null; + // verify the required parameter 'database' is set + if (database == null) { + throw new WebClientResponseException("Missing the required parameter 'database' when calling fetchServiceStatus", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'schema' is set + if (schema == null) { + throw new WebClientResponseException("Missing the required parameter 'schema' when calling fetchServiceStatus", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'name' is set + if (name == null) { + throw new WebClientResponseException("Missing the required parameter 'name' when calling fetchServiceStatus", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // create path and map variables + final Map pathParams = new HashMap(); + + pathParams.put("database", database); + pathParams.put("schema", schema); + pathParams.put("name", name); + + final MultiValueMap queryParams = new LinkedMultiValueMap(); + final HttpHeaders headerParams = new HttpHeaders(); + final MultiValueMap cookieParams = new LinkedMultiValueMap(); + final MultiValueMap formParams = new LinkedMultiValueMap(); + + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "timeout", timeout)); + + final String[] localVarAccepts = { + "application/json" + }; + final List localVarAccept = apiClient.selectHeaderAccept(localVarAccepts); + final String[] localVarContentTypes = { }; + final MediaType localVarContentType = apiClient.selectHeaderContentType(localVarContentTypes); + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return apiClient.invokeAPI("/api/v2/databases/{database}/schemas/{schema}/services/{name}/status", HttpMethod.GET, pathParams, queryParams, postBody, headerParams, cookieParams, formParams, localVarAccept, localVarContentType, localVarAuthNames, localVarReturnType); + } + + /** + * + * Fetch the status for a given service. Deprecated - use listServiceContainers instead. + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @param timeout Number of seconds to wait for the service to reach a steady state (for example, READY) before returning the status. If the service does not reach a steady state within the specified time, Snowflake returns the current state. + * @return FetchServiceStatus200Response + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono fetchServiceStatus(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Integer timeout) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return fetchServiceStatusRequestCreation(database, schema, name, timeout).bodyToMono(localVarReturnType); + } + + /** + * + * Fetch the status for a given service. Deprecated - use listServiceContainers instead. + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @param timeout Number of seconds to wait for the service to reach a steady state (for example, READY) before returning the status. If the service does not reach a steady state within the specified time, Snowflake returns the current state. + * @return ResponseEntity<FetchServiceStatus200Response> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono> fetchServiceStatusWithHttpInfo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Integer timeout) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return fetchServiceStatusRequestCreation(database, schema, name, timeout).toEntity(localVarReturnType); + } + + /** + * + * Fetch the status for a given service. Deprecated - use listServiceContainers instead. + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @param timeout Number of seconds to wait for the service to reach a steady state (for example, READY) before returning the status. If the service does not reach a steady state within the specified time, Snowflake returns the current state. + * @return ResponseSpec + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public ResponseSpec fetchServiceStatusWithResponseSpec(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Integer timeout) throws WebClientResponseException { + return fetchServiceStatusRequestCreation(database, schema, name, timeout); + } + + /** + * + * List all the containers of the service + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @return List<ServiceContainer> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + private ResponseSpec listServiceContainersRequestCreation(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name) throws WebClientResponseException { + Object postBody = null; + // verify the required parameter 'database' is set + if (database == null) { + throw new WebClientResponseException("Missing the required parameter 'database' when calling listServiceContainers", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'schema' is set + if (schema == null) { + throw new WebClientResponseException("Missing the required parameter 'schema' when calling listServiceContainers", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'name' is set + if (name == null) { + throw new WebClientResponseException("Missing the required parameter 'name' when calling listServiceContainers", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // create path and map variables + final Map pathParams = new HashMap(); + + pathParams.put("database", database); + pathParams.put("schema", schema); + pathParams.put("name", name); + + final MultiValueMap queryParams = new LinkedMultiValueMap(); + final HttpHeaders headerParams = new HttpHeaders(); + final MultiValueMap cookieParams = new LinkedMultiValueMap(); + final MultiValueMap formParams = new LinkedMultiValueMap(); + + final String[] localVarAccepts = { + "application/json" + }; + final List localVarAccept = apiClient.selectHeaderAccept(localVarAccepts); + final String[] localVarContentTypes = { }; + final MediaType localVarContentType = apiClient.selectHeaderContentType(localVarContentTypes); + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return apiClient.invokeAPI("/api/v2/databases/{database}/schemas/{schema}/services/{name}/containers", HttpMethod.GET, pathParams, queryParams, postBody, headerParams, cookieParams, formParams, localVarAccept, localVarContentType, localVarAuthNames, localVarReturnType); + } + + /** + * + * List all the containers of the service + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @return List<ServiceContainer> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Flux listServiceContainers(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return listServiceContainersRequestCreation(database, schema, name).bodyToFlux(localVarReturnType); + } + + /** + * + * List all the containers of the service + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @return ResponseEntity<List<ServiceContainer>> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono>> listServiceContainersWithHttpInfo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return listServiceContainersRequestCreation(database, schema, name).toEntityList(localVarReturnType); + } + + /** + * + * List all the containers of the service + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @return ResponseSpec + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public ResponseSpec listServiceContainersWithResponseSpec(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name) throws WebClientResponseException { + return listServiceContainersRequestCreation(database, schema, name); + } + + /** + * + * List all the instances of the service + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @return List<ServiceInstance> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + private ResponseSpec listServiceInstancesRequestCreation(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name) throws WebClientResponseException { + Object postBody = null; + // verify the required parameter 'database' is set + if (database == null) { + throw new WebClientResponseException("Missing the required parameter 'database' when calling listServiceInstances", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'schema' is set + if (schema == null) { + throw new WebClientResponseException("Missing the required parameter 'schema' when calling listServiceInstances", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'name' is set + if (name == null) { + throw new WebClientResponseException("Missing the required parameter 'name' when calling listServiceInstances", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // create path and map variables + final Map pathParams = new HashMap(); + + pathParams.put("database", database); + pathParams.put("schema", schema); + pathParams.put("name", name); + + final MultiValueMap queryParams = new LinkedMultiValueMap(); + final HttpHeaders headerParams = new HttpHeaders(); + final MultiValueMap cookieParams = new LinkedMultiValueMap(); + final MultiValueMap formParams = new LinkedMultiValueMap(); + + final String[] localVarAccepts = { + "application/json" + }; + final List localVarAccept = apiClient.selectHeaderAccept(localVarAccepts); + final String[] localVarContentTypes = { }; + final MediaType localVarContentType = apiClient.selectHeaderContentType(localVarContentTypes); + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return apiClient.invokeAPI("/api/v2/databases/{database}/schemas/{schema}/services/{name}/instances", HttpMethod.GET, pathParams, queryParams, postBody, headerParams, cookieParams, formParams, localVarAccept, localVarContentType, localVarAuthNames, localVarReturnType); + } + + /** + * + * List all the instances of the service + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @return List<ServiceInstance> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Flux listServiceInstances(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return listServiceInstancesRequestCreation(database, schema, name).bodyToFlux(localVarReturnType); + } + + /** + * + * List all the instances of the service + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @return ResponseEntity<List<ServiceInstance>> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono>> listServiceInstancesWithHttpInfo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return listServiceInstancesRequestCreation(database, schema, name).toEntityList(localVarReturnType); + } + + /** + * + * List all the instances of the service + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @return ResponseSpec + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public ResponseSpec listServiceInstancesWithResponseSpec(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name) throws WebClientResponseException { + return listServiceInstancesRequestCreation(database, schema, name); + } + + /** + * + * List all the grants of the service role + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param service Name of the service that contains the service role. + * @param name Identifier (i.e. name) for the resource. + * @return List<GrantOf> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + private ResponseSpec listServiceRoleGrantsOfRequestCreation(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String service, @javax.annotation.Nonnull String name) throws WebClientResponseException { + Object postBody = null; + // verify the required parameter 'database' is set + if (database == null) { + throw new WebClientResponseException("Missing the required parameter 'database' when calling listServiceRoleGrantsOf", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'schema' is set + if (schema == null) { + throw new WebClientResponseException("Missing the required parameter 'schema' when calling listServiceRoleGrantsOf", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'service' is set + if (service == null) { + throw new WebClientResponseException("Missing the required parameter 'service' when calling listServiceRoleGrantsOf", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'name' is set + if (name == null) { + throw new WebClientResponseException("Missing the required parameter 'name' when calling listServiceRoleGrantsOf", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // create path and map variables + final Map pathParams = new HashMap(); + + pathParams.put("database", database); + pathParams.put("schema", schema); + pathParams.put("service", service); + pathParams.put("name", name); + + final MultiValueMap queryParams = new LinkedMultiValueMap(); + final HttpHeaders headerParams = new HttpHeaders(); + final MultiValueMap cookieParams = new LinkedMultiValueMap(); + final MultiValueMap formParams = new LinkedMultiValueMap(); + + final String[] localVarAccepts = { + "application/json" + }; + final List localVarAccept = apiClient.selectHeaderAccept(localVarAccepts); + final String[] localVarContentTypes = { }; + final MediaType localVarContentType = apiClient.selectHeaderContentType(localVarContentTypes); + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return apiClient.invokeAPI("/api/v2/databases/{database}/schemas/{schema}/services/{service}/roles/{name}/grants-of", HttpMethod.GET, pathParams, queryParams, postBody, headerParams, cookieParams, formParams, localVarAccept, localVarContentType, localVarAuthNames, localVarReturnType); + } + + /** + * + * List all the grants of the service role + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param service Name of the service that contains the service role. + * @param name Identifier (i.e. name) for the resource. + * @return List<GrantOf> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Flux listServiceRoleGrantsOf(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String service, @javax.annotation.Nonnull String name) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return listServiceRoleGrantsOfRequestCreation(database, schema, service, name).bodyToFlux(localVarReturnType); + } + + /** + * + * List all the grants of the service role + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param service Name of the service that contains the service role. + * @param name Identifier (i.e. name) for the resource. + * @return ResponseEntity<List<GrantOf>> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono>> listServiceRoleGrantsOfWithHttpInfo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String service, @javax.annotation.Nonnull String name) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return listServiceRoleGrantsOfRequestCreation(database, schema, service, name).toEntityList(localVarReturnType); + } + + /** + * + * List all the grants of the service role + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param service Name of the service that contains the service role. + * @param name Identifier (i.e. name) for the resource. + * @return ResponseSpec + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public ResponseSpec listServiceRoleGrantsOfWithResponseSpec(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String service, @javax.annotation.Nonnull String name) throws WebClientResponseException { + return listServiceRoleGrantsOfRequestCreation(database, schema, service, name); + } + + /** + * + * List all the grants given to the service role + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param service Name of the service that contains the service role. + * @param name Identifier (i.e. name) for the resource. + * @return List<ServiceRoleGrantTo> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + private ResponseSpec listServiceRoleGrantsToRequestCreation(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String service, @javax.annotation.Nonnull String name) throws WebClientResponseException { + Object postBody = null; + // verify the required parameter 'database' is set + if (database == null) { + throw new WebClientResponseException("Missing the required parameter 'database' when calling listServiceRoleGrantsTo", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'schema' is set + if (schema == null) { + throw new WebClientResponseException("Missing the required parameter 'schema' when calling listServiceRoleGrantsTo", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'service' is set + if (service == null) { + throw new WebClientResponseException("Missing the required parameter 'service' when calling listServiceRoleGrantsTo", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'name' is set + if (name == null) { + throw new WebClientResponseException("Missing the required parameter 'name' when calling listServiceRoleGrantsTo", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // create path and map variables + final Map pathParams = new HashMap(); + + pathParams.put("database", database); + pathParams.put("schema", schema); + pathParams.put("service", service); + pathParams.put("name", name); + + final MultiValueMap queryParams = new LinkedMultiValueMap(); + final HttpHeaders headerParams = new HttpHeaders(); + final MultiValueMap cookieParams = new LinkedMultiValueMap(); + final MultiValueMap formParams = new LinkedMultiValueMap(); + + final String[] localVarAccepts = { + "application/json" + }; + final List localVarAccept = apiClient.selectHeaderAccept(localVarAccepts); + final String[] localVarContentTypes = { }; + final MediaType localVarContentType = apiClient.selectHeaderContentType(localVarContentTypes); + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return apiClient.invokeAPI("/api/v2/databases/{database}/schemas/{schema}/services/{service}/roles/{name}/grants", HttpMethod.GET, pathParams, queryParams, postBody, headerParams, cookieParams, formParams, localVarAccept, localVarContentType, localVarAuthNames, localVarReturnType); + } + + /** + * + * List all the grants given to the service role + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param service Name of the service that contains the service role. + * @param name Identifier (i.e. name) for the resource. + * @return List<ServiceRoleGrantTo> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Flux listServiceRoleGrantsTo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String service, @javax.annotation.Nonnull String name) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return listServiceRoleGrantsToRequestCreation(database, schema, service, name).bodyToFlux(localVarReturnType); + } + + /** + * + * List all the grants given to the service role + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param service Name of the service that contains the service role. + * @param name Identifier (i.e. name) for the resource. + * @return ResponseEntity<List<ServiceRoleGrantTo>> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono>> listServiceRoleGrantsToWithHttpInfo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String service, @javax.annotation.Nonnull String name) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return listServiceRoleGrantsToRequestCreation(database, schema, service, name).toEntityList(localVarReturnType); + } + + /** + * + * List all the grants given to the service role + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param service Name of the service that contains the service role. + * @param name Identifier (i.e. name) for the resource. + * @return ResponseSpec + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public ResponseSpec listServiceRoleGrantsToWithResponseSpec(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String service, @javax.annotation.Nonnull String name) throws WebClientResponseException { + return listServiceRoleGrantsToRequestCreation(database, schema, service, name); + } + + /** + * + * List all the service roles of the service + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @return List<ServiceRole> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + private ResponseSpec listServiceRolesRequestCreation(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name) throws WebClientResponseException { + Object postBody = null; + // verify the required parameter 'database' is set + if (database == null) { + throw new WebClientResponseException("Missing the required parameter 'database' when calling listServiceRoles", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'schema' is set + if (schema == null) { + throw new WebClientResponseException("Missing the required parameter 'schema' when calling listServiceRoles", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'name' is set + if (name == null) { + throw new WebClientResponseException("Missing the required parameter 'name' when calling listServiceRoles", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // create path and map variables + final Map pathParams = new HashMap(); + + pathParams.put("database", database); + pathParams.put("schema", schema); + pathParams.put("name", name); + + final MultiValueMap queryParams = new LinkedMultiValueMap(); + final HttpHeaders headerParams = new HttpHeaders(); + final MultiValueMap cookieParams = new LinkedMultiValueMap(); + final MultiValueMap formParams = new LinkedMultiValueMap(); + + final String[] localVarAccepts = { + "application/json" + }; + final List localVarAccept = apiClient.selectHeaderAccept(localVarAccepts); + final String[] localVarContentTypes = { }; + final MediaType localVarContentType = apiClient.selectHeaderContentType(localVarContentTypes); + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return apiClient.invokeAPI("/api/v2/databases/{database}/schemas/{schema}/services/{name}/roles", HttpMethod.GET, pathParams, queryParams, postBody, headerParams, cookieParams, formParams, localVarAccept, localVarContentType, localVarAuthNames, localVarReturnType); + } + + /** + * + * List all the service roles of the service + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @return List<ServiceRole> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Flux listServiceRoles(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return listServiceRolesRequestCreation(database, schema, name).bodyToFlux(localVarReturnType); + } + + /** + * + * List all the service roles of the service + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @return ResponseEntity<List<ServiceRole>> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono>> listServiceRolesWithHttpInfo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return listServiceRolesRequestCreation(database, schema, name).toEntityList(localVarReturnType); + } + + /** + * + * List all the service roles of the service + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @return ResponseSpec + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public ResponseSpec listServiceRolesWithResponseSpec(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name) throws WebClientResponseException { + return listServiceRolesRequestCreation(database, schema, name); + } + + /** + * List services + * Lists the services under the database and schema. + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param like Parameter to filter the command output by resource name. Uses case-insensitive pattern matching, with support for SQL wildcard characters. + * @param startsWith Parameter to filter the command output based on the string of characters that appear at the beginning of the object name. Uses case-sensitive pattern matching. + * @param showLimit Parameter to limit the maximum number of rows returned by a command. + * @param fromName Parameter to enable fetching rows only following the first row whose object name matches the specified string. Case-sensitive and does not have to be the full name. + * @return List<Service> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + private ResponseSpec listServicesRequestCreation(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nullable String like, @javax.annotation.Nullable String startsWith, @javax.annotation.Nullable Integer showLimit, @javax.annotation.Nullable String fromName) throws WebClientResponseException { + Object postBody = null; + // verify the required parameter 'database' is set + if (database == null) { + throw new WebClientResponseException("Missing the required parameter 'database' when calling listServices", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'schema' is set + if (schema == null) { + throw new WebClientResponseException("Missing the required parameter 'schema' when calling listServices", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // create path and map variables + final Map pathParams = new HashMap(); + + pathParams.put("database", database); + pathParams.put("schema", schema); + + final MultiValueMap queryParams = new LinkedMultiValueMap(); + final HttpHeaders headerParams = new HttpHeaders(); + final MultiValueMap cookieParams = new LinkedMultiValueMap(); + final MultiValueMap formParams = new LinkedMultiValueMap(); + + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "like", like)); + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "startsWith", startsWith)); + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "showLimit", showLimit)); + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "fromName", fromName)); + + final String[] localVarAccepts = { + "application/json" + }; + final List localVarAccept = apiClient.selectHeaderAccept(localVarAccepts); + final String[] localVarContentTypes = { }; + final MediaType localVarContentType = apiClient.selectHeaderContentType(localVarContentTypes); + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return apiClient.invokeAPI("/api/v2/databases/{database}/schemas/{schema}/services", HttpMethod.GET, pathParams, queryParams, postBody, headerParams, cookieParams, formParams, localVarAccept, localVarContentType, localVarAuthNames, localVarReturnType); + } + + /** + * List services + * Lists the services under the database and schema. + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param like Parameter to filter the command output by resource name. Uses case-insensitive pattern matching, with support for SQL wildcard characters. + * @param startsWith Parameter to filter the command output based on the string of characters that appear at the beginning of the object name. Uses case-sensitive pattern matching. + * @param showLimit Parameter to limit the maximum number of rows returned by a command. + * @param fromName Parameter to enable fetching rows only following the first row whose object name matches the specified string. Case-sensitive and does not have to be the full name. + * @return List<Service> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Flux listServices(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nullable String like, @javax.annotation.Nullable String startsWith, @javax.annotation.Nullable Integer showLimit, @javax.annotation.Nullable String fromName) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return listServicesRequestCreation(database, schema, like, startsWith, showLimit, fromName).bodyToFlux(localVarReturnType); + } + + /** + * List services + * Lists the services under the database and schema. + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param like Parameter to filter the command output by resource name. Uses case-insensitive pattern matching, with support for SQL wildcard characters. + * @param startsWith Parameter to filter the command output based on the string of characters that appear at the beginning of the object name. Uses case-sensitive pattern matching. + * @param showLimit Parameter to limit the maximum number of rows returned by a command. + * @param fromName Parameter to enable fetching rows only following the first row whose object name matches the specified string. Case-sensitive and does not have to be the full name. + * @return ResponseEntity<List<Service>> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono>> listServicesWithHttpInfo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nullable String like, @javax.annotation.Nullable String startsWith, @javax.annotation.Nullable Integer showLimit, @javax.annotation.Nullable String fromName) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return listServicesRequestCreation(database, schema, like, startsWith, showLimit, fromName).toEntityList(localVarReturnType); + } + + /** + * List services + * Lists the services under the database and schema. + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param like Parameter to filter the command output by resource name. Uses case-insensitive pattern matching, with support for SQL wildcard characters. + * @param startsWith Parameter to filter the command output based on the string of characters that appear at the beginning of the object name. Uses case-sensitive pattern matching. + * @param showLimit Parameter to limit the maximum number of rows returned by a command. + * @param fromName Parameter to enable fetching rows only following the first row whose object name matches the specified string. Case-sensitive and does not have to be the full name. + * @return ResponseSpec + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public ResponseSpec listServicesWithResponseSpec(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nullable String like, @javax.annotation.Nullable String startsWith, @javax.annotation.Nullable Integer showLimit, @javax.annotation.Nullable String fromName) throws WebClientResponseException { + return listServicesRequestCreation(database, schema, like, startsWith, showLimit, fromName); + } + + /** + * + * Resume a service. + *

200 - Successful request. + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @param ifExists Parameter that specifies how to handle the request for a resource that does not exist: - `true`: The endpoint does not throw an error if the resource does not exist. It returns a 200 success response, but does not take any action on the resource. - `false`: The endpoint throws an error if the resource doesn't exist. + * @return SuccessResponse + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + private ResponseSpec resumeServiceRequestCreation(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Boolean ifExists) throws WebClientResponseException { + Object postBody = null; + // verify the required parameter 'database' is set + if (database == null) { + throw new WebClientResponseException("Missing the required parameter 'database' when calling resumeService", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'schema' is set + if (schema == null) { + throw new WebClientResponseException("Missing the required parameter 'schema' when calling resumeService", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'name' is set + if (name == null) { + throw new WebClientResponseException("Missing the required parameter 'name' when calling resumeService", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // create path and map variables + final Map pathParams = new HashMap(); + + pathParams.put("database", database); + pathParams.put("schema", schema); + pathParams.put("name", name); + + final MultiValueMap queryParams = new LinkedMultiValueMap(); + final HttpHeaders headerParams = new HttpHeaders(); + final MultiValueMap cookieParams = new LinkedMultiValueMap(); + final MultiValueMap formParams = new LinkedMultiValueMap(); + + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "ifExists", ifExists)); + + final String[] localVarAccepts = { + "application/json" + }; + final List localVarAccept = apiClient.selectHeaderAccept(localVarAccepts); + final String[] localVarContentTypes = { }; + final MediaType localVarContentType = apiClient.selectHeaderContentType(localVarContentTypes); + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return apiClient.invokeAPI("/api/v2/databases/{database}/schemas/{schema}/services/{name}:resume", HttpMethod.POST, pathParams, queryParams, postBody, headerParams, cookieParams, formParams, localVarAccept, localVarContentType, localVarAuthNames, localVarReturnType); + } + + /** + * + * Resume a service. + *

200 - Successful request. + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @param ifExists Parameter that specifies how to handle the request for a resource that does not exist: - `true`: The endpoint does not throw an error if the resource does not exist. It returns a 200 success response, but does not take any action on the resource. - `false`: The endpoint throws an error if the resource doesn't exist. + * @return SuccessResponse + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono resumeService(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Boolean ifExists) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return resumeServiceRequestCreation(database, schema, name, ifExists).bodyToMono(localVarReturnType); + } + + /** + * + * Resume a service. + *

200 - Successful request. + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @param ifExists Parameter that specifies how to handle the request for a resource that does not exist: - `true`: The endpoint does not throw an error if the resource does not exist. It returns a 200 success response, but does not take any action on the resource. - `false`: The endpoint throws an error if the resource doesn't exist. + * @return ResponseEntity<SuccessResponse> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono> resumeServiceWithHttpInfo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Boolean ifExists) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return resumeServiceRequestCreation(database, schema, name, ifExists).toEntity(localVarReturnType); + } + + /** + * + * Resume a service. + *

200 - Successful request. + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @param ifExists Parameter that specifies how to handle the request for a resource that does not exist: - `true`: The endpoint does not throw an error if the resource does not exist. It returns a 200 success response, but does not take any action on the resource. - `false`: The endpoint throws an error if the resource doesn't exist. + * @return ResponseSpec + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public ResponseSpec resumeServiceWithResponseSpec(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Boolean ifExists) throws WebClientResponseException { + return resumeServiceRequestCreation(database, schema, name, ifExists); + } + + /** + * List the endpoints in a service. + * Lists the endpoints in a Snowpark Container Services service (or a job service). + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @return List<ServiceEndpoint> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + private ResponseSpec showServiceEndpointsRequestCreation(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name) throws WebClientResponseException { + Object postBody = null; + // verify the required parameter 'database' is set + if (database == null) { + throw new WebClientResponseException("Missing the required parameter 'database' when calling showServiceEndpoints", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'schema' is set + if (schema == null) { + throw new WebClientResponseException("Missing the required parameter 'schema' when calling showServiceEndpoints", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'name' is set + if (name == null) { + throw new WebClientResponseException("Missing the required parameter 'name' when calling showServiceEndpoints", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // create path and map variables + final Map pathParams = new HashMap(); + + pathParams.put("database", database); + pathParams.put("schema", schema); + pathParams.put("name", name); + + final MultiValueMap queryParams = new LinkedMultiValueMap(); + final HttpHeaders headerParams = new HttpHeaders(); + final MultiValueMap cookieParams = new LinkedMultiValueMap(); + final MultiValueMap formParams = new LinkedMultiValueMap(); + + final String[] localVarAccepts = { + "application/json" + }; + final List localVarAccept = apiClient.selectHeaderAccept(localVarAccepts); + final String[] localVarContentTypes = { }; + final MediaType localVarContentType = apiClient.selectHeaderContentType(localVarContentTypes); + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return apiClient.invokeAPI("/api/v2/databases/{database}/schemas/{schema}/services/{name}/endpoints", HttpMethod.GET, pathParams, queryParams, postBody, headerParams, cookieParams, formParams, localVarAccept, localVarContentType, localVarAuthNames, localVarReturnType); + } + + /** + * List the endpoints in a service. + * Lists the endpoints in a Snowpark Container Services service (or a job service). + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @return List<ServiceEndpoint> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Flux showServiceEndpoints(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return showServiceEndpointsRequestCreation(database, schema, name).bodyToFlux(localVarReturnType); + } + + /** + * List the endpoints in a service. + * Lists the endpoints in a Snowpark Container Services service (or a job service). + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @return ResponseEntity<List<ServiceEndpoint>> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono>> showServiceEndpointsWithHttpInfo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return showServiceEndpointsRequestCreation(database, schema, name).toEntityList(localVarReturnType); + } + + /** + * List the endpoints in a service. + * Lists the endpoints in a Snowpark Container Services service (or a job service). + *

200 - successful + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @return ResponseSpec + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public ResponseSpec showServiceEndpointsWithResponseSpec(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name) throws WebClientResponseException { + return showServiceEndpointsRequestCreation(database, schema, name); + } + + /** + * + * Suspend a service. + *

200 - Successful request. + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @param ifExists Parameter that specifies how to handle the request for a resource that does not exist: - `true`: The endpoint does not throw an error if the resource does not exist. It returns a 200 success response, but does not take any action on the resource. - `false`: The endpoint throws an error if the resource doesn't exist. + * @return SuccessResponse + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + private ResponseSpec suspendServiceRequestCreation(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Boolean ifExists) throws WebClientResponseException { + Object postBody = null; + // verify the required parameter 'database' is set + if (database == null) { + throw new WebClientResponseException("Missing the required parameter 'database' when calling suspendService", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'schema' is set + if (schema == null) { + throw new WebClientResponseException("Missing the required parameter 'schema' when calling suspendService", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'name' is set + if (name == null) { + throw new WebClientResponseException("Missing the required parameter 'name' when calling suspendService", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // create path and map variables + final Map pathParams = new HashMap(); + + pathParams.put("database", database); + pathParams.put("schema", schema); + pathParams.put("name", name); + + final MultiValueMap queryParams = new LinkedMultiValueMap(); + final HttpHeaders headerParams = new HttpHeaders(); + final MultiValueMap cookieParams = new LinkedMultiValueMap(); + final MultiValueMap formParams = new LinkedMultiValueMap(); + + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "ifExists", ifExists)); + + final String[] localVarAccepts = { + "application/json" + }; + final List localVarAccept = apiClient.selectHeaderAccept(localVarAccepts); + final String[] localVarContentTypes = { }; + final MediaType localVarContentType = apiClient.selectHeaderContentType(localVarContentTypes); + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return apiClient.invokeAPI("/api/v2/databases/{database}/schemas/{schema}/services/{name}:suspend", HttpMethod.POST, pathParams, queryParams, postBody, headerParams, cookieParams, formParams, localVarAccept, localVarContentType, localVarAuthNames, localVarReturnType); + } + + /** + * + * Suspend a service. + *

200 - Successful request. + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @param ifExists Parameter that specifies how to handle the request for a resource that does not exist: - `true`: The endpoint does not throw an error if the resource does not exist. It returns a 200 success response, but does not take any action on the resource. - `false`: The endpoint throws an error if the resource doesn't exist. + * @return SuccessResponse + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono suspendService(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Boolean ifExists) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return suspendServiceRequestCreation(database, schema, name, ifExists).bodyToMono(localVarReturnType); + } + + /** + * + * Suspend a service. + *

200 - Successful request. + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @param ifExists Parameter that specifies how to handle the request for a resource that does not exist: - `true`: The endpoint does not throw an error if the resource does not exist. It returns a 200 success response, but does not take any action on the resource. - `false`: The endpoint throws an error if the resource doesn't exist. + * @return ResponseEntity<SuccessResponse> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono> suspendServiceWithHttpInfo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Boolean ifExists) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return suspendServiceRequestCreation(database, schema, name, ifExists).toEntity(localVarReturnType); + } + + /** + * + * Suspend a service. + *

200 - Successful request. + *

202 - Successfully accepted the request, but it is not completed yet. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. + * @param name Identifier (i.e. name) for the resource. + * @param ifExists Parameter that specifies how to handle the request for a resource that does not exist: - `true`: The endpoint does not throw an error if the resource does not exist. It returns a 200 success response, but does not take any action on the resource. - `false`: The endpoint throws an error if the resource doesn't exist. + * @return ResponseSpec + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public ResponseSpec suspendServiceWithResponseSpec(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Boolean ifExists) throws WebClientResponseException { + return suspendServiceRequestCreation(database, schema, name, ifExists); + } +} diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/api/StatementsApi.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/api/StatementsApi.java new file mode 100644 index 00000000..8fbac10a --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/api/StatementsApi.java @@ -0,0 +1,513 @@ +package eu.openanalytics.containerproxy.backend.spcs.client.api; + +import eu.openanalytics.containerproxy.backend.spcs.client.ApiClient; + +import eu.openanalytics.containerproxy.backend.spcs.client.model.CancelStatus; +import eu.openanalytics.containerproxy.backend.spcs.client.model.QueryFailureStatus; +import eu.openanalytics.containerproxy.backend.spcs.client.model.QueryStatus; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ResultSet; +import eu.openanalytics.containerproxy.backend.spcs.client.model.SubmitStatementRequest; +import java.util.UUID; + +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.Arrays; +import java.util.stream.Collectors; + +import org.springframework.core.io.FileSystemResource; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.reactive.function.client.WebClient.ResponseSpec; +import org.springframework.web.reactive.function.client.WebClientResponseException; +import reactor.core.publisher.Mono; +import reactor.core.publisher.Flux; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:41:35.116838100+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class StatementsApi { + private ApiClient apiClient; + + public StatementsApi() { + this(new ApiClient()); + } + + public StatementsApi(ApiClient apiClient) { + this.apiClient = apiClient; + } + + public ApiClient getApiClient() { + return apiClient; + } + + public void setApiClient(ApiClient apiClient) { + this.apiClient = apiClient; + } + + /** + * Cancels the execution of a statement. + * Cancels the execution of the statement with the specified statement handle. + *

200 - The execution of the statement was successfully canceled. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This happens if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint is wrong. For example, if the application hits /api/api/hello which doesn't exist, it will receive this code. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. The application must change a method for retry. + *

422 - An error occurred when cancelling the execution of the statement. Check the error code and error message for details. + *

500 - Internal Server Error. The server hits an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ + * @param statementHandle The handle of the statement that you want to use (e.g. to fetch the result set or cancel execution). + * @param userAgent Set this to the name and version of your application (e.g. “applicationName/applicationVersion”). You must use a value that complies with RFC 7231. + * @param requestId Unique ID of the API request. This ensures that the execution is idempotent. If not specified, a new UUID is generated and assigned. + * @param accept The response payload format. The schema should be specified in resultSetMetaData in the request payload. + * @param xSnowflakeAuthorizationTokenType Specify the authorization token type for the Authorization header. KEYPAIR_JWT is for Keypair JWT or OAUTH for oAuth token. If not specified, OAUTH is assumed. + * @return CancelStatus + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + private ResponseSpec cancelStatementRequestCreation(@javax.annotation.Nonnull UUID statementHandle, @javax.annotation.Nonnull String userAgent, @javax.annotation.Nullable UUID requestId, @javax.annotation.Nullable String accept, @javax.annotation.Nullable String xSnowflakeAuthorizationTokenType) throws WebClientResponseException { + Object postBody = null; + // verify the required parameter 'statementHandle' is set + if (statementHandle == null) { + throw new WebClientResponseException("Missing the required parameter 'statementHandle' when calling cancelStatement", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'userAgent' is set + if (userAgent == null) { + throw new WebClientResponseException("Missing the required parameter 'userAgent' when calling cancelStatement", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // create path and map variables + final Map pathParams = new HashMap(); + + pathParams.put("statementHandle", statementHandle); + + final MultiValueMap queryParams = new LinkedMultiValueMap(); + final HttpHeaders headerParams = new HttpHeaders(); + final MultiValueMap cookieParams = new LinkedMultiValueMap(); + final MultiValueMap formParams = new LinkedMultiValueMap(); + + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "requestId", requestId)); + + if (accept != null) + headerParams.add("Accept", apiClient.parameterToString(accept)); + if (userAgent != null) + headerParams.add("User-Agent", apiClient.parameterToString(userAgent)); + if (xSnowflakeAuthorizationTokenType != null) + headerParams.add("X-Snowflake-Authorization-Token-Type", apiClient.parameterToString(xSnowflakeAuthorizationTokenType)); + final String[] localVarAccepts = { + "application/json" + }; + final List localVarAccept = apiClient.selectHeaderAccept(localVarAccepts); + final String[] localVarContentTypes = { }; + final MediaType localVarContentType = apiClient.selectHeaderContentType(localVarContentTypes); + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return apiClient.invokeAPI("/api/v2/statements/{statementHandle}/cancel", HttpMethod.POST, pathParams, queryParams, postBody, headerParams, cookieParams, formParams, localVarAccept, localVarContentType, localVarAuthNames, localVarReturnType); + } + + /** + * Cancels the execution of a statement. + * Cancels the execution of the statement with the specified statement handle. + *

200 - The execution of the statement was successfully canceled. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This happens if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint is wrong. For example, if the application hits /api/api/hello which doesn't exist, it will receive this code. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. The application must change a method for retry. + *

422 - An error occurred when cancelling the execution of the statement. Check the error code and error message for details. + *

500 - Internal Server Error. The server hits an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ + * @param statementHandle The handle of the statement that you want to use (e.g. to fetch the result set or cancel execution). + * @param userAgent Set this to the name and version of your application (e.g. “applicationName/applicationVersion”). You must use a value that complies with RFC 7231. + * @param requestId Unique ID of the API request. This ensures that the execution is idempotent. If not specified, a new UUID is generated and assigned. + * @param accept The response payload format. The schema should be specified in resultSetMetaData in the request payload. + * @param xSnowflakeAuthorizationTokenType Specify the authorization token type for the Authorization header. KEYPAIR_JWT is for Keypair JWT or OAUTH for oAuth token. If not specified, OAUTH is assumed. + * @return CancelStatus + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono cancelStatement(@javax.annotation.Nonnull UUID statementHandle, @javax.annotation.Nonnull String userAgent, @javax.annotation.Nullable UUID requestId, @javax.annotation.Nullable String accept, @javax.annotation.Nullable String xSnowflakeAuthorizationTokenType) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return cancelStatementRequestCreation(statementHandle, userAgent, requestId, accept, xSnowflakeAuthorizationTokenType).bodyToMono(localVarReturnType); + } + + /** + * Cancels the execution of a statement. + * Cancels the execution of the statement with the specified statement handle. + *

200 - The execution of the statement was successfully canceled. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This happens if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint is wrong. For example, if the application hits /api/api/hello which doesn't exist, it will receive this code. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. The application must change a method for retry. + *

422 - An error occurred when cancelling the execution of the statement. Check the error code and error message for details. + *

500 - Internal Server Error. The server hits an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ + * @param statementHandle The handle of the statement that you want to use (e.g. to fetch the result set or cancel execution). + * @param userAgent Set this to the name and version of your application (e.g. “applicationName/applicationVersion”). You must use a value that complies with RFC 7231. + * @param requestId Unique ID of the API request. This ensures that the execution is idempotent. If not specified, a new UUID is generated and assigned. + * @param accept The response payload format. The schema should be specified in resultSetMetaData in the request payload. + * @param xSnowflakeAuthorizationTokenType Specify the authorization token type for the Authorization header. KEYPAIR_JWT is for Keypair JWT or OAUTH for oAuth token. If not specified, OAUTH is assumed. + * @return ResponseEntity<CancelStatus> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono> cancelStatementWithHttpInfo(@javax.annotation.Nonnull UUID statementHandle, @javax.annotation.Nonnull String userAgent, @javax.annotation.Nullable UUID requestId, @javax.annotation.Nullable String accept, @javax.annotation.Nullable String xSnowflakeAuthorizationTokenType) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return cancelStatementRequestCreation(statementHandle, userAgent, requestId, accept, xSnowflakeAuthorizationTokenType).toEntity(localVarReturnType); + } + + /** + * Cancels the execution of a statement. + * Cancels the execution of the statement with the specified statement handle. + *

200 - The execution of the statement was successfully canceled. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This happens if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint is wrong. For example, if the application hits /api/api/hello which doesn't exist, it will receive this code. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. The application must change a method for retry. + *

422 - An error occurred when cancelling the execution of the statement. Check the error code and error message for details. + *

500 - Internal Server Error. The server hits an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ + * @param statementHandle The handle of the statement that you want to use (e.g. to fetch the result set or cancel execution). + * @param userAgent Set this to the name and version of your application (e.g. “applicationName/applicationVersion”). You must use a value that complies with RFC 7231. + * @param requestId Unique ID of the API request. This ensures that the execution is idempotent. If not specified, a new UUID is generated and assigned. + * @param accept The response payload format. The schema should be specified in resultSetMetaData in the request payload. + * @param xSnowflakeAuthorizationTokenType Specify the authorization token type for the Authorization header. KEYPAIR_JWT is for Keypair JWT or OAUTH for oAuth token. If not specified, OAUTH is assumed. + * @return ResponseSpec + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public ResponseSpec cancelStatementWithResponseSpec(@javax.annotation.Nonnull UUID statementHandle, @javax.annotation.Nonnull String userAgent, @javax.annotation.Nullable UUID requestId, @javax.annotation.Nullable String accept, @javax.annotation.Nullable String xSnowflakeAuthorizationTokenType) throws WebClientResponseException { + return cancelStatementRequestCreation(statementHandle, userAgent, requestId, accept, xSnowflakeAuthorizationTokenType); + } + + /** + * Checks the status of the execution of a statement + * Checks the status of the execution of the statement with the specified statement handle. If the statement was executed successfully, the operation returns the requested partition of the result set. + *

200 - The statement was executed successfully, and the response includes any data requested. + *

202 - The execution of the statement is still in progress. Use this method again to check the status of the statement execution. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This happens if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint is wrong. For example, if the application hits /api/api/hello which doesn't exist, it will receive this code. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. The application must change a method for retry. + *

415 - The request header Content-Type includes unsupported media type. The API supports application/json only. If none specified, the request payload is taken as JSON, but if any other media type is specified, this error is returned. + *

422 - An error occurred when executing the statement. Check the error code and error message for details. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hits an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ + * @param statementHandle The handle of the statement that you want to use (e.g. to fetch the result set or cancel execution). + * @param userAgent Set this to the name and version of your application (e.g. “applicationName/applicationVersion”). You must use a value that complies with RFC 7231. + * @param requestId Unique ID of the API request. This ensures that the execution is idempotent. If not specified, a new UUID is generated and assigned. + * @param partition Number of the partition of results to return. The number can range from 0 to the total number of partitions minus 1. + * @param accept The response payload format. The schema should be specified in resultSetMetaData in the request payload. + * @param xSnowflakeAuthorizationTokenType Specify the authorization token type for the Authorization header. KEYPAIR_JWT is for Keypair JWT or OAUTH for oAuth token. If not specified, OAUTH is assumed. + * @return ResultSet + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + private ResponseSpec getStatementStatusRequestCreation(@javax.annotation.Nonnull UUID statementHandle, @javax.annotation.Nonnull String userAgent, @javax.annotation.Nullable UUID requestId, @javax.annotation.Nullable Long partition, @javax.annotation.Nullable String accept, @javax.annotation.Nullable String xSnowflakeAuthorizationTokenType) throws WebClientResponseException { + Object postBody = null; + // verify the required parameter 'statementHandle' is set + if (statementHandle == null) { + throw new WebClientResponseException("Missing the required parameter 'statementHandle' when calling getStatementStatus", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'userAgent' is set + if (userAgent == null) { + throw new WebClientResponseException("Missing the required parameter 'userAgent' when calling getStatementStatus", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // create path and map variables + final Map pathParams = new HashMap(); + + pathParams.put("statementHandle", statementHandle); + + final MultiValueMap queryParams = new LinkedMultiValueMap(); + final HttpHeaders headerParams = new HttpHeaders(); + final MultiValueMap cookieParams = new LinkedMultiValueMap(); + final MultiValueMap formParams = new LinkedMultiValueMap(); + + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "requestId", requestId)); + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "partition", partition)); + + if (accept != null) + headerParams.add("Accept", apiClient.parameterToString(accept)); + if (userAgent != null) + headerParams.add("User-Agent", apiClient.parameterToString(userAgent)); + if (xSnowflakeAuthorizationTokenType != null) + headerParams.add("X-Snowflake-Authorization-Token-Type", apiClient.parameterToString(xSnowflakeAuthorizationTokenType)); + final String[] localVarAccepts = { + "application/json" + }; + final List localVarAccept = apiClient.selectHeaderAccept(localVarAccepts); + final String[] localVarContentTypes = { }; + final MediaType localVarContentType = apiClient.selectHeaderContentType(localVarContentTypes); + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return apiClient.invokeAPI("/api/v2/statements/{statementHandle}", HttpMethod.GET, pathParams, queryParams, postBody, headerParams, cookieParams, formParams, localVarAccept, localVarContentType, localVarAuthNames, localVarReturnType); + } + + /** + * Checks the status of the execution of a statement + * Checks the status of the execution of the statement with the specified statement handle. If the statement was executed successfully, the operation returns the requested partition of the result set. + *

200 - The statement was executed successfully, and the response includes any data requested. + *

202 - The execution of the statement is still in progress. Use this method again to check the status of the statement execution. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This happens if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint is wrong. For example, if the application hits /api/api/hello which doesn't exist, it will receive this code. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. The application must change a method for retry. + *

415 - The request header Content-Type includes unsupported media type. The API supports application/json only. If none specified, the request payload is taken as JSON, but if any other media type is specified, this error is returned. + *

422 - An error occurred when executing the statement. Check the error code and error message for details. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hits an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ + * @param statementHandle The handle of the statement that you want to use (e.g. to fetch the result set or cancel execution). + * @param userAgent Set this to the name and version of your application (e.g. “applicationName/applicationVersion”). You must use a value that complies with RFC 7231. + * @param requestId Unique ID of the API request. This ensures that the execution is idempotent. If not specified, a new UUID is generated and assigned. + * @param partition Number of the partition of results to return. The number can range from 0 to the total number of partitions minus 1. + * @param accept The response payload format. The schema should be specified in resultSetMetaData in the request payload. + * @param xSnowflakeAuthorizationTokenType Specify the authorization token type for the Authorization header. KEYPAIR_JWT is for Keypair JWT or OAUTH for oAuth token. If not specified, OAUTH is assumed. + * @return ResultSet + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono getStatementStatus(@javax.annotation.Nonnull UUID statementHandle, @javax.annotation.Nonnull String userAgent, @javax.annotation.Nullable UUID requestId, @javax.annotation.Nullable Long partition, @javax.annotation.Nullable String accept, @javax.annotation.Nullable String xSnowflakeAuthorizationTokenType) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return getStatementStatusRequestCreation(statementHandle, userAgent, requestId, partition, accept, xSnowflakeAuthorizationTokenType).bodyToMono(localVarReturnType); + } + + /** + * Checks the status of the execution of a statement + * Checks the status of the execution of the statement with the specified statement handle. If the statement was executed successfully, the operation returns the requested partition of the result set. + *

200 - The statement was executed successfully, and the response includes any data requested. + *

202 - The execution of the statement is still in progress. Use this method again to check the status of the statement execution. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This happens if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint is wrong. For example, if the application hits /api/api/hello which doesn't exist, it will receive this code. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. The application must change a method for retry. + *

415 - The request header Content-Type includes unsupported media type. The API supports application/json only. If none specified, the request payload is taken as JSON, but if any other media type is specified, this error is returned. + *

422 - An error occurred when executing the statement. Check the error code and error message for details. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hits an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ + * @param statementHandle The handle of the statement that you want to use (e.g. to fetch the result set or cancel execution). + * @param userAgent Set this to the name and version of your application (e.g. “applicationName/applicationVersion”). You must use a value that complies with RFC 7231. + * @param requestId Unique ID of the API request. This ensures that the execution is idempotent. If not specified, a new UUID is generated and assigned. + * @param partition Number of the partition of results to return. The number can range from 0 to the total number of partitions minus 1. + * @param accept The response payload format. The schema should be specified in resultSetMetaData in the request payload. + * @param xSnowflakeAuthorizationTokenType Specify the authorization token type for the Authorization header. KEYPAIR_JWT is for Keypair JWT or OAUTH for oAuth token. If not specified, OAUTH is assumed. + * @return ResponseEntity<ResultSet> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono> getStatementStatusWithHttpInfo(@javax.annotation.Nonnull UUID statementHandle, @javax.annotation.Nonnull String userAgent, @javax.annotation.Nullable UUID requestId, @javax.annotation.Nullable Long partition, @javax.annotation.Nullable String accept, @javax.annotation.Nullable String xSnowflakeAuthorizationTokenType) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return getStatementStatusRequestCreation(statementHandle, userAgent, requestId, partition, accept, xSnowflakeAuthorizationTokenType).toEntity(localVarReturnType); + } + + /** + * Checks the status of the execution of a statement + * Checks the status of the execution of the statement with the specified statement handle. If the statement was executed successfully, the operation returns the requested partition of the result set. + *

200 - The statement was executed successfully, and the response includes any data requested. + *

202 - The execution of the statement is still in progress. Use this method again to check the status of the statement execution. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This happens if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint is wrong. For example, if the application hits /api/api/hello which doesn't exist, it will receive this code. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. The application must change a method for retry. + *

415 - The request header Content-Type includes unsupported media type. The API supports application/json only. If none specified, the request payload is taken as JSON, but if any other media type is specified, this error is returned. + *

422 - An error occurred when executing the statement. Check the error code and error message for details. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hits an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ + * @param statementHandle The handle of the statement that you want to use (e.g. to fetch the result set or cancel execution). + * @param userAgent Set this to the name and version of your application (e.g. “applicationName/applicationVersion”). You must use a value that complies with RFC 7231. + * @param requestId Unique ID of the API request. This ensures that the execution is idempotent. If not specified, a new UUID is generated and assigned. + * @param partition Number of the partition of results to return. The number can range from 0 to the total number of partitions minus 1. + * @param accept The response payload format. The schema should be specified in resultSetMetaData in the request payload. + * @param xSnowflakeAuthorizationTokenType Specify the authorization token type for the Authorization header. KEYPAIR_JWT is for Keypair JWT or OAUTH for oAuth token. If not specified, OAUTH is assumed. + * @return ResponseSpec + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public ResponseSpec getStatementStatusWithResponseSpec(@javax.annotation.Nonnull UUID statementHandle, @javax.annotation.Nonnull String userAgent, @javax.annotation.Nullable UUID requestId, @javax.annotation.Nullable Long partition, @javax.annotation.Nullable String accept, @javax.annotation.Nullable String xSnowflakeAuthorizationTokenType) throws WebClientResponseException { + return getStatementStatusRequestCreation(statementHandle, userAgent, requestId, partition, accept, xSnowflakeAuthorizationTokenType); + } + + /** + * Submits a SQL statement for execution. + * Submits one or more statements for execution. You can specify that the statement should be executed asynchronously. + *

200 - The statement was executed successfully, and the response includes any data requested. + *

202 - The execution of the statement is still in progress. Use GET /statements/ and specify the statement handle to check the status of the statement execution. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This happens if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint is wrong. For example, if the application hits /api/api/hello which doesn't exist, it will receive this code. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. The application must change a method for retry. + *

408 - The execution of the statement exceeded the timeout period. The execution of the statement was cancelled. + *

415 - The request header Content-Type includes unsupported media type. The API supports application/json only. If none specified, the request payload is taken as JSON, but if any other media type is specified, this error is returned. + *

422 - An error occurred when executing the statement. Check the error code and error message for details. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hits an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ + * @param userAgent Set this to the name and version of your application (e.g. “applicationName/applicationVersion”). You must use a value that complies with RFC 7231. + * @param submitStatementRequest Specifies the SQL statement to execute and the statement context. + * @param requestId Unique ID of the API request. This ensures that the execution is idempotent. If not specified, a new UUID is generated and assigned. + * @param async Set to true to execute the statement asynchronously and return the statement handle. If the parameter is not specified or is set to false, a statement is executed and the first result is returned if the execution is completed in 45 seconds. If the statement execution takes longer to complete, the statement handle is returned. + * @param nullable Set to true to execute the statement to generate the result set including null. If the parameter is set to false, the result set value null will be replaced with a string 'null'. + * @param accept The response payload format. The schema should be specified in resultSetMetaData in the request payload. + * @param xSnowflakeAuthorizationTokenType Specify the authorization token type for the Authorization header. KEYPAIR_JWT is for Keypair JWT or OAUTH for oAuth token. If not specified, OAUTH is assumed. + * @return ResultSet + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + private ResponseSpec submitStatementRequestCreation(@javax.annotation.Nonnull String userAgent, @javax.annotation.Nonnull SubmitStatementRequest submitStatementRequest, @javax.annotation.Nullable UUID requestId, @javax.annotation.Nullable Boolean async, @javax.annotation.Nullable Boolean nullable, @javax.annotation.Nullable String accept, @javax.annotation.Nullable String xSnowflakeAuthorizationTokenType) throws WebClientResponseException { + Object postBody = submitStatementRequest; + // verify the required parameter 'userAgent' is set + if (userAgent == null) { + throw new WebClientResponseException("Missing the required parameter 'userAgent' when calling submitStatement", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // verify the required parameter 'submitStatementRequest' is set + if (submitStatementRequest == null) { + throw new WebClientResponseException("Missing the required parameter 'submitStatementRequest' when calling submitStatement", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null); + } + // create path and map variables + final Map pathParams = new HashMap(); + + final MultiValueMap queryParams = new LinkedMultiValueMap(); + final HttpHeaders headerParams = new HttpHeaders(); + final MultiValueMap cookieParams = new LinkedMultiValueMap(); + final MultiValueMap formParams = new LinkedMultiValueMap(); + + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "requestId", requestId)); + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "async", async)); + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "nullable", nullable)); + + if (accept != null) + headerParams.add("Accept", apiClient.parameterToString(accept)); + if (userAgent != null) + headerParams.add("User-Agent", apiClient.parameterToString(userAgent)); + if (xSnowflakeAuthorizationTokenType != null) + headerParams.add("X-Snowflake-Authorization-Token-Type", apiClient.parameterToString(xSnowflakeAuthorizationTokenType)); + final String[] localVarAccepts = { + "application/json" + }; + final List localVarAccept = apiClient.selectHeaderAccept(localVarAccepts); + final String[] localVarContentTypes = { + "application/json" + }; + final MediaType localVarContentType = apiClient.selectHeaderContentType(localVarContentTypes); + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return apiClient.invokeAPI("/api/v2/statements", HttpMethod.POST, pathParams, queryParams, postBody, headerParams, cookieParams, formParams, localVarAccept, localVarContentType, localVarAuthNames, localVarReturnType); + } + + /** + * Submits a SQL statement for execution. + * Submits one or more statements for execution. You can specify that the statement should be executed asynchronously. + *

200 - The statement was executed successfully, and the response includes any data requested. + *

202 - The execution of the statement is still in progress. Use GET /statements/ and specify the statement handle to check the status of the statement execution. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This happens if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint is wrong. For example, if the application hits /api/api/hello which doesn't exist, it will receive this code. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. The application must change a method for retry. + *

408 - The execution of the statement exceeded the timeout period. The execution of the statement was cancelled. + *

415 - The request header Content-Type includes unsupported media type. The API supports application/json only. If none specified, the request payload is taken as JSON, but if any other media type is specified, this error is returned. + *

422 - An error occurred when executing the statement. Check the error code and error message for details. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hits an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ + * @param userAgent Set this to the name and version of your application (e.g. “applicationName/applicationVersion”). You must use a value that complies with RFC 7231. + * @param submitStatementRequest Specifies the SQL statement to execute and the statement context. + * @param requestId Unique ID of the API request. This ensures that the execution is idempotent. If not specified, a new UUID is generated and assigned. + * @param async Set to true to execute the statement asynchronously and return the statement handle. If the parameter is not specified or is set to false, a statement is executed and the first result is returned if the execution is completed in 45 seconds. If the statement execution takes longer to complete, the statement handle is returned. + * @param nullable Set to true to execute the statement to generate the result set including null. If the parameter is set to false, the result set value null will be replaced with a string 'null'. + * @param accept The response payload format. The schema should be specified in resultSetMetaData in the request payload. + * @param xSnowflakeAuthorizationTokenType Specify the authorization token type for the Authorization header. KEYPAIR_JWT is for Keypair JWT or OAUTH for oAuth token. If not specified, OAUTH is assumed. + * @return ResultSet + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono submitStatement(@javax.annotation.Nonnull String userAgent, @javax.annotation.Nonnull SubmitStatementRequest submitStatementRequest, @javax.annotation.Nullable UUID requestId, @javax.annotation.Nullable Boolean async, @javax.annotation.Nullable Boolean nullable, @javax.annotation.Nullable String accept, @javax.annotation.Nullable String xSnowflakeAuthorizationTokenType) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return submitStatementRequestCreation(userAgent, submitStatementRequest, requestId, async, nullable, accept, xSnowflakeAuthorizationTokenType).bodyToMono(localVarReturnType); + } + + /** + * Submits a SQL statement for execution. + * Submits one or more statements for execution. You can specify that the statement should be executed asynchronously. + *

200 - The statement was executed successfully, and the response includes any data requested. + *

202 - The execution of the statement is still in progress. Use GET /statements/ and specify the statement handle to check the status of the statement execution. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This happens if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint is wrong. For example, if the application hits /api/api/hello which doesn't exist, it will receive this code. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. The application must change a method for retry. + *

408 - The execution of the statement exceeded the timeout period. The execution of the statement was cancelled. + *

415 - The request header Content-Type includes unsupported media type. The API supports application/json only. If none specified, the request payload is taken as JSON, but if any other media type is specified, this error is returned. + *

422 - An error occurred when executing the statement. Check the error code and error message for details. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hits an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ + * @param userAgent Set this to the name and version of your application (e.g. “applicationName/applicationVersion”). You must use a value that complies with RFC 7231. + * @param submitStatementRequest Specifies the SQL statement to execute and the statement context. + * @param requestId Unique ID of the API request. This ensures that the execution is idempotent. If not specified, a new UUID is generated and assigned. + * @param async Set to true to execute the statement asynchronously and return the statement handle. If the parameter is not specified or is set to false, a statement is executed and the first result is returned if the execution is completed in 45 seconds. If the statement execution takes longer to complete, the statement handle is returned. + * @param nullable Set to true to execute the statement to generate the result set including null. If the parameter is set to false, the result set value null will be replaced with a string 'null'. + * @param accept The response payload format. The schema should be specified in resultSetMetaData in the request payload. + * @param xSnowflakeAuthorizationTokenType Specify the authorization token type for the Authorization header. KEYPAIR_JWT is for Keypair JWT or OAUTH for oAuth token. If not specified, OAUTH is assumed. + * @return ResponseEntity<ResultSet> + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public Mono> submitStatementWithHttpInfo(@javax.annotation.Nonnull String userAgent, @javax.annotation.Nonnull SubmitStatementRequest submitStatementRequest, @javax.annotation.Nullable UUID requestId, @javax.annotation.Nullable Boolean async, @javax.annotation.Nullable Boolean nullable, @javax.annotation.Nullable String accept, @javax.annotation.Nullable String xSnowflakeAuthorizationTokenType) throws WebClientResponseException { + ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference() {}; + return submitStatementRequestCreation(userAgent, submitStatementRequest, requestId, async, nullable, accept, xSnowflakeAuthorizationTokenType).toEntity(localVarReturnType); + } + + /** + * Submits a SQL statement for execution. + * Submits one or more statements for execution. You can specify that the statement should be executed asynchronously. + *

200 - The statement was executed successfully, and the response includes any data requested. + *

202 - The execution of the statement is still in progress. Use GET /statements/ and specify the statement handle to check the status of the statement execution. + *

400 - Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. + *

401 - Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. + *

403 - Forbidden. The request is forbidden. This happens if the request is made even if the API is not enabled. + *

404 - Not Found. The request endpoint is not valid. This happens if the API endpoint is wrong. For example, if the application hits /api/api/hello which doesn't exist, it will receive this code. + *

405 - Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. The application must change a method for retry. + *

408 - The execution of the statement exceeded the timeout period. The execution of the statement was cancelled. + *

415 - The request header Content-Type includes unsupported media type. The API supports application/json only. If none specified, the request payload is taken as JSON, but if any other media type is specified, this error is returned. + *

422 - An error occurred when executing the statement. Check the error code and error message for details. + *

429 - Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. + *

500 - Internal Server Error. The server hits an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. + *

503 - Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ + *

504 - Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ + * @param userAgent Set this to the name and version of your application (e.g. “applicationName/applicationVersion”). You must use a value that complies with RFC 7231. + * @param submitStatementRequest Specifies the SQL statement to execute and the statement context. + * @param requestId Unique ID of the API request. This ensures that the execution is idempotent. If not specified, a new UUID is generated and assigned. + * @param async Set to true to execute the statement asynchronously and return the statement handle. If the parameter is not specified or is set to false, a statement is executed and the first result is returned if the execution is completed in 45 seconds. If the statement execution takes longer to complete, the statement handle is returned. + * @param nullable Set to true to execute the statement to generate the result set including null. If the parameter is set to false, the result set value null will be replaced with a string 'null'. + * @param accept The response payload format. The schema should be specified in resultSetMetaData in the request payload. + * @param xSnowflakeAuthorizationTokenType Specify the authorization token type for the Authorization header. KEYPAIR_JWT is for Keypair JWT or OAUTH for oAuth token. If not specified, OAUTH is assumed. + * @return ResponseSpec + * @throws WebClientResponseException if an error occurs while attempting to invoke the API + */ + public ResponseSpec submitStatementWithResponseSpec(@javax.annotation.Nonnull String userAgent, @javax.annotation.Nonnull SubmitStatementRequest submitStatementRequest, @javax.annotation.Nullable UUID requestId, @javax.annotation.Nullable Boolean async, @javax.annotation.Nullable Boolean nullable, @javax.annotation.Nullable String accept, @javax.annotation.Nullable String xSnowflakeAuthorizationTokenType) throws WebClientResponseException { + return submitStatementRequestCreation(userAgent, submitStatementRequest, requestId, async, nullable, accept, xSnowflakeAuthorizationTokenType); + } +} diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/ApiKeyAuth.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/ApiKeyAuth.java new file mode 100644 index 00000000..021f5dde --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/ApiKeyAuth.java @@ -0,0 +1,75 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.auth; + +import org.springframework.http.HttpHeaders; +import org.springframework.util.MultiValueMap; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:42:29.597406700+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ApiKeyAuth implements Authentication { + private final String location; + private final String paramName; + + private String apiKey; + private String apiKeyPrefix; + + public ApiKeyAuth(String location, String paramName) { + this.location = location; + this.paramName = paramName; + } + + public String getLocation() { + return location; + } + + public String getParamName() { + return paramName; + } + + public String getApiKey() { + return apiKey; + } + + public void setApiKey(String apiKey) { + this.apiKey = apiKey; + } + + public String getApiKeyPrefix() { + return apiKeyPrefix; + } + + public void setApiKeyPrefix(String apiKeyPrefix) { + this.apiKeyPrefix = apiKeyPrefix; + } + + @Override + public void applyToParams(MultiValueMap queryParams, HttpHeaders headerParams, MultiValueMap cookieParams) { + if (apiKey == null) { + return; + } + String value; + if (apiKeyPrefix != null) { + value = apiKeyPrefix + " " + apiKey; + } else { + value = apiKey; + } + if (location.equals("query")) { + queryParams.add(paramName, value); + } else if (location.equals("header")) { + headerParams.add(paramName, value); + } else if (location.equals("cookie")) { + cookieParams.add(paramName, value); + } + } +} diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/Authentication.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/Authentication.java new file mode 100644 index 00000000..86c8312b --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/Authentication.java @@ -0,0 +1,29 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.auth; + +import org.springframework.http.HttpHeaders; +import org.springframework.util.MultiValueMap; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:42:29.597406700+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public interface Authentication { + /** + * Apply authentication settings to header and / or query parameters. + * + * @param queryParams The query parameters for the request + * @param headerParams The header parameters for the request + * @param cookieParams The cookie parameters for the request + */ + void applyToParams(MultiValueMap queryParams, HttpHeaders headerParams, MultiValueMap cookieParams); +} diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/HttpBasicAuth.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/HttpBasicAuth.java new file mode 100644 index 00000000..e45e2e79 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/HttpBasicAuth.java @@ -0,0 +1,51 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.auth; + +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +import org.springframework.http.HttpHeaders; +import org.springframework.util.MultiValueMap; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:42:29.597406700+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class HttpBasicAuth implements Authentication { + private String username; + private String password; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + @Override + public void applyToParams(MultiValueMap queryParams, HttpHeaders headerParams, MultiValueMap cookieParams) { + if (username == null && password == null) { + return; + } + String str = (username == null ? "" : username) + ":" + (password == null ? "" : password); + headerParams.add(HttpHeaders.AUTHORIZATION, "Basic " + Base64.getEncoder().encodeToString(str.getBytes(StandardCharsets.UTF_8))); + } +} diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/HttpBearerAuth.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/HttpBearerAuth.java new file mode 100644 index 00000000..c04ac3bf --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/HttpBearerAuth.java @@ -0,0 +1,63 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.auth; + +import org.springframework.http.HttpHeaders; +import org.springframework.util.MultiValueMap; + +import java.util.function.Supplier; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:42:29.597406700+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class HttpBearerAuth implements Authentication { + private final String scheme; + private String bearerToken; + /** Optional: when set, token is resolved per request (e.g. for SPCS session token file). */ + private Supplier bearerTokenSupplier; + + public HttpBearerAuth(String scheme) { + this.scheme = scheme; + } + + public String getBearerToken() { + return bearerToken; + } + + public void setBearerToken(String bearerToken) { + this.bearerToken = bearerToken; + this.bearerTokenSupplier = null; + } + + /** + * Set a supplier so the token is resolved on each request. + * Use for SPCS session token (file can be updated) or keypair JWT (refresh on expiry). + */ + public void setBearerToken(Supplier bearerTokenSupplier) { + this.bearerTokenSupplier = bearerTokenSupplier; + this.bearerToken = null; + } + + @Override + public void applyToParams(MultiValueMap queryParams, HttpHeaders headerParams, MultiValueMap cookieParams) { + String token = bearerTokenSupplier != null ? bearerTokenSupplier.get() : bearerToken; + if (token == null) { + return; + } + headerParams.add(HttpHeaders.AUTHORIZATION, (scheme != null ? upperCaseBearer(scheme) + " " : "") + token); + } + + private static String upperCaseBearer(String scheme) { + return ("bearer".equalsIgnoreCase(scheme)) ? "Bearer" : scheme; + } + +} diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/OAuth.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/OAuth.java new file mode 100644 index 00000000..dac1f0f5 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/OAuth.java @@ -0,0 +1,37 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.auth; + +import org.springframework.http.HttpHeaders; +import org.springframework.util.MultiValueMap; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:42:29.597406700+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class OAuth implements Authentication { + private String accessToken; + + public String getAccessToken() { + return accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + @Override + public void applyToParams(MultiValueMap queryParams, HttpHeaders headerParams, MultiValueMap cookieParams) { + if (accessToken != null) { + headerParams.add(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken); + } + } +} diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/CancelStatus.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/CancelStatus.java new file mode 100644 index 00000000..9053d5a8 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/CancelStatus.java @@ -0,0 +1,236 @@ +/* + * Snowflake SQL API + * The Snowflake SQL API is a REST API that you can use to access and update data in a Snowflake database. + * + * The version of the OpenAPI document: 2.0.0 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Arrays; +import java.util.Locale; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import java.net.URI; +import java.util.UUID; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * CancelStatus + */ +@JsonPropertyOrder({ + CancelStatus.JSON_PROPERTY_CODE, + CancelStatus.JSON_PROPERTY_SQL_STATE, + CancelStatus.JSON_PROPERTY_MESSAGE, + CancelStatus.JSON_PROPERTY_STATEMENT_HANDLE, + CancelStatus.JSON_PROPERTY_STATEMENT_STATUS_URL +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:41:35.116838100+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class CancelStatus { + public static final String JSON_PROPERTY_CODE = "code"; + @javax.annotation.Nullable + private String code; + + public static final String JSON_PROPERTY_SQL_STATE = "sqlState"; + @javax.annotation.Nullable + private String sqlState; + + public static final String JSON_PROPERTY_MESSAGE = "message"; + @javax.annotation.Nullable + private String message; + + public static final String JSON_PROPERTY_STATEMENT_HANDLE = "statementHandle"; + @javax.annotation.Nonnull + private UUID statementHandle; + + public static final String JSON_PROPERTY_STATEMENT_STATUS_URL = "statementStatusUrl"; + @javax.annotation.Nullable + private URI statementStatusUrl; + + public CancelStatus() { + } + + public CancelStatus code(@javax.annotation.Nullable String code) { + + this.code = code; + return this; + } + + /** + * Get code + * @return code + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_CODE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getCode() { + return code; + } + + + @JsonProperty(value = JSON_PROPERTY_CODE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setCode(@javax.annotation.Nullable String code) { + this.code = code; + } + + public CancelStatus sqlState(@javax.annotation.Nullable String sqlState) { + + this.sqlState = sqlState; + return this; + } + + /** + * Get sqlState + * @return sqlState + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_SQL_STATE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getSqlState() { + return sqlState; + } + + + @JsonProperty(value = JSON_PROPERTY_SQL_STATE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setSqlState(@javax.annotation.Nullable String sqlState) { + this.sqlState = sqlState; + } + + public CancelStatus message(@javax.annotation.Nullable String message) { + + this.message = message; + return this; + } + + /** + * Get message + * @return message + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_MESSAGE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getMessage() { + return message; + } + + + @JsonProperty(value = JSON_PROPERTY_MESSAGE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setMessage(@javax.annotation.Nullable String message) { + this.message = message; + } + + public CancelStatus statementHandle(@javax.annotation.Nonnull UUID statementHandle) { + + this.statementHandle = statementHandle; + return this; + } + + /** + * Get statementHandle + * @return statementHandle + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_STATEMENT_HANDLE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + + public UUID getStatementHandle() { + return statementHandle; + } + + + @JsonProperty(value = JSON_PROPERTY_STATEMENT_HANDLE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setStatementHandle(@javax.annotation.Nonnull UUID statementHandle) { + this.statementHandle = statementHandle; + } + + public CancelStatus statementStatusUrl(@javax.annotation.Nullable URI statementStatusUrl) { + + this.statementStatusUrl = statementStatusUrl; + return this; + } + + /** + * Get statementStatusUrl + * @return statementStatusUrl + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_STATEMENT_STATUS_URL, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public URI getStatementStatusUrl() { + return statementStatusUrl; + } + + + @JsonProperty(value = JSON_PROPERTY_STATEMENT_STATUS_URL, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setStatementStatusUrl(@javax.annotation.Nullable URI statementStatusUrl) { + this.statementStatusUrl = statementStatusUrl; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + CancelStatus cancelStatus = (CancelStatus) o; + return Objects.equals(this.code, cancelStatus.code) && + Objects.equals(this.sqlState, cancelStatus.sqlState) && + Objects.equals(this.message, cancelStatus.message) && + Objects.equals(this.statementHandle, cancelStatus.statementHandle) && + Objects.equals(this.statementStatusUrl, cancelStatus.statementStatusUrl); + } + + @Override + public int hashCode() { + return Objects.hash(code, sqlState, message, statementHandle, statementStatusUrl); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class CancelStatus {\n"); + sb.append(" code: ").append(toIndentedString(code)).append("\n"); + sb.append(" sqlState: ").append(toIndentedString(sqlState)).append("\n"); + sb.append(" message: ").append(toIndentedString(message)).append("\n"); + sb.append(" statementHandle: ").append(toIndentedString(statementHandle)).append("\n"); + sb.append(" statementStatusUrl: ").append(toIndentedString(statementStatusUrl)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ErrorResponse.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ErrorResponse.java new file mode 100644 index 00000000..731a97a7 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ErrorResponse.java @@ -0,0 +1,202 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Arrays; +import java.util.Locale; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * ErrorResponse + */ +@JsonPropertyOrder({ + ErrorResponse.JSON_PROPERTY_MESSAGE, + ErrorResponse.JSON_PROPERTY_CODE, + ErrorResponse.JSON_PROPERTY_ERROR_CODE, + ErrorResponse.JSON_PROPERTY_REQUEST_ID +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:42:29.597406700+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ErrorResponse { + public static final String JSON_PROPERTY_MESSAGE = "message"; + @javax.annotation.Nullable + private String message; + + public static final String JSON_PROPERTY_CODE = "code"; + @javax.annotation.Nullable + private String code; + + public static final String JSON_PROPERTY_ERROR_CODE = "error_code"; + @javax.annotation.Nullable + private String errorCode; + + public static final String JSON_PROPERTY_REQUEST_ID = "request_id"; + @javax.annotation.Nullable + private String requestId; + + public ErrorResponse() { + } + + public ErrorResponse message(@javax.annotation.Nullable String message) { + + this.message = message; + return this; + } + + /** + * Error message returned by the server + * @return message + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_MESSAGE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getMessage() { + return message; + } + + + @JsonProperty(value = JSON_PROPERTY_MESSAGE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setMessage(@javax.annotation.Nullable String message) { + this.message = message; + } + + public ErrorResponse code(@javax.annotation.Nullable String code) { + + this.code = code; + return this; + } + + /** + * Error code. + * @return code + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_CODE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getCode() { + return code; + } + + + @JsonProperty(value = JSON_PROPERTY_CODE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setCode(@javax.annotation.Nullable String code) { + this.code = code; + } + + public ErrorResponse errorCode(@javax.annotation.Nullable String errorCode) { + + this.errorCode = errorCode; + return this; + } + + /** + * Error code, same as `code` above. This property has been deprecated and will be removed in a future release, but is temporarily supported for for short-term backward compatibility. + * @return errorCode + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_ERROR_CODE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getErrorCode() { + return errorCode; + } + + + @JsonProperty(value = JSON_PROPERTY_ERROR_CODE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setErrorCode(@javax.annotation.Nullable String errorCode) { + this.errorCode = errorCode; + } + + public ErrorResponse requestId(@javax.annotation.Nullable String requestId) { + + this.requestId = requestId; + return this; + } + + /** + * Unique request ID. + * @return requestId + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_REQUEST_ID, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getRequestId() { + return requestId; + } + + + @JsonProperty(value = JSON_PROPERTY_REQUEST_ID, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setRequestId(@javax.annotation.Nullable String requestId) { + this.requestId = requestId; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ErrorResponse errorResponse = (ErrorResponse) o; + return Objects.equals(this.message, errorResponse.message) && + Objects.equals(this.code, errorResponse.code) && + Objects.equals(this.errorCode, errorResponse.errorCode) && + Objects.equals(this.requestId, errorResponse.requestId); + } + + @Override + public int hashCode() { + return Objects.hash(message, code, errorCode, requestId); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ErrorResponse {\n"); + sb.append(" message: ").append(toIndentedString(message)).append("\n"); + sb.append(" code: ").append(toIndentedString(code)).append("\n"); + sb.append(" errorCode: ").append(toIndentedString(errorCode)).append("\n"); + sb.append(" requestId: ").append(toIndentedString(requestId)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/FetchServiceLogs200Response.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/FetchServiceLogs200Response.java new file mode 100644 index 00000000..28ea5919 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/FetchServiceLogs200Response.java @@ -0,0 +1,107 @@ +/* + * Snowflake Services API + * The Snowflake Services API is a REST API that you can use to access, update, and perform certain actions on Services resource in a Snowflake database. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Arrays; +import java.util.Locale; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * FetchServiceLogs200Response + */ +@JsonPropertyOrder({ + FetchServiceLogs200Response.JSON_PROPERTY_SYSTEM$GET_SERVICE_LOGS +}) +@JsonTypeName("fetchServiceLogs_200_response") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:41:25.529847700+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class FetchServiceLogs200Response { + public static final String JSON_PROPERTY_SYSTEM$GET_SERVICE_LOGS = "system$get_service_logs"; + @javax.annotation.Nullable + private String system$getServiceLogs; + + public FetchServiceLogs200Response() { + } + + public FetchServiceLogs200Response system$getServiceLogs(@javax.annotation.Nullable String system$getServiceLogs) { + + this.system$getServiceLogs = system$getServiceLogs; + return this; + } + + /** + * Get system$getServiceLogs + * @return system$getServiceLogs + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_SYSTEM$GET_SERVICE_LOGS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getSystem$getServiceLogs() { + return system$getServiceLogs; + } + + + @JsonProperty(value = JSON_PROPERTY_SYSTEM$GET_SERVICE_LOGS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setSystem$getServiceLogs(@javax.annotation.Nullable String system$getServiceLogs) { + this.system$getServiceLogs = system$getServiceLogs; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + FetchServiceLogs200Response fetchServiceLogs200Response = (FetchServiceLogs200Response) o; + return Objects.equals(this.system$getServiceLogs, fetchServiceLogs200Response.system$getServiceLogs); + } + + @Override + public int hashCode() { + return Objects.hash(system$getServiceLogs); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class FetchServiceLogs200Response {\n"); + sb.append(" system$getServiceLogs: ").append(toIndentedString(system$getServiceLogs)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/FetchServiceStatus200Response.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/FetchServiceStatus200Response.java new file mode 100644 index 00000000..5f20765f --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/FetchServiceStatus200Response.java @@ -0,0 +1,107 @@ +/* + * Snowflake Services API + * The Snowflake Services API is a REST API that you can use to access, update, and perform certain actions on Services resource in a Snowflake database. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Arrays; +import java.util.Locale; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * FetchServiceStatus200Response + */ +@JsonPropertyOrder({ + FetchServiceStatus200Response.JSON_PROPERTY_SYSTEM$GET_SERVICE_STATUS +}) +@JsonTypeName("fetchServiceStatus_200_response") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:41:25.529847700+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class FetchServiceStatus200Response { + public static final String JSON_PROPERTY_SYSTEM$GET_SERVICE_STATUS = "system$get_service_status"; + @javax.annotation.Nullable + private String system$getServiceStatus; + + public FetchServiceStatus200Response() { + } + + public FetchServiceStatus200Response system$getServiceStatus(@javax.annotation.Nullable String system$getServiceStatus) { + + this.system$getServiceStatus = system$getServiceStatus; + return this; + } + + /** + * Get system$getServiceStatus + * @return system$getServiceStatus + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_SYSTEM$GET_SERVICE_STATUS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getSystem$getServiceStatus() { + return system$getServiceStatus; + } + + + @JsonProperty(value = JSON_PROPERTY_SYSTEM$GET_SERVICE_STATUS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setSystem$getServiceStatus(@javax.annotation.Nullable String system$getServiceStatus) { + this.system$getServiceStatus = system$getServiceStatus; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + FetchServiceStatus200Response fetchServiceStatus200Response = (FetchServiceStatus200Response) o; + return Objects.equals(this.system$getServiceStatus, fetchServiceStatus200Response.system$getServiceStatus); + } + + @Override + public int hashCode() { + return Objects.hash(system$getServiceStatus); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class FetchServiceStatus200Response {\n"); + sb.append(" system$getServiceStatus: ").append(toIndentedString(system$getServiceStatus)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/GrantOf.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/GrantOf.java new file mode 100644 index 00000000..bc48034f --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/GrantOf.java @@ -0,0 +1,198 @@ +/* + * Snowflake Services API + * The Snowflake Services API is a REST API that you can use to access, update, and perform certain actions on Services resource in a Snowflake database. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Arrays; +import java.util.Locale; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import java.time.OffsetDateTime; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * GrantOf + */ +@JsonPropertyOrder({ + GrantOf.JSON_PROPERTY_CREATED_ON, + GrantOf.JSON_PROPERTY_ROLE, + GrantOf.JSON_PROPERTY_GRANTED_TO, + GrantOf.JSON_PROPERTY_GRANTEE_NAME, + GrantOf.JSON_PROPERTY_GRANTED_BY +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:41:25.529847700+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class GrantOf { + public static final String JSON_PROPERTY_CREATED_ON = "created_on"; + @javax.annotation.Nullable + private OffsetDateTime createdOn; + + public static final String JSON_PROPERTY_ROLE = "role"; + @javax.annotation.Nullable + private String role; + + public static final String JSON_PROPERTY_GRANTED_TO = "granted_to"; + @javax.annotation.Nullable + private String grantedTo; + + public static final String JSON_PROPERTY_GRANTEE_NAME = "grantee_name"; + @javax.annotation.Nullable + private String granteeName; + + public static final String JSON_PROPERTY_GRANTED_BY = "granted_by"; + @javax.annotation.Nullable + private String grantedBy; + + public GrantOf() { + } + /** + * Constructor with only readonly parameters + */ + @JsonCreator + public GrantOf( + @JsonProperty(JSON_PROPERTY_CREATED_ON) OffsetDateTime createdOn, + @JsonProperty(JSON_PROPERTY_ROLE) String role, + @JsonProperty(JSON_PROPERTY_GRANTED_TO) String grantedTo, + @JsonProperty(JSON_PROPERTY_GRANTEE_NAME) String granteeName, + @JsonProperty(JSON_PROPERTY_GRANTED_BY) String grantedBy + ) { + this(); + this.createdOn = createdOn; + this.role = role; + this.grantedTo = grantedTo; + this.granteeName = granteeName; + this.grantedBy = grantedBy; + } + + /** + * Date and time when the grant was created + * @return createdOn + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_CREATED_ON, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public OffsetDateTime getCreatedOn() { + return createdOn; + } + + + + /** + * The name of the service role + * @return role + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_ROLE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getRole() { + return role; + } + + + + /** + * The type of the grantee, can be USER or ROLE + * @return grantedTo + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_GRANTED_TO, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getGrantedTo() { + return grantedTo; + } + + + + /** + * The name of the grantee + * @return granteeName + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_GRANTEE_NAME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getGranteeName() { + return granteeName; + } + + + + /** + * The name of role that granted the service role to the grantee + * @return grantedBy + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_GRANTED_BY, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getGrantedBy() { + return grantedBy; + } + + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + GrantOf grantOf = (GrantOf) o; + return Objects.equals(this.createdOn, grantOf.createdOn) && + Objects.equals(this.role, grantOf.role) && + Objects.equals(this.grantedTo, grantOf.grantedTo) && + Objects.equals(this.granteeName, grantOf.granteeName) && + Objects.equals(this.grantedBy, grantOf.grantedBy); + } + + @Override + public int hashCode() { + return Objects.hash(createdOn, role, grantedTo, granteeName, grantedBy); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class GrantOf {\n"); + sb.append(" createdOn: ").append(toIndentedString(createdOn)).append("\n"); + sb.append(" role: ").append(toIndentedString(role)).append("\n"); + sb.append(" grantedTo: ").append(toIndentedString(grantedTo)).append("\n"); + sb.append(" granteeName: ").append(toIndentedString(granteeName)).append("\n"); + sb.append(" grantedBy: ").append(toIndentedString(grantedBy)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/JobService.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/JobService.java new file mode 100644 index 00000000..bb48a831 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/JobService.java @@ -0,0 +1,342 @@ +/* + * Snowflake Services API + * The Snowflake Services API is a REST API that you can use to access, update, and perform certain actions on Services resource in a Snowflake database. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Arrays; +import java.util.Locale; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceSpec; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * A Snowflake job service object. + */ +@JsonPropertyOrder({ + JobService.JSON_PROPERTY_NAME, + JobService.JSON_PROPERTY_STATUS, + JobService.JSON_PROPERTY_COMPUTE_POOL, + JobService.JSON_PROPERTY_SPEC, + JobService.JSON_PROPERTY_EXTERNAL_ACCESS_INTEGRATIONS, + JobService.JSON_PROPERTY_QUERY_WAREHOUSE, + JobService.JSON_PROPERTY_COMMENT, + JobService.JSON_PROPERTY_IS_ASYNC_JOB +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:41:25.529847700+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class JobService { + public static final String JSON_PROPERTY_NAME = "name"; + @javax.annotation.Nonnull + private String name; + + public static final String JSON_PROPERTY_STATUS = "status"; + @javax.annotation.Nullable + private String status; + + public static final String JSON_PROPERTY_COMPUTE_POOL = "compute_pool"; + @javax.annotation.Nonnull + private String computePool; + + public static final String JSON_PROPERTY_SPEC = "spec"; + @javax.annotation.Nonnull + private ServiceSpec spec; + + public static final String JSON_PROPERTY_EXTERNAL_ACCESS_INTEGRATIONS = "external_access_integrations"; + @javax.annotation.Nullable + private List externalAccessIntegrations = new ArrayList<>(); + + public static final String JSON_PROPERTY_QUERY_WAREHOUSE = "query_warehouse"; + @javax.annotation.Nullable + private String queryWarehouse; + + public static final String JSON_PROPERTY_COMMENT = "comment"; + @javax.annotation.Nullable + private String comment; + + public static final String JSON_PROPERTY_IS_ASYNC_JOB = "is_async_job"; + @javax.annotation.Nullable + private Boolean isAsyncJob; + + public JobService() { + } + + public JobService name(@javax.annotation.Nonnull String name) { + + this.name = name; + return this; + } + + /** + * A Snowflake object identifier. If the identifier contains spaces or special characters, the entire string must be enclosed in double quotes. Identifiers enclosed in double quotes are also case-sensitive. + * @return name + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_NAME, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + + public String getName() { + return name; + } + + + @JsonProperty(value = JSON_PROPERTY_NAME, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setName(@javax.annotation.Nonnull String name) { + this.name = name; + } + + public JobService status(@javax.annotation.Nullable String status) { + + this.status = status; + return this; + } + + /** + * The current status of the service. + * @return status + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_STATUS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getStatus() { + return status; + } + + + @JsonProperty(value = JSON_PROPERTY_STATUS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setStatus(@javax.annotation.Nullable String status) { + this.status = status; + } + + public JobService computePool(@javax.annotation.Nonnull String computePool) { + + this.computePool = computePool; + return this; + } + + /** + * Specifies the name of the compute pool in your account on which to run the service. + * @return computePool + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_COMPUTE_POOL, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + + public String getComputePool() { + return computePool; + } + + + @JsonProperty(value = JSON_PROPERTY_COMPUTE_POOL, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setComputePool(@javax.annotation.Nonnull String computePool) { + this.computePool = computePool; + } + + public JobService spec(@javax.annotation.Nonnull ServiceSpec spec) { + + this.spec = spec; + return this; + } + + /** + * Get spec + * @return spec + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_SPEC, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + + public ServiceSpec getSpec() { + return spec; + } + + + @JsonProperty(value = JSON_PROPERTY_SPEC, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setSpec(@javax.annotation.Nonnull ServiceSpec spec) { + this.spec = spec; + } + + public JobService externalAccessIntegrations(@javax.annotation.Nullable List externalAccessIntegrations) { + + this.externalAccessIntegrations = externalAccessIntegrations; + return this; + } + + public JobService addExternalAccessIntegrationsItem(String externalAccessIntegrationsItem) { + if (this.externalAccessIntegrations == null) { + this.externalAccessIntegrations = new ArrayList<>(); + } + this.externalAccessIntegrations.add(externalAccessIntegrationsItem); + return this; + } + + /** + * Specifies the names of the external access integrations that allow your service to access external sites. + * @return externalAccessIntegrations + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_EXTERNAL_ACCESS_INTEGRATIONS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public List getExternalAccessIntegrations() { + return externalAccessIntegrations; + } + + + @JsonProperty(value = JSON_PROPERTY_EXTERNAL_ACCESS_INTEGRATIONS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setExternalAccessIntegrations(@javax.annotation.Nullable List externalAccessIntegrations) { + this.externalAccessIntegrations = externalAccessIntegrations; + } + + public JobService queryWarehouse(@javax.annotation.Nullable String queryWarehouse) { + + this.queryWarehouse = queryWarehouse; + return this; + } + + /** + * A Snowflake object identifier. If the identifier contains spaces or special characters, the entire string must be enclosed in double quotes. Identifiers enclosed in double quotes are also case-sensitive. + * @return queryWarehouse + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_QUERY_WAREHOUSE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getQueryWarehouse() { + return queryWarehouse; + } + + + @JsonProperty(value = JSON_PROPERTY_QUERY_WAREHOUSE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setQueryWarehouse(@javax.annotation.Nullable String queryWarehouse) { + this.queryWarehouse = queryWarehouse; + } + + public JobService comment(@javax.annotation.Nullable String comment) { + + this.comment = comment; + return this; + } + + /** + * Specifies a comment for the service. + * @return comment + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_COMMENT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getComment() { + return comment; + } + + + @JsonProperty(value = JSON_PROPERTY_COMMENT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setComment(@javax.annotation.Nullable String comment) { + this.comment = comment; + } + + public JobService isAsyncJob(@javax.annotation.Nullable Boolean isAsyncJob) { + + this.isAsyncJob = isAsyncJob; + return this; + } + + /** + * True if the service is an async job service; false otherwise. + * @return isAsyncJob + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_IS_ASYNC_JOB, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Boolean getIsAsyncJob() { + return isAsyncJob; + } + + + @JsonProperty(value = JSON_PROPERTY_IS_ASYNC_JOB, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setIsAsyncJob(@javax.annotation.Nullable Boolean isAsyncJob) { + this.isAsyncJob = isAsyncJob; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + JobService jobService = (JobService) o; + return Objects.equals(this.name, jobService.name) && + Objects.equals(this.status, jobService.status) && + Objects.equals(this.computePool, jobService.computePool) && + Objects.equals(this.spec, jobService.spec) && + Objects.equals(this.externalAccessIntegrations, jobService.externalAccessIntegrations) && + Objects.equals(this.queryWarehouse, jobService.queryWarehouse) && + Objects.equals(this.comment, jobService.comment) && + Objects.equals(this.isAsyncJob, jobService.isAsyncJob); + } + + @Override + public int hashCode() { + return Objects.hash(name, status, computePool, spec, externalAccessIntegrations, queryWarehouse, comment, isAsyncJob); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class JobService {\n"); + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append(" status: ").append(toIndentedString(status)).append("\n"); + sb.append(" computePool: ").append(toIndentedString(computePool)).append("\n"); + sb.append(" spec: ").append(toIndentedString(spec)).append("\n"); + sb.append(" externalAccessIntegrations: ").append(toIndentedString(externalAccessIntegrations)).append("\n"); + sb.append(" queryWarehouse: ").append(toIndentedString(queryWarehouse)).append("\n"); + sb.append(" comment: ").append(toIndentedString(comment)).append("\n"); + sb.append(" isAsyncJob: ").append(toIndentedString(isAsyncJob)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/QueryFailureStatus.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/QueryFailureStatus.java new file mode 100644 index 00000000..90bec8fc --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/QueryFailureStatus.java @@ -0,0 +1,268 @@ +/* + * Snowflake SQL API + * The Snowflake SQL API is a REST API that you can use to access and update data in a Snowflake database. + * + * The version of the OpenAPI document: 2.0.0 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Arrays; +import java.util.Locale; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import java.net.URI; +import java.util.UUID; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * QueryFailureStatus + */ +@JsonPropertyOrder({ + QueryFailureStatus.JSON_PROPERTY_CODE, + QueryFailureStatus.JSON_PROPERTY_SQL_STATE, + QueryFailureStatus.JSON_PROPERTY_MESSAGE, + QueryFailureStatus.JSON_PROPERTY_STATEMENT_HANDLE, + QueryFailureStatus.JSON_PROPERTY_CREATED_ON, + QueryFailureStatus.JSON_PROPERTY_STATEMENT_STATUS_URL +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:41:35.116838100+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class QueryFailureStatus { + public static final String JSON_PROPERTY_CODE = "code"; + @javax.annotation.Nullable + private String code; + + public static final String JSON_PROPERTY_SQL_STATE = "sqlState"; + @javax.annotation.Nullable + private String sqlState; + + public static final String JSON_PROPERTY_MESSAGE = "message"; + @javax.annotation.Nonnull + private String message; + + public static final String JSON_PROPERTY_STATEMENT_HANDLE = "statementHandle"; + @javax.annotation.Nonnull + private UUID statementHandle; + + public static final String JSON_PROPERTY_CREATED_ON = "createdOn"; + @javax.annotation.Nullable + private Long createdOn; + + public static final String JSON_PROPERTY_STATEMENT_STATUS_URL = "statementStatusUrl"; + @javax.annotation.Nullable + private URI statementStatusUrl; + + public QueryFailureStatus() { + } + + public QueryFailureStatus code(@javax.annotation.Nullable String code) { + + this.code = code; + return this; + } + + /** + * Get code + * @return code + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_CODE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getCode() { + return code; + } + + + @JsonProperty(value = JSON_PROPERTY_CODE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setCode(@javax.annotation.Nullable String code) { + this.code = code; + } + + public QueryFailureStatus sqlState(@javax.annotation.Nullable String sqlState) { + + this.sqlState = sqlState; + return this; + } + + /** + * Get sqlState + * @return sqlState + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_SQL_STATE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getSqlState() { + return sqlState; + } + + + @JsonProperty(value = JSON_PROPERTY_SQL_STATE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setSqlState(@javax.annotation.Nullable String sqlState) { + this.sqlState = sqlState; + } + + public QueryFailureStatus message(@javax.annotation.Nonnull String message) { + + this.message = message; + return this; + } + + /** + * Get message + * @return message + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_MESSAGE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + + public String getMessage() { + return message; + } + + + @JsonProperty(value = JSON_PROPERTY_MESSAGE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setMessage(@javax.annotation.Nonnull String message) { + this.message = message; + } + + public QueryFailureStatus statementHandle(@javax.annotation.Nonnull UUID statementHandle) { + + this.statementHandle = statementHandle; + return this; + } + + /** + * Get statementHandle + * @return statementHandle + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_STATEMENT_HANDLE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + + public UUID getStatementHandle() { + return statementHandle; + } + + + @JsonProperty(value = JSON_PROPERTY_STATEMENT_HANDLE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setStatementHandle(@javax.annotation.Nonnull UUID statementHandle) { + this.statementHandle = statementHandle; + } + + public QueryFailureStatus createdOn(@javax.annotation.Nullable Long createdOn) { + + this.createdOn = createdOn; + return this; + } + + /** + * Timestamp that specifies when the statement execution started.‌ The timestamp is expressed in milliseconds since the epoch. + * @return createdOn + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_CREATED_ON, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Long getCreatedOn() { + return createdOn; + } + + + @JsonProperty(value = JSON_PROPERTY_CREATED_ON, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setCreatedOn(@javax.annotation.Nullable Long createdOn) { + this.createdOn = createdOn; + } + + public QueryFailureStatus statementStatusUrl(@javax.annotation.Nullable URI statementStatusUrl) { + + this.statementStatusUrl = statementStatusUrl; + return this; + } + + /** + * Get statementStatusUrl + * @return statementStatusUrl + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_STATEMENT_STATUS_URL, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public URI getStatementStatusUrl() { + return statementStatusUrl; + } + + + @JsonProperty(value = JSON_PROPERTY_STATEMENT_STATUS_URL, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setStatementStatusUrl(@javax.annotation.Nullable URI statementStatusUrl) { + this.statementStatusUrl = statementStatusUrl; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + QueryFailureStatus queryFailureStatus = (QueryFailureStatus) o; + return Objects.equals(this.code, queryFailureStatus.code) && + Objects.equals(this.sqlState, queryFailureStatus.sqlState) && + Objects.equals(this.message, queryFailureStatus.message) && + Objects.equals(this.statementHandle, queryFailureStatus.statementHandle) && + Objects.equals(this.createdOn, queryFailureStatus.createdOn) && + Objects.equals(this.statementStatusUrl, queryFailureStatus.statementStatusUrl); + } + + @Override + public int hashCode() { + return Objects.hash(code, sqlState, message, statementHandle, createdOn, statementStatusUrl); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class QueryFailureStatus {\n"); + sb.append(" code: ").append(toIndentedString(code)).append("\n"); + sb.append(" sqlState: ").append(toIndentedString(sqlState)).append("\n"); + sb.append(" message: ").append(toIndentedString(message)).append("\n"); + sb.append(" statementHandle: ").append(toIndentedString(statementHandle)).append("\n"); + sb.append(" createdOn: ").append(toIndentedString(createdOn)).append("\n"); + sb.append(" statementStatusUrl: ").append(toIndentedString(statementStatusUrl)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/QueryStatus.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/QueryStatus.java new file mode 100644 index 00000000..a4266d0d --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/QueryStatus.java @@ -0,0 +1,268 @@ +/* + * Snowflake SQL API + * The Snowflake SQL API is a REST API that you can use to access and update data in a Snowflake database. + * + * The version of the OpenAPI document: 2.0.0 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Arrays; +import java.util.Locale; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import java.net.URI; +import java.util.UUID; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * QueryStatus + */ +@JsonPropertyOrder({ + QueryStatus.JSON_PROPERTY_CODE, + QueryStatus.JSON_PROPERTY_SQL_STATE, + QueryStatus.JSON_PROPERTY_MESSAGE, + QueryStatus.JSON_PROPERTY_STATEMENT_HANDLE, + QueryStatus.JSON_PROPERTY_CREATED_ON, + QueryStatus.JSON_PROPERTY_STATEMENT_STATUS_URL +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:41:35.116838100+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class QueryStatus { + public static final String JSON_PROPERTY_CODE = "code"; + @javax.annotation.Nullable + private String code; + + public static final String JSON_PROPERTY_SQL_STATE = "sqlState"; + @javax.annotation.Nullable + private String sqlState; + + public static final String JSON_PROPERTY_MESSAGE = "message"; + @javax.annotation.Nullable + private String message; + + public static final String JSON_PROPERTY_STATEMENT_HANDLE = "statementHandle"; + @javax.annotation.Nonnull + private UUID statementHandle; + + public static final String JSON_PROPERTY_CREATED_ON = "createdOn"; + @javax.annotation.Nullable + private Long createdOn; + + public static final String JSON_PROPERTY_STATEMENT_STATUS_URL = "statementStatusUrl"; + @javax.annotation.Nullable + private URI statementStatusUrl; + + public QueryStatus() { + } + + public QueryStatus code(@javax.annotation.Nullable String code) { + + this.code = code; + return this; + } + + /** + * Get code + * @return code + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_CODE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getCode() { + return code; + } + + + @JsonProperty(value = JSON_PROPERTY_CODE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setCode(@javax.annotation.Nullable String code) { + this.code = code; + } + + public QueryStatus sqlState(@javax.annotation.Nullable String sqlState) { + + this.sqlState = sqlState; + return this; + } + + /** + * Get sqlState + * @return sqlState + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_SQL_STATE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getSqlState() { + return sqlState; + } + + + @JsonProperty(value = JSON_PROPERTY_SQL_STATE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setSqlState(@javax.annotation.Nullable String sqlState) { + this.sqlState = sqlState; + } + + public QueryStatus message(@javax.annotation.Nullable String message) { + + this.message = message; + return this; + } + + /** + * Get message + * @return message + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_MESSAGE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getMessage() { + return message; + } + + + @JsonProperty(value = JSON_PROPERTY_MESSAGE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setMessage(@javax.annotation.Nullable String message) { + this.message = message; + } + + public QueryStatus statementHandle(@javax.annotation.Nonnull UUID statementHandle) { + + this.statementHandle = statementHandle; + return this; + } + + /** + * Get statementHandle + * @return statementHandle + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_STATEMENT_HANDLE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + + public UUID getStatementHandle() { + return statementHandle; + } + + + @JsonProperty(value = JSON_PROPERTY_STATEMENT_HANDLE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setStatementHandle(@javax.annotation.Nonnull UUID statementHandle) { + this.statementHandle = statementHandle; + } + + public QueryStatus createdOn(@javax.annotation.Nullable Long createdOn) { + + this.createdOn = createdOn; + return this; + } + + /** + * Timestamp that specifies when the statement execution started. The timestamp is expressed in milliseconds since the epoch. + * @return createdOn + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_CREATED_ON, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Long getCreatedOn() { + return createdOn; + } + + + @JsonProperty(value = JSON_PROPERTY_CREATED_ON, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setCreatedOn(@javax.annotation.Nullable Long createdOn) { + this.createdOn = createdOn; + } + + public QueryStatus statementStatusUrl(@javax.annotation.Nullable URI statementStatusUrl) { + + this.statementStatusUrl = statementStatusUrl; + return this; + } + + /** + * URL that you can use to check the status of the execution of the statement and the result set. + * @return statementStatusUrl + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_STATEMENT_STATUS_URL, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public URI getStatementStatusUrl() { + return statementStatusUrl; + } + + + @JsonProperty(value = JSON_PROPERTY_STATEMENT_STATUS_URL, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setStatementStatusUrl(@javax.annotation.Nullable URI statementStatusUrl) { + this.statementStatusUrl = statementStatusUrl; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + QueryStatus queryStatus = (QueryStatus) o; + return Objects.equals(this.code, queryStatus.code) && + Objects.equals(this.sqlState, queryStatus.sqlState) && + Objects.equals(this.message, queryStatus.message) && + Objects.equals(this.statementHandle, queryStatus.statementHandle) && + Objects.equals(this.createdOn, queryStatus.createdOn) && + Objects.equals(this.statementStatusUrl, queryStatus.statementStatusUrl); + } + + @Override + public int hashCode() { + return Objects.hash(code, sqlState, message, statementHandle, createdOn, statementStatusUrl); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class QueryStatus {\n"); + sb.append(" code: ").append(toIndentedString(code)).append("\n"); + sb.append(" sqlState: ").append(toIndentedString(sqlState)).append("\n"); + sb.append(" message: ").append(toIndentedString(message)).append("\n"); + sb.append(" statementHandle: ").append(toIndentedString(statementHandle)).append("\n"); + sb.append(" createdOn: ").append(toIndentedString(createdOn)).append("\n"); + sb.append(" statementStatusUrl: ").append(toIndentedString(statementStatusUrl)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSet.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSet.java new file mode 100644 index 00000000..3bd6fd8e --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSet.java @@ -0,0 +1,377 @@ +/* + * Snowflake SQL API + * The Snowflake SQL API is a REST API that you can use to access and update data in a Snowflake database. + * + * The version of the OpenAPI document: 2.0.0 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Arrays; +import java.util.Locale; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ResultSetResultSetMetaData; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ResultSetStats; +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * ResultSet + */ +@JsonPropertyOrder({ + ResultSet.JSON_PROPERTY_CODE, + ResultSet.JSON_PROPERTY_SQL_STATE, + ResultSet.JSON_PROPERTY_MESSAGE, + ResultSet.JSON_PROPERTY_STATEMENT_HANDLE, + ResultSet.JSON_PROPERTY_CREATED_ON, + ResultSet.JSON_PROPERTY_STATEMENT_STATUS_URL, + ResultSet.JSON_PROPERTY_RESULT_SET_META_DATA, + ResultSet.JSON_PROPERTY_DATA, + ResultSet.JSON_PROPERTY_STATS +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:41:35.116838100+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ResultSet { + public static final String JSON_PROPERTY_CODE = "code"; + @javax.annotation.Nullable + private String code; + + public static final String JSON_PROPERTY_SQL_STATE = "sqlState"; + @javax.annotation.Nullable + private String sqlState; + + public static final String JSON_PROPERTY_MESSAGE = "message"; + @javax.annotation.Nullable + private String message; + + public static final String JSON_PROPERTY_STATEMENT_HANDLE = "statementHandle"; + @javax.annotation.Nullable + private UUID statementHandle; + + public static final String JSON_PROPERTY_CREATED_ON = "createdOn"; + @javax.annotation.Nullable + private Long createdOn; + + public static final String JSON_PROPERTY_STATEMENT_STATUS_URL = "statementStatusUrl"; + @javax.annotation.Nullable + private URI statementStatusUrl; + + public static final String JSON_PROPERTY_RESULT_SET_META_DATA = "resultSetMetaData"; + @javax.annotation.Nullable + private ResultSetResultSetMetaData resultSetMetaData; + + public static final String JSON_PROPERTY_DATA = "data"; + @javax.annotation.Nullable + private List> data = new ArrayList<>(); + + public static final String JSON_PROPERTY_STATS = "stats"; + @javax.annotation.Nullable + private ResultSetStats stats; + + public ResultSet() { + } + + public ResultSet code(@javax.annotation.Nullable String code) { + + this.code = code; + return this; + } + + /** + * Get code + * @return code + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_CODE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getCode() { + return code; + } + + + @JsonProperty(value = JSON_PROPERTY_CODE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setCode(@javax.annotation.Nullable String code) { + this.code = code; + } + + public ResultSet sqlState(@javax.annotation.Nullable String sqlState) { + + this.sqlState = sqlState; + return this; + } + + /** + * Get sqlState + * @return sqlState + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_SQL_STATE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getSqlState() { + return sqlState; + } + + + @JsonProperty(value = JSON_PROPERTY_SQL_STATE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setSqlState(@javax.annotation.Nullable String sqlState) { + this.sqlState = sqlState; + } + + public ResultSet message(@javax.annotation.Nullable String message) { + + this.message = message; + return this; + } + + /** + * Get message + * @return message + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_MESSAGE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getMessage() { + return message; + } + + + @JsonProperty(value = JSON_PROPERTY_MESSAGE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setMessage(@javax.annotation.Nullable String message) { + this.message = message; + } + + public ResultSet statementHandle(@javax.annotation.Nullable UUID statementHandle) { + + this.statementHandle = statementHandle; + return this; + } + + /** + * Get statementHandle + * @return statementHandle + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_STATEMENT_HANDLE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public UUID getStatementHandle() { + return statementHandle; + } + + + @JsonProperty(value = JSON_PROPERTY_STATEMENT_HANDLE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setStatementHandle(@javax.annotation.Nullable UUID statementHandle) { + this.statementHandle = statementHandle; + } + + public ResultSet createdOn(@javax.annotation.Nullable Long createdOn) { + + this.createdOn = createdOn; + return this; + } + + /** + * Timestamp that specifies when the statement execution started.‌ The timestamp is expressed in milliseconds since the epoch.‌ + * @return createdOn + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_CREATED_ON, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Long getCreatedOn() { + return createdOn; + } + + + @JsonProperty(value = JSON_PROPERTY_CREATED_ON, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setCreatedOn(@javax.annotation.Nullable Long createdOn) { + this.createdOn = createdOn; + } + + public ResultSet statementStatusUrl(@javax.annotation.Nullable URI statementStatusUrl) { + + this.statementStatusUrl = statementStatusUrl; + return this; + } + + /** + * Get statementStatusUrl + * @return statementStatusUrl + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_STATEMENT_STATUS_URL, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public URI getStatementStatusUrl() { + return statementStatusUrl; + } + + + @JsonProperty(value = JSON_PROPERTY_STATEMENT_STATUS_URL, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setStatementStatusUrl(@javax.annotation.Nullable URI statementStatusUrl) { + this.statementStatusUrl = statementStatusUrl; + } + + public ResultSet resultSetMetaData(@javax.annotation.Nullable ResultSetResultSetMetaData resultSetMetaData) { + + this.resultSetMetaData = resultSetMetaData; + return this; + } + + /** + * Get resultSetMetaData + * @return resultSetMetaData + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_RESULT_SET_META_DATA, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public ResultSetResultSetMetaData getResultSetMetaData() { + return resultSetMetaData; + } + + + @JsonProperty(value = JSON_PROPERTY_RESULT_SET_META_DATA, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setResultSetMetaData(@javax.annotation.Nullable ResultSetResultSetMetaData resultSetMetaData) { + this.resultSetMetaData = resultSetMetaData; + } + + public ResultSet data(@javax.annotation.Nullable List> data) { + + this.data = data; + return this; + } + + public ResultSet addDataItem(List dataItem) { + if (this.data == null) { + this.data = new ArrayList<>(); + } + this.data.add(dataItem); + return this; + } + + /** + * Result set data. + * @return data + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_DATA, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public List> getData() { + return data; + } + + + @JsonProperty(value = JSON_PROPERTY_DATA, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setData(@javax.annotation.Nullable List> data) { + this.data = data; + } + + public ResultSet stats(@javax.annotation.Nullable ResultSetStats stats) { + + this.stats = stats; + return this; + } + + /** + * Get stats + * @return stats + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_STATS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public ResultSetStats getStats() { + return stats; + } + + + @JsonProperty(value = JSON_PROPERTY_STATS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setStats(@javax.annotation.Nullable ResultSetStats stats) { + this.stats = stats; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResultSet resultSet = (ResultSet) o; + return Objects.equals(this.code, resultSet.code) && + Objects.equals(this.sqlState, resultSet.sqlState) && + Objects.equals(this.message, resultSet.message) && + Objects.equals(this.statementHandle, resultSet.statementHandle) && + Objects.equals(this.createdOn, resultSet.createdOn) && + Objects.equals(this.statementStatusUrl, resultSet.statementStatusUrl) && + Objects.equals(this.resultSetMetaData, resultSet.resultSetMetaData) && + Objects.equals(this.data, resultSet.data) && + Objects.equals(this.stats, resultSet.stats); + } + + @Override + public int hashCode() { + return Objects.hash(code, sqlState, message, statementHandle, createdOn, statementStatusUrl, resultSetMetaData, data, stats); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResultSet {\n"); + sb.append(" code: ").append(toIndentedString(code)).append("\n"); + sb.append(" sqlState: ").append(toIndentedString(sqlState)).append("\n"); + sb.append(" message: ").append(toIndentedString(message)).append("\n"); + sb.append(" statementHandle: ").append(toIndentedString(statementHandle)).append("\n"); + sb.append(" createdOn: ").append(toIndentedString(createdOn)).append("\n"); + sb.append(" statementStatusUrl: ").append(toIndentedString(statementStatusUrl)).append("\n"); + sb.append(" resultSetMetaData: ").append(toIndentedString(resultSetMetaData)).append("\n"); + sb.append(" data: ").append(toIndentedString(data)).append("\n"); + sb.append(" stats: ").append(toIndentedString(stats)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSetResultSetMetaData.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSetResultSetMetaData.java new file mode 100644 index 00000000..34289894 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSetResultSetMetaData.java @@ -0,0 +1,322 @@ +/* + * Snowflake SQL API + * The Snowflake SQL API is a REST API that you can use to access and update data in a Snowflake database. + * + * The version of the OpenAPI document: 2.0.0 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Arrays; +import java.util.Locale; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ResultSetResultSetMetaDataParameters; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ResultSetResultSetMetaDataPartitionInfoInner; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ResultSetResultSetMetaDataRowTypeInner; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * ResultSetResultSetMetaData + */ +@JsonPropertyOrder({ + ResultSetResultSetMetaData.JSON_PROPERTY_FORMAT, + ResultSetResultSetMetaData.JSON_PROPERTY_NUM_ROWS, + ResultSetResultSetMetaData.JSON_PROPERTY_ROW_TYPE, + ResultSetResultSetMetaData.JSON_PROPERTY_PARTITION_INFO, + ResultSetResultSetMetaData.JSON_PROPERTY_NULLABLE, + ResultSetResultSetMetaData.JSON_PROPERTY_PARAMETERS +}) +@JsonTypeName("ResultSet_resultSetMetaData") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:41:35.116838100+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ResultSetResultSetMetaData { + /** + * For v2 endpoints the only possible value for this field is jsonv2. + */ + public enum FormatEnum { + JSONV2(String.valueOf("jsonv2")); + + private String value; + + FormatEnum(String value) { + this.value = value; + } + + @JsonValue + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static FormatEnum fromValue(String value) { + for (FormatEnum b : FormatEnum.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } + } + + public static final String JSON_PROPERTY_FORMAT = "format"; + @javax.annotation.Nullable + private FormatEnum format; + + public static final String JSON_PROPERTY_NUM_ROWS = "numRows"; + @javax.annotation.Nullable + private Long numRows; + + public static final String JSON_PROPERTY_ROW_TYPE = "rowType"; + @javax.annotation.Nullable + private List rowType = new ArrayList<>(); + + public static final String JSON_PROPERTY_PARTITION_INFO = "partitionInfo"; + @javax.annotation.Nullable + private List partitionInfo = new ArrayList<>(); + + public static final String JSON_PROPERTY_NULLABLE = "nullable"; + @javax.annotation.Nullable + private Boolean nullable; + + public static final String JSON_PROPERTY_PARAMETERS = "parameters"; + @javax.annotation.Nullable + private ResultSetResultSetMetaDataParameters parameters; + + public ResultSetResultSetMetaData() { + } + + public ResultSetResultSetMetaData format(@javax.annotation.Nullable FormatEnum format) { + + this.format = format; + return this; + } + + /** + * For v2 endpoints the only possible value for this field is jsonv2. + * @return format + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_FORMAT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public FormatEnum getFormat() { + return format; + } + + + @JsonProperty(value = JSON_PROPERTY_FORMAT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setFormat(@javax.annotation.Nullable FormatEnum format) { + this.format = format; + } + + public ResultSetResultSetMetaData numRows(@javax.annotation.Nullable Long numRows) { + + this.numRows = numRows; + return this; + } + + /** + * The total number of rows of results. + * @return numRows + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_NUM_ROWS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Long getNumRows() { + return numRows; + } + + + @JsonProperty(value = JSON_PROPERTY_NUM_ROWS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setNumRows(@javax.annotation.Nullable Long numRows) { + this.numRows = numRows; + } + + public ResultSetResultSetMetaData rowType(@javax.annotation.Nullable List rowType) { + + this.rowType = rowType; + return this; + } + + public ResultSetResultSetMetaData addRowTypeItem(ResultSetResultSetMetaDataRowTypeInner rowTypeItem) { + if (this.rowType == null) { + this.rowType = new ArrayList<>(); + } + this.rowType.add(rowTypeItem); + return this; + } + + /** + * Get rowType + * @return rowType + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_ROW_TYPE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public List getRowType() { + return rowType; + } + + + @JsonProperty(value = JSON_PROPERTY_ROW_TYPE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setRowType(@javax.annotation.Nullable List rowType) { + this.rowType = rowType; + } + + public ResultSetResultSetMetaData partitionInfo(@javax.annotation.Nullable List partitionInfo) { + + this.partitionInfo = partitionInfo; + return this; + } + + public ResultSetResultSetMetaData addPartitionInfoItem(ResultSetResultSetMetaDataPartitionInfoInner partitionInfoItem) { + if (this.partitionInfo == null) { + this.partitionInfo = new ArrayList<>(); + } + this.partitionInfo.add(partitionInfoItem); + return this; + } + + /** + * Partition information + * @return partitionInfo + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_PARTITION_INFO, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public List getPartitionInfo() { + return partitionInfo; + } + + + @JsonProperty(value = JSON_PROPERTY_PARTITION_INFO, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setPartitionInfo(@javax.annotation.Nullable List partitionInfo) { + this.partitionInfo = partitionInfo; + } + + public ResultSetResultSetMetaData nullable(@javax.annotation.Nullable Boolean nullable) { + + this.nullable = nullable; + return this; + } + + /** + * false if null is replaced with a string 'null' otherwise false + * @return nullable + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_NULLABLE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Boolean getNullable() { + return nullable; + } + + + @JsonProperty(value = JSON_PROPERTY_NULLABLE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setNullable(@javax.annotation.Nullable Boolean nullable) { + this.nullable = nullable; + } + + public ResultSetResultSetMetaData parameters(@javax.annotation.Nullable ResultSetResultSetMetaDataParameters parameters) { + + this.parameters = parameters; + return this; + } + + /** + * Get parameters + * @return parameters + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_PARAMETERS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public ResultSetResultSetMetaDataParameters getParameters() { + return parameters; + } + + + @JsonProperty(value = JSON_PROPERTY_PARAMETERS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setParameters(@javax.annotation.Nullable ResultSetResultSetMetaDataParameters parameters) { + this.parameters = parameters; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResultSetResultSetMetaData resultSetResultSetMetaData = (ResultSetResultSetMetaData) o; + return Objects.equals(this.format, resultSetResultSetMetaData.format) && + Objects.equals(this.numRows, resultSetResultSetMetaData.numRows) && + Objects.equals(this.rowType, resultSetResultSetMetaData.rowType) && + Objects.equals(this.partitionInfo, resultSetResultSetMetaData.partitionInfo) && + Objects.equals(this.nullable, resultSetResultSetMetaData.nullable) && + Objects.equals(this.parameters, resultSetResultSetMetaData.parameters); + } + + @Override + public int hashCode() { + return Objects.hash(format, numRows, rowType, partitionInfo, nullable, parameters); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResultSetResultSetMetaData {\n"); + sb.append(" format: ").append(toIndentedString(format)).append("\n"); + sb.append(" numRows: ").append(toIndentedString(numRows)).append("\n"); + sb.append(" rowType: ").append(toIndentedString(rowType)).append("\n"); + sb.append(" partitionInfo: ").append(toIndentedString(partitionInfo)).append("\n"); + sb.append(" nullable: ").append(toIndentedString(nullable)).append("\n"); + sb.append(" parameters: ").append(toIndentedString(parameters)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSetResultSetMetaDataParameters.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSetResultSetMetaDataParameters.java new file mode 100644 index 00000000..7178cdc7 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSetResultSetMetaDataParameters.java @@ -0,0 +1,331 @@ +/* + * Snowflake SQL API + * The Snowflake SQL API is a REST API that you can use to access and update data in a Snowflake database. + * + * The version of the OpenAPI document: 2.0.0 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Arrays; +import java.util.Locale; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * ResultSetResultSetMetaDataParameters + */ +@JsonPropertyOrder({ + ResultSetResultSetMetaDataParameters.JSON_PROPERTY_BINARY_OUTPUT_FORMAT, + ResultSetResultSetMetaDataParameters.JSON_PROPERTY_DATE_OUTPUT_FORMAT, + ResultSetResultSetMetaDataParameters.JSON_PROPERTY_TIME_OUTPUT_FORMAT, + ResultSetResultSetMetaDataParameters.JSON_PROPERTY_TIMESTAMP_OUTPUT_FORMAT, + ResultSetResultSetMetaDataParameters.JSON_PROPERTY_TIMESTAMP_LTZ_OUTPUT_FORMAT, + ResultSetResultSetMetaDataParameters.JSON_PROPERTY_TIMESTAMP_NTZ_OUTPUT_FORMAT, + ResultSetResultSetMetaDataParameters.JSON_PROPERTY_TIMESTAMP_TZ_OUTPUT_FORMAT, + ResultSetResultSetMetaDataParameters.JSON_PROPERTY_MULTI_STATEMENT_COUNT +}) +@JsonTypeName("ResultSet_resultSetMetaData_parameters") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:41:35.116838100+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ResultSetResultSetMetaDataParameters { + public static final String JSON_PROPERTY_BINARY_OUTPUT_FORMAT = "binary_output_format"; + @javax.annotation.Nullable + private String binaryOutputFormat; + + public static final String JSON_PROPERTY_DATE_OUTPUT_FORMAT = "date_output_format"; + @javax.annotation.Nullable + private String dateOutputFormat; + + public static final String JSON_PROPERTY_TIME_OUTPUT_FORMAT = "time_output_format"; + @javax.annotation.Nullable + private String timeOutputFormat; + + public static final String JSON_PROPERTY_TIMESTAMP_OUTPUT_FORMAT = "timestamp_output_format"; + @javax.annotation.Nullable + private String timestampOutputFormat; + + public static final String JSON_PROPERTY_TIMESTAMP_LTZ_OUTPUT_FORMAT = "timestamp_ltz_output_format"; + @javax.annotation.Nullable + private String timestampLtzOutputFormat; + + public static final String JSON_PROPERTY_TIMESTAMP_NTZ_OUTPUT_FORMAT = "timestamp_ntz_output_format"; + @javax.annotation.Nullable + private String timestampNtzOutputFormat; + + public static final String JSON_PROPERTY_TIMESTAMP_TZ_OUTPUT_FORMAT = "timestamp_tz_output_format"; + @javax.annotation.Nullable + private String timestampTzOutputFormat; + + public static final String JSON_PROPERTY_MULTI_STATEMENT_COUNT = "multi_statement_count"; + @javax.annotation.Nullable + private Integer multiStatementCount; + + public ResultSetResultSetMetaDataParameters() { + } + + public ResultSetResultSetMetaDataParameters binaryOutputFormat(@javax.annotation.Nullable String binaryOutputFormat) { + + this.binaryOutputFormat = binaryOutputFormat; + return this; + } + + /** + * Get binaryOutputFormat + * @return binaryOutputFormat + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_BINARY_OUTPUT_FORMAT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getBinaryOutputFormat() { + return binaryOutputFormat; + } + + + @JsonProperty(value = JSON_PROPERTY_BINARY_OUTPUT_FORMAT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setBinaryOutputFormat(@javax.annotation.Nullable String binaryOutputFormat) { + this.binaryOutputFormat = binaryOutputFormat; + } + + public ResultSetResultSetMetaDataParameters dateOutputFormat(@javax.annotation.Nullable String dateOutputFormat) { + + this.dateOutputFormat = dateOutputFormat; + return this; + } + + /** + * Get dateOutputFormat + * @return dateOutputFormat + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_DATE_OUTPUT_FORMAT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getDateOutputFormat() { + return dateOutputFormat; + } + + + @JsonProperty(value = JSON_PROPERTY_DATE_OUTPUT_FORMAT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setDateOutputFormat(@javax.annotation.Nullable String dateOutputFormat) { + this.dateOutputFormat = dateOutputFormat; + } + + public ResultSetResultSetMetaDataParameters timeOutputFormat(@javax.annotation.Nullable String timeOutputFormat) { + + this.timeOutputFormat = timeOutputFormat; + return this; + } + + /** + * Get timeOutputFormat + * @return timeOutputFormat + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_TIME_OUTPUT_FORMAT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getTimeOutputFormat() { + return timeOutputFormat; + } + + + @JsonProperty(value = JSON_PROPERTY_TIME_OUTPUT_FORMAT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setTimeOutputFormat(@javax.annotation.Nullable String timeOutputFormat) { + this.timeOutputFormat = timeOutputFormat; + } + + public ResultSetResultSetMetaDataParameters timestampOutputFormat(@javax.annotation.Nullable String timestampOutputFormat) { + + this.timestampOutputFormat = timestampOutputFormat; + return this; + } + + /** + * Get timestampOutputFormat + * @return timestampOutputFormat + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_TIMESTAMP_OUTPUT_FORMAT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getTimestampOutputFormat() { + return timestampOutputFormat; + } + + + @JsonProperty(value = JSON_PROPERTY_TIMESTAMP_OUTPUT_FORMAT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setTimestampOutputFormat(@javax.annotation.Nullable String timestampOutputFormat) { + this.timestampOutputFormat = timestampOutputFormat; + } + + public ResultSetResultSetMetaDataParameters timestampLtzOutputFormat(@javax.annotation.Nullable String timestampLtzOutputFormat) { + + this.timestampLtzOutputFormat = timestampLtzOutputFormat; + return this; + } + + /** + * Get timestampLtzOutputFormat + * @return timestampLtzOutputFormat + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_TIMESTAMP_LTZ_OUTPUT_FORMAT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getTimestampLtzOutputFormat() { + return timestampLtzOutputFormat; + } + + + @JsonProperty(value = JSON_PROPERTY_TIMESTAMP_LTZ_OUTPUT_FORMAT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setTimestampLtzOutputFormat(@javax.annotation.Nullable String timestampLtzOutputFormat) { + this.timestampLtzOutputFormat = timestampLtzOutputFormat; + } + + public ResultSetResultSetMetaDataParameters timestampNtzOutputFormat(@javax.annotation.Nullable String timestampNtzOutputFormat) { + + this.timestampNtzOutputFormat = timestampNtzOutputFormat; + return this; + } + + /** + * Get timestampNtzOutputFormat + * @return timestampNtzOutputFormat + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_TIMESTAMP_NTZ_OUTPUT_FORMAT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getTimestampNtzOutputFormat() { + return timestampNtzOutputFormat; + } + + + @JsonProperty(value = JSON_PROPERTY_TIMESTAMP_NTZ_OUTPUT_FORMAT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setTimestampNtzOutputFormat(@javax.annotation.Nullable String timestampNtzOutputFormat) { + this.timestampNtzOutputFormat = timestampNtzOutputFormat; + } + + public ResultSetResultSetMetaDataParameters timestampTzOutputFormat(@javax.annotation.Nullable String timestampTzOutputFormat) { + + this.timestampTzOutputFormat = timestampTzOutputFormat; + return this; + } + + /** + * Get timestampTzOutputFormat + * @return timestampTzOutputFormat + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_TIMESTAMP_TZ_OUTPUT_FORMAT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getTimestampTzOutputFormat() { + return timestampTzOutputFormat; + } + + + @JsonProperty(value = JSON_PROPERTY_TIMESTAMP_TZ_OUTPUT_FORMAT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setTimestampTzOutputFormat(@javax.annotation.Nullable String timestampTzOutputFormat) { + this.timestampTzOutputFormat = timestampTzOutputFormat; + } + + public ResultSetResultSetMetaDataParameters multiStatementCount(@javax.annotation.Nullable Integer multiStatementCount) { + + this.multiStatementCount = multiStatementCount; + return this; + } + + /** + * Get multiStatementCount + * @return multiStatementCount + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_MULTI_STATEMENT_COUNT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Integer getMultiStatementCount() { + return multiStatementCount; + } + + + @JsonProperty(value = JSON_PROPERTY_MULTI_STATEMENT_COUNT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setMultiStatementCount(@javax.annotation.Nullable Integer multiStatementCount) { + this.multiStatementCount = multiStatementCount; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResultSetResultSetMetaDataParameters resultSetResultSetMetaDataParameters = (ResultSetResultSetMetaDataParameters) o; + return Objects.equals(this.binaryOutputFormat, resultSetResultSetMetaDataParameters.binaryOutputFormat) && + Objects.equals(this.dateOutputFormat, resultSetResultSetMetaDataParameters.dateOutputFormat) && + Objects.equals(this.timeOutputFormat, resultSetResultSetMetaDataParameters.timeOutputFormat) && + Objects.equals(this.timestampOutputFormat, resultSetResultSetMetaDataParameters.timestampOutputFormat) && + Objects.equals(this.timestampLtzOutputFormat, resultSetResultSetMetaDataParameters.timestampLtzOutputFormat) && + Objects.equals(this.timestampNtzOutputFormat, resultSetResultSetMetaDataParameters.timestampNtzOutputFormat) && + Objects.equals(this.timestampTzOutputFormat, resultSetResultSetMetaDataParameters.timestampTzOutputFormat) && + Objects.equals(this.multiStatementCount, resultSetResultSetMetaDataParameters.multiStatementCount); + } + + @Override + public int hashCode() { + return Objects.hash(binaryOutputFormat, dateOutputFormat, timeOutputFormat, timestampOutputFormat, timestampLtzOutputFormat, timestampNtzOutputFormat, timestampTzOutputFormat, multiStatementCount); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResultSetResultSetMetaDataParameters {\n"); + sb.append(" binaryOutputFormat: ").append(toIndentedString(binaryOutputFormat)).append("\n"); + sb.append(" dateOutputFormat: ").append(toIndentedString(dateOutputFormat)).append("\n"); + sb.append(" timeOutputFormat: ").append(toIndentedString(timeOutputFormat)).append("\n"); + sb.append(" timestampOutputFormat: ").append(toIndentedString(timestampOutputFormat)).append("\n"); + sb.append(" timestampLtzOutputFormat: ").append(toIndentedString(timestampLtzOutputFormat)).append("\n"); + sb.append(" timestampNtzOutputFormat: ").append(toIndentedString(timestampNtzOutputFormat)).append("\n"); + sb.append(" timestampTzOutputFormat: ").append(toIndentedString(timestampTzOutputFormat)).append("\n"); + sb.append(" multiStatementCount: ").append(toIndentedString(multiStatementCount)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSetResultSetMetaDataPartitionInfoInner.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSetResultSetMetaDataPartitionInfoInner.java new file mode 100644 index 00000000..2f725cd5 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSetResultSetMetaDataPartitionInfoInner.java @@ -0,0 +1,174 @@ +/* + * Snowflake SQL API + * The Snowflake SQL API is a REST API that you can use to access and update data in a Snowflake database. + * + * The version of the OpenAPI document: 2.0.0 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Arrays; +import java.util.Locale; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * ResultSetResultSetMetaDataPartitionInfoInner + */ +@JsonPropertyOrder({ + ResultSetResultSetMetaDataPartitionInfoInner.JSON_PROPERTY_ROW_COUNT, + ResultSetResultSetMetaDataPartitionInfoInner.JSON_PROPERTY_COMPRESSED_SIZE, + ResultSetResultSetMetaDataPartitionInfoInner.JSON_PROPERTY_UNCOMPRESSED_SIZE +}) +@JsonTypeName("ResultSet_resultSetMetaData_partitionInfo_inner") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:41:35.116838100+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ResultSetResultSetMetaDataPartitionInfoInner { + public static final String JSON_PROPERTY_ROW_COUNT = "rowCount"; + @javax.annotation.Nullable + private Long rowCount; + + public static final String JSON_PROPERTY_COMPRESSED_SIZE = "compressedSize"; + @javax.annotation.Nullable + private Long compressedSize; + + public static final String JSON_PROPERTY_UNCOMPRESSED_SIZE = "uncompressedSize"; + @javax.annotation.Nullable + private Long uncompressedSize; + + public ResultSetResultSetMetaDataPartitionInfoInner() { + } + + public ResultSetResultSetMetaDataPartitionInfoInner rowCount(@javax.annotation.Nullable Long rowCount) { + + this.rowCount = rowCount; + return this; + } + + /** + * Number of rows in the partition. + * minimum: 0 + * @return rowCount + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_ROW_COUNT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Long getRowCount() { + return rowCount; + } + + + @JsonProperty(value = JSON_PROPERTY_ROW_COUNT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setRowCount(@javax.annotation.Nullable Long rowCount) { + this.rowCount = rowCount; + } + + public ResultSetResultSetMetaDataPartitionInfoInner compressedSize(@javax.annotation.Nullable Long compressedSize) { + + this.compressedSize = compressedSize; + return this; + } + + /** + * the partition size before the decompression. This may or may not be present in the partitionInfo. Uncompressed size would always be there. + * minimum: 0 + * @return compressedSize + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_COMPRESSED_SIZE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Long getCompressedSize() { + return compressedSize; + } + + + @JsonProperty(value = JSON_PROPERTY_COMPRESSED_SIZE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setCompressedSize(@javax.annotation.Nullable Long compressedSize) { + this.compressedSize = compressedSize; + } + + public ResultSetResultSetMetaDataPartitionInfoInner uncompressedSize(@javax.annotation.Nullable Long uncompressedSize) { + + this.uncompressedSize = uncompressedSize; + return this; + } + + /** + * the partition size after the decompression + * minimum: 0 + * @return uncompressedSize + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_UNCOMPRESSED_SIZE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Long getUncompressedSize() { + return uncompressedSize; + } + + + @JsonProperty(value = JSON_PROPERTY_UNCOMPRESSED_SIZE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setUncompressedSize(@javax.annotation.Nullable Long uncompressedSize) { + this.uncompressedSize = uncompressedSize; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResultSetResultSetMetaDataPartitionInfoInner resultSetResultSetMetaDataPartitionInfoInner = (ResultSetResultSetMetaDataPartitionInfoInner) o; + return Objects.equals(this.rowCount, resultSetResultSetMetaDataPartitionInfoInner.rowCount) && + Objects.equals(this.compressedSize, resultSetResultSetMetaDataPartitionInfoInner.compressedSize) && + Objects.equals(this.uncompressedSize, resultSetResultSetMetaDataPartitionInfoInner.uncompressedSize); + } + + @Override + public int hashCode() { + return Objects.hash(rowCount, compressedSize, uncompressedSize); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResultSetResultSetMetaDataPartitionInfoInner {\n"); + sb.append(" rowCount: ").append(toIndentedString(rowCount)).append("\n"); + sb.append(" compressedSize: ").append(toIndentedString(compressedSize)).append("\n"); + sb.append(" uncompressedSize: ").append(toIndentedString(uncompressedSize)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSetResultSetMetaDataRowTypeInner.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSetResultSetMetaDataRowTypeInner.java new file mode 100644 index 00000000..fc4289a2 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSetResultSetMetaDataRowTypeInner.java @@ -0,0 +1,270 @@ +/* + * Snowflake SQL API + * The Snowflake SQL API is a REST API that you can use to access and update data in a Snowflake database. + * + * The version of the OpenAPI document: 2.0.0 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Arrays; +import java.util.Locale; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * ResultSetResultSetMetaDataRowTypeInner + */ +@JsonPropertyOrder({ + ResultSetResultSetMetaDataRowTypeInner.JSON_PROPERTY_NAME, + ResultSetResultSetMetaDataRowTypeInner.JSON_PROPERTY_TYPE, + ResultSetResultSetMetaDataRowTypeInner.JSON_PROPERTY_LENGTH, + ResultSetResultSetMetaDataRowTypeInner.JSON_PROPERTY_PRECISION, + ResultSetResultSetMetaDataRowTypeInner.JSON_PROPERTY_SCALE, + ResultSetResultSetMetaDataRowTypeInner.JSON_PROPERTY_NULLABLE +}) +@JsonTypeName("ResultSet_resultSetMetaData_rowType_inner") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:41:35.116838100+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ResultSetResultSetMetaDataRowTypeInner { + public static final String JSON_PROPERTY_NAME = "name"; + @javax.annotation.Nullable + private String name; + + public static final String JSON_PROPERTY_TYPE = "type"; + @javax.annotation.Nullable + private String type; + + public static final String JSON_PROPERTY_LENGTH = "length"; + @javax.annotation.Nullable + private Long length; + + public static final String JSON_PROPERTY_PRECISION = "precision"; + @javax.annotation.Nullable + private Long precision; + + public static final String JSON_PROPERTY_SCALE = "scale"; + @javax.annotation.Nullable + private Long scale; + + public static final String JSON_PROPERTY_NULLABLE = "nullable"; + @javax.annotation.Nullable + private Boolean nullable; + + public ResultSetResultSetMetaDataRowTypeInner() { + } + + public ResultSetResultSetMetaDataRowTypeInner name(@javax.annotation.Nullable String name) { + + this.name = name; + return this; + } + + /** + * Get name + * @return name + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_NAME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getName() { + return name; + } + + + @JsonProperty(value = JSON_PROPERTY_NAME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setName(@javax.annotation.Nullable String name) { + this.name = name; + } + + public ResultSetResultSetMetaDataRowTypeInner type(@javax.annotation.Nullable String type) { + + this.type = type; + return this; + } + + /** + * Get type + * @return type + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_TYPE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getType() { + return type; + } + + + @JsonProperty(value = JSON_PROPERTY_TYPE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setType(@javax.annotation.Nullable String type) { + this.type = type; + } + + public ResultSetResultSetMetaDataRowTypeInner length(@javax.annotation.Nullable Long length) { + + this.length = length; + return this; + } + + /** + * Get length + * minimum: 0 + * @return length + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_LENGTH, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Long getLength() { + return length; + } + + + @JsonProperty(value = JSON_PROPERTY_LENGTH, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setLength(@javax.annotation.Nullable Long length) { + this.length = length; + } + + public ResultSetResultSetMetaDataRowTypeInner precision(@javax.annotation.Nullable Long precision) { + + this.precision = precision; + return this; + } + + /** + * Get precision + * minimum: 0 + * @return precision + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_PRECISION, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Long getPrecision() { + return precision; + } + + + @JsonProperty(value = JSON_PROPERTY_PRECISION, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setPrecision(@javax.annotation.Nullable Long precision) { + this.precision = precision; + } + + public ResultSetResultSetMetaDataRowTypeInner scale(@javax.annotation.Nullable Long scale) { + + this.scale = scale; + return this; + } + + /** + * Get scale + * minimum: 0 + * @return scale + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_SCALE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Long getScale() { + return scale; + } + + + @JsonProperty(value = JSON_PROPERTY_SCALE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setScale(@javax.annotation.Nullable Long scale) { + this.scale = scale; + } + + public ResultSetResultSetMetaDataRowTypeInner nullable(@javax.annotation.Nullable Boolean nullable) { + + this.nullable = nullable; + return this; + } + + /** + * Get nullable + * @return nullable + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_NULLABLE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Boolean getNullable() { + return nullable; + } + + + @JsonProperty(value = JSON_PROPERTY_NULLABLE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setNullable(@javax.annotation.Nullable Boolean nullable) { + this.nullable = nullable; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResultSetResultSetMetaDataRowTypeInner resultSetResultSetMetaDataRowTypeInner = (ResultSetResultSetMetaDataRowTypeInner) o; + return Objects.equals(this.name, resultSetResultSetMetaDataRowTypeInner.name) && + Objects.equals(this.type, resultSetResultSetMetaDataRowTypeInner.type) && + Objects.equals(this.length, resultSetResultSetMetaDataRowTypeInner.length) && + Objects.equals(this.precision, resultSetResultSetMetaDataRowTypeInner.precision) && + Objects.equals(this.scale, resultSetResultSetMetaDataRowTypeInner.scale) && + Objects.equals(this.nullable, resultSetResultSetMetaDataRowTypeInner.nullable); + } + + @Override + public int hashCode() { + return Objects.hash(name, type, length, precision, scale, nullable); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResultSetResultSetMetaDataRowTypeInner {\n"); + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append(" type: ").append(toIndentedString(type)).append("\n"); + sb.append(" length: ").append(toIndentedString(length)).append("\n"); + sb.append(" precision: ").append(toIndentedString(precision)).append("\n"); + sb.append(" scale: ").append(toIndentedString(scale)).append("\n"); + sb.append(" nullable: ").append(toIndentedString(nullable)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSetStats.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSetStats.java new file mode 100644 index 00000000..fe7ae33d --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSetStats.java @@ -0,0 +1,207 @@ +/* + * Snowflake SQL API + * The Snowflake SQL API is a REST API that you can use to access and update data in a Snowflake database. + * + * The version of the OpenAPI document: 2.0.0 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Arrays; +import java.util.Locale; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * these stats might not be available for each request. + */ +@JsonPropertyOrder({ + ResultSetStats.JSON_PROPERTY_NUM_ROWS_INSERTED, + ResultSetStats.JSON_PROPERTY_NUM_ROWS_UPDATED, + ResultSetStats.JSON_PROPERTY_NUM_ROWS_DELETED, + ResultSetStats.JSON_PROPERTY_NUM_DUPLICATE_ROWS_UPDATED +}) +@JsonTypeName("ResultSet_stats") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:41:35.116838100+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ResultSetStats { + public static final String JSON_PROPERTY_NUM_ROWS_INSERTED = "numRowsInserted"; + @javax.annotation.Nullable + private Long numRowsInserted; + + public static final String JSON_PROPERTY_NUM_ROWS_UPDATED = "numRowsUpdated"; + @javax.annotation.Nullable + private Long numRowsUpdated; + + public static final String JSON_PROPERTY_NUM_ROWS_DELETED = "numRowsDeleted"; + @javax.annotation.Nullable + private Long numRowsDeleted; + + public static final String JSON_PROPERTY_NUM_DUPLICATE_ROWS_UPDATED = "numDuplicateRowsUpdated"; + @javax.annotation.Nullable + private Long numDuplicateRowsUpdated; + + public ResultSetStats() { + } + + public ResultSetStats numRowsInserted(@javax.annotation.Nullable Long numRowsInserted) { + + this.numRowsInserted = numRowsInserted; + return this; + } + + /** + * Number of rows that were inserted. + * minimum: 0 + * @return numRowsInserted + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_NUM_ROWS_INSERTED, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Long getNumRowsInserted() { + return numRowsInserted; + } + + + @JsonProperty(value = JSON_PROPERTY_NUM_ROWS_INSERTED, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setNumRowsInserted(@javax.annotation.Nullable Long numRowsInserted) { + this.numRowsInserted = numRowsInserted; + } + + public ResultSetStats numRowsUpdated(@javax.annotation.Nullable Long numRowsUpdated) { + + this.numRowsUpdated = numRowsUpdated; + return this; + } + + /** + * Number of rows that were updated. + * minimum: 0 + * @return numRowsUpdated + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_NUM_ROWS_UPDATED, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Long getNumRowsUpdated() { + return numRowsUpdated; + } + + + @JsonProperty(value = JSON_PROPERTY_NUM_ROWS_UPDATED, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setNumRowsUpdated(@javax.annotation.Nullable Long numRowsUpdated) { + this.numRowsUpdated = numRowsUpdated; + } + + public ResultSetStats numRowsDeleted(@javax.annotation.Nullable Long numRowsDeleted) { + + this.numRowsDeleted = numRowsDeleted; + return this; + } + + /** + * Number of rows that were deleted. + * minimum: 0 + * @return numRowsDeleted + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_NUM_ROWS_DELETED, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Long getNumRowsDeleted() { + return numRowsDeleted; + } + + + @JsonProperty(value = JSON_PROPERTY_NUM_ROWS_DELETED, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setNumRowsDeleted(@javax.annotation.Nullable Long numRowsDeleted) { + this.numRowsDeleted = numRowsDeleted; + } + + public ResultSetStats numDuplicateRowsUpdated(@javax.annotation.Nullable Long numDuplicateRowsUpdated) { + + this.numDuplicateRowsUpdated = numDuplicateRowsUpdated; + return this; + } + + /** + * Number of duplicate rows that were updated. + * minimum: 0 + * @return numDuplicateRowsUpdated + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_NUM_DUPLICATE_ROWS_UPDATED, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Long getNumDuplicateRowsUpdated() { + return numDuplicateRowsUpdated; + } + + + @JsonProperty(value = JSON_PROPERTY_NUM_DUPLICATE_ROWS_UPDATED, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setNumDuplicateRowsUpdated(@javax.annotation.Nullable Long numDuplicateRowsUpdated) { + this.numDuplicateRowsUpdated = numDuplicateRowsUpdated; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResultSetStats resultSetStats = (ResultSetStats) o; + return Objects.equals(this.numRowsInserted, resultSetStats.numRowsInserted) && + Objects.equals(this.numRowsUpdated, resultSetStats.numRowsUpdated) && + Objects.equals(this.numRowsDeleted, resultSetStats.numRowsDeleted) && + Objects.equals(this.numDuplicateRowsUpdated, resultSetStats.numDuplicateRowsUpdated); + } + + @Override + public int hashCode() { + return Objects.hash(numRowsInserted, numRowsUpdated, numRowsDeleted, numDuplicateRowsUpdated); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResultSetStats {\n"); + sb.append(" numRowsInserted: ").append(toIndentedString(numRowsInserted)).append("\n"); + sb.append(" numRowsUpdated: ").append(toIndentedString(numRowsUpdated)).append("\n"); + sb.append(" numRowsDeleted: ").append(toIndentedString(numRowsDeleted)).append("\n"); + sb.append(" numDuplicateRowsUpdated: ").append(toIndentedString(numDuplicateRowsUpdated)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/Service.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/Service.java new file mode 100644 index 00000000..7e1bb4e9 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/Service.java @@ -0,0 +1,897 @@ +/* + * Snowflake Services API + * The Snowflake Services API is a REST API that you can use to access, update, and perform certain actions on Services resource in a Snowflake database. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Arrays; +import java.util.Locale; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceSpec; +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Service + */ +@JsonPropertyOrder({ + Service.JSON_PROPERTY_NAME, + Service.JSON_PROPERTY_STATUS, + Service.JSON_PROPERTY_COMPUTE_POOL, + Service.JSON_PROPERTY_SPEC, + Service.JSON_PROPERTY_EXTERNAL_ACCESS_INTEGRATIONS, + Service.JSON_PROPERTY_QUERY_WAREHOUSE, + Service.JSON_PROPERTY_COMMENT, + Service.JSON_PROPERTY_IS_ASYNC_JOB, + Service.JSON_PROPERTY_AUTO_RESUME, + Service.JSON_PROPERTY_CURRENT_INSTANCES, + Service.JSON_PROPERTY_TARGET_INSTANCES, + Service.JSON_PROPERTY_MIN_READY_INSTANCES, + Service.JSON_PROPERTY_MIN_INSTANCES, + Service.JSON_PROPERTY_MAX_INSTANCES, + Service.JSON_PROPERTY_DATABASE_NAME, + Service.JSON_PROPERTY_SCHEMA_NAME, + Service.JSON_PROPERTY_OWNER, + Service.JSON_PROPERTY_DNS_NAME, + Service.JSON_PROPERTY_CREATED_ON, + Service.JSON_PROPERTY_UPDATED_ON, + Service.JSON_PROPERTY_RESUMED_ON, + Service.JSON_PROPERTY_SUSPENDED_ON, + Service.JSON_PROPERTY_AUTO_SUSPEND_SECS, + Service.JSON_PROPERTY_OWNER_ROLE_TYPE, + Service.JSON_PROPERTY_IS_JOB, + Service.JSON_PROPERTY_SPEC_DIGEST, + Service.JSON_PROPERTY_IS_UPGRADING, + Service.JSON_PROPERTY_MANAGING_OBJECT_DOMAIN, + Service.JSON_PROPERTY_MANAGING_OBJECT_NAME +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:41:25.529847700+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class Service { + public static final String JSON_PROPERTY_NAME = "name"; + @javax.annotation.Nonnull + private String name; + + public static final String JSON_PROPERTY_STATUS = "status"; + @javax.annotation.Nullable + private String status; + + public static final String JSON_PROPERTY_COMPUTE_POOL = "compute_pool"; + @javax.annotation.Nonnull + private String computePool; + + public static final String JSON_PROPERTY_SPEC = "spec"; + @javax.annotation.Nonnull + private ServiceSpec spec; + + public static final String JSON_PROPERTY_EXTERNAL_ACCESS_INTEGRATIONS = "external_access_integrations"; + @javax.annotation.Nullable + private List externalAccessIntegrations = new ArrayList<>(); + + public static final String JSON_PROPERTY_QUERY_WAREHOUSE = "query_warehouse"; + @javax.annotation.Nullable + private String queryWarehouse; + + public static final String JSON_PROPERTY_COMMENT = "comment"; + @javax.annotation.Nullable + private String comment; + + public static final String JSON_PROPERTY_IS_ASYNC_JOB = "is_async_job"; + @javax.annotation.Nullable + private Boolean isAsyncJob; + + public static final String JSON_PROPERTY_AUTO_RESUME = "auto_resume"; + @javax.annotation.Nullable + private Boolean autoResume; + + public static final String JSON_PROPERTY_CURRENT_INSTANCES = "current_instances"; + @javax.annotation.Nullable + private Integer currentInstances; + + public static final String JSON_PROPERTY_TARGET_INSTANCES = "target_instances"; + @javax.annotation.Nullable + private Integer targetInstances; + + public static final String JSON_PROPERTY_MIN_READY_INSTANCES = "min_ready_instances"; + @javax.annotation.Nullable + private Integer minReadyInstances; + + public static final String JSON_PROPERTY_MIN_INSTANCES = "min_instances"; + @javax.annotation.Nullable + private Integer minInstances; + + public static final String JSON_PROPERTY_MAX_INSTANCES = "max_instances"; + @javax.annotation.Nullable + private Integer maxInstances; + + public static final String JSON_PROPERTY_DATABASE_NAME = "database_name"; + @javax.annotation.Nullable + private String databaseName; + + public static final String JSON_PROPERTY_SCHEMA_NAME = "schema_name"; + @javax.annotation.Nullable + private String schemaName; + + public static final String JSON_PROPERTY_OWNER = "owner"; + @javax.annotation.Nullable + private String owner; + + public static final String JSON_PROPERTY_DNS_NAME = "dns_name"; + @javax.annotation.Nullable + private String dnsName; + + public static final String JSON_PROPERTY_CREATED_ON = "created_on"; + @javax.annotation.Nullable + private OffsetDateTime createdOn; + + public static final String JSON_PROPERTY_UPDATED_ON = "updated_on"; + @javax.annotation.Nullable + private OffsetDateTime updatedOn; + + public static final String JSON_PROPERTY_RESUMED_ON = "resumed_on"; + @javax.annotation.Nullable + private OffsetDateTime resumedOn; + + public static final String JSON_PROPERTY_SUSPENDED_ON = "suspended_on"; + @javax.annotation.Nullable + private OffsetDateTime suspendedOn; + + public static final String JSON_PROPERTY_AUTO_SUSPEND_SECS = "auto_suspend_secs"; + @javax.annotation.Nullable + private Long autoSuspendSecs; + + public static final String JSON_PROPERTY_OWNER_ROLE_TYPE = "owner_role_type"; + @javax.annotation.Nullable + private String ownerRoleType; + + public static final String JSON_PROPERTY_IS_JOB = "is_job"; + @javax.annotation.Nullable + private Boolean isJob; + + public static final String JSON_PROPERTY_SPEC_DIGEST = "spec_digest"; + @javax.annotation.Nullable + private String specDigest; + + public static final String JSON_PROPERTY_IS_UPGRADING = "is_upgrading"; + @javax.annotation.Nullable + private Boolean isUpgrading; + + public static final String JSON_PROPERTY_MANAGING_OBJECT_DOMAIN = "managing_object_domain"; + @javax.annotation.Nullable + private String managingObjectDomain; + + public static final String JSON_PROPERTY_MANAGING_OBJECT_NAME = "managing_object_name"; + @javax.annotation.Nullable + private String managingObjectName; + + public Service() { + } + /** + * Constructor with only readonly parameters + */ + @JsonCreator + public Service( + @JsonProperty(JSON_PROPERTY_CURRENT_INSTANCES) Integer currentInstances, + @JsonProperty(JSON_PROPERTY_TARGET_INSTANCES) Integer targetInstances, + @JsonProperty(JSON_PROPERTY_OWNER) String owner, + @JsonProperty(JSON_PROPERTY_DNS_NAME) String dnsName, + @JsonProperty(JSON_PROPERTY_CREATED_ON) OffsetDateTime createdOn, + @JsonProperty(JSON_PROPERTY_UPDATED_ON) OffsetDateTime updatedOn, + @JsonProperty(JSON_PROPERTY_RESUMED_ON) OffsetDateTime resumedOn, + @JsonProperty(JSON_PROPERTY_SUSPENDED_ON) OffsetDateTime suspendedOn, + @JsonProperty(JSON_PROPERTY_OWNER_ROLE_TYPE) String ownerRoleType, + @JsonProperty(JSON_PROPERTY_IS_JOB) Boolean isJob, + @JsonProperty(JSON_PROPERTY_SPEC_DIGEST) String specDigest, + @JsonProperty(JSON_PROPERTY_IS_UPGRADING) Boolean isUpgrading, + @JsonProperty(JSON_PROPERTY_MANAGING_OBJECT_DOMAIN) String managingObjectDomain, + @JsonProperty(JSON_PROPERTY_MANAGING_OBJECT_NAME) String managingObjectName + ) { + this(); + this.currentInstances = currentInstances; + this.targetInstances = targetInstances; + this.owner = owner; + this.dnsName = dnsName; + this.createdOn = createdOn; + this.updatedOn = updatedOn; + this.resumedOn = resumedOn; + this.suspendedOn = suspendedOn; + this.ownerRoleType = ownerRoleType; + this.isJob = isJob; + this.specDigest = specDigest; + this.isUpgrading = isUpgrading; + this.managingObjectDomain = managingObjectDomain; + this.managingObjectName = managingObjectName; + } + + public Service name(@javax.annotation.Nonnull String name) { + + this.name = name; + return this; + } + + /** + * A Snowflake object identifier. If the identifier contains spaces or special characters, the entire string must be enclosed in double quotes. Identifiers enclosed in double quotes are also case-sensitive. + * @return name + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_NAME, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + + public String getName() { + return name; + } + + + @JsonProperty(value = JSON_PROPERTY_NAME, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setName(@javax.annotation.Nonnull String name) { + this.name = name; + } + + public Service status(@javax.annotation.Nullable String status) { + + this.status = status; + return this; + } + + /** + * The current status of the service. + * @return status + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_STATUS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getStatus() { + return status; + } + + + @JsonProperty(value = JSON_PROPERTY_STATUS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setStatus(@javax.annotation.Nullable String status) { + this.status = status; + } + + public Service computePool(@javax.annotation.Nonnull String computePool) { + + this.computePool = computePool; + return this; + } + + /** + * Specifies the name of the compute pool in your account on which to run the service. + * @return computePool + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_COMPUTE_POOL, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + + public String getComputePool() { + return computePool; + } + + + @JsonProperty(value = JSON_PROPERTY_COMPUTE_POOL, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setComputePool(@javax.annotation.Nonnull String computePool) { + this.computePool = computePool; + } + + public Service spec(@javax.annotation.Nonnull ServiceSpec spec) { + + this.spec = spec; + return this; + } + + /** + * Get spec + * @return spec + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_SPEC, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + + public ServiceSpec getSpec() { + return spec; + } + + + @JsonProperty(value = JSON_PROPERTY_SPEC, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setSpec(@javax.annotation.Nonnull ServiceSpec spec) { + this.spec = spec; + } + + public Service externalAccessIntegrations(@javax.annotation.Nullable List externalAccessIntegrations) { + + this.externalAccessIntegrations = externalAccessIntegrations; + return this; + } + + public Service addExternalAccessIntegrationsItem(String externalAccessIntegrationsItem) { + if (this.externalAccessIntegrations == null) { + this.externalAccessIntegrations = new ArrayList<>(); + } + this.externalAccessIntegrations.add(externalAccessIntegrationsItem); + return this; + } + + /** + * Specifies the names of the external access integrations that allow your service to access external sites. + * @return externalAccessIntegrations + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_EXTERNAL_ACCESS_INTEGRATIONS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public List getExternalAccessIntegrations() { + return externalAccessIntegrations; + } + + + @JsonProperty(value = JSON_PROPERTY_EXTERNAL_ACCESS_INTEGRATIONS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setExternalAccessIntegrations(@javax.annotation.Nullable List externalAccessIntegrations) { + this.externalAccessIntegrations = externalAccessIntegrations; + } + + public Service queryWarehouse(@javax.annotation.Nullable String queryWarehouse) { + + this.queryWarehouse = queryWarehouse; + return this; + } + + /** + * A Snowflake object identifier. If the identifier contains spaces or special characters, the entire string must be enclosed in double quotes. Identifiers enclosed in double quotes are also case-sensitive. + * @return queryWarehouse + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_QUERY_WAREHOUSE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getQueryWarehouse() { + return queryWarehouse; + } + + + @JsonProperty(value = JSON_PROPERTY_QUERY_WAREHOUSE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setQueryWarehouse(@javax.annotation.Nullable String queryWarehouse) { + this.queryWarehouse = queryWarehouse; + } + + public Service comment(@javax.annotation.Nullable String comment) { + + this.comment = comment; + return this; + } + + /** + * Specifies a comment for the service. + * @return comment + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_COMMENT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getComment() { + return comment; + } + + + @JsonProperty(value = JSON_PROPERTY_COMMENT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setComment(@javax.annotation.Nullable String comment) { + this.comment = comment; + } + + public Service isAsyncJob(@javax.annotation.Nullable Boolean isAsyncJob) { + + this.isAsyncJob = isAsyncJob; + return this; + } + + /** + * True if the service is an async job service; false otherwise. + * @return isAsyncJob + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_IS_ASYNC_JOB, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Boolean getIsAsyncJob() { + return isAsyncJob; + } + + + @JsonProperty(value = JSON_PROPERTY_IS_ASYNC_JOB, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setIsAsyncJob(@javax.annotation.Nullable Boolean isAsyncJob) { + this.isAsyncJob = isAsyncJob; + } + + public Service autoResume(@javax.annotation.Nullable Boolean autoResume) { + + this.autoResume = autoResume; + return this; + } + + /** + * Specifies whether to automatically resume a service when a service function or ingress is called. + * @return autoResume + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_AUTO_RESUME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Boolean getAutoResume() { + return autoResume; + } + + + @JsonProperty(value = JSON_PROPERTY_AUTO_RESUME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setAutoResume(@javax.annotation.Nullable Boolean autoResume) { + this.autoResume = autoResume; + } + + /** + * The current number of instances for the service. + * @return currentInstances + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_CURRENT_INSTANCES, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Integer getCurrentInstances() { + return currentInstances; + } + + + + /** + * The target number of service instances that should be running as determined by Snowflake. + * @return targetInstances + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_TARGET_INSTANCES, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Integer getTargetInstances() { + return targetInstances; + } + + + + public Service minReadyInstances(@javax.annotation.Nullable Integer minReadyInstances) { + + this.minReadyInstances = minReadyInstances; + return this; + } + + /** + * The minimum number of ready service instances to declare the service as READY. + * @return minReadyInstances + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_MIN_READY_INSTANCES, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Integer getMinReadyInstances() { + return minReadyInstances; + } + + + @JsonProperty(value = JSON_PROPERTY_MIN_READY_INSTANCES, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setMinReadyInstances(@javax.annotation.Nullable Integer minReadyInstances) { + this.minReadyInstances = minReadyInstances; + } + + public Service minInstances(@javax.annotation.Nullable Integer minInstances) { + + this.minInstances = minInstances; + return this; + } + + /** + * Specifies the minimum number of service instances to run. + * @return minInstances + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_MIN_INSTANCES, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Integer getMinInstances() { + return minInstances; + } + + + @JsonProperty(value = JSON_PROPERTY_MIN_INSTANCES, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setMinInstances(@javax.annotation.Nullable Integer minInstances) { + this.minInstances = minInstances; + } + + public Service maxInstances(@javax.annotation.Nullable Integer maxInstances) { + + this.maxInstances = maxInstances; + return this; + } + + /** + * Specifies the maximum number of service instances to run. + * @return maxInstances + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_MAX_INSTANCES, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Integer getMaxInstances() { + return maxInstances; + } + + + @JsonProperty(value = JSON_PROPERTY_MAX_INSTANCES, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setMaxInstances(@javax.annotation.Nullable Integer maxInstances) { + this.maxInstances = maxInstances; + } + + public Service databaseName(@javax.annotation.Nullable String databaseName) { + + this.databaseName = databaseName; + return this; + } + + /** + * A Snowflake object identifier. If the identifier contains spaces or special characters, the entire string must be enclosed in double quotes. Identifiers enclosed in double quotes are also case-sensitive. + * @return databaseName + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_DATABASE_NAME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getDatabaseName() { + return databaseName; + } + + + @JsonProperty(value = JSON_PROPERTY_DATABASE_NAME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setDatabaseName(@javax.annotation.Nullable String databaseName) { + this.databaseName = databaseName; + } + + public Service schemaName(@javax.annotation.Nullable String schemaName) { + + this.schemaName = schemaName; + return this; + } + + /** + * A Snowflake object identifier. If the identifier contains spaces or special characters, the entire string must be enclosed in double quotes. Identifiers enclosed in double quotes are also case-sensitive. + * @return schemaName + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_SCHEMA_NAME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getSchemaName() { + return schemaName; + } + + + @JsonProperty(value = JSON_PROPERTY_SCHEMA_NAME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setSchemaName(@javax.annotation.Nullable String schemaName) { + this.schemaName = schemaName; + } + + /** + * Role that owns the service. + * @return owner + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_OWNER, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getOwner() { + return owner; + } + + + + /** + * Snowflake-assiged DNS name of the service. The DNS name enables service-to-service communications. + * @return dnsName + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_DNS_NAME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getDnsName() { + return dnsName; + } + + + + /** + * Timestamp when the service was created. + * @return createdOn + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_CREATED_ON, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public OffsetDateTime getCreatedOn() { + return createdOn; + } + + + + /** + * Timestamp when the service was last updated. + * @return updatedOn + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_UPDATED_ON, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public OffsetDateTime getUpdatedOn() { + return updatedOn; + } + + + + /** + * Timestamp when the service was last resumed. + * @return resumedOn + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_RESUMED_ON, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public OffsetDateTime getResumedOn() { + return resumedOn; + } + + + + /** + * Timestamp when the service was last suspended. + * @return suspendedOn + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_SUSPENDED_ON, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public OffsetDateTime getSuspendedOn() { + return suspendedOn; + } + + + + public Service autoSuspendSecs(@javax.annotation.Nullable Long autoSuspendSecs) { + + this.autoSuspendSecs = autoSuspendSecs; + return this; + } + + /** + * Number of seconds of inactivity after which the service will be automatically suspended. The default value is 0 which represents the service will not be automatically suspended. + * @return autoSuspendSecs + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_AUTO_SUSPEND_SECS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Long getAutoSuspendSecs() { + return autoSuspendSecs; + } + + + @JsonProperty(value = JSON_PROPERTY_AUTO_SUSPEND_SECS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setAutoSuspendSecs(@javax.annotation.Nullable Long autoSuspendSecs) { + this.autoSuspendSecs = autoSuspendSecs; + } + + /** + * The role type of the service owner. + * @return ownerRoleType + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_OWNER_ROLE_TYPE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getOwnerRoleType() { + return ownerRoleType; + } + + + + /** + * True if the service is a job service; false otherwise. + * @return isJob + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_IS_JOB, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Boolean getIsJob() { + return isJob; + } + + + + /** + * The unique and immutable identifier representing the service spec content. + * @return specDigest + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_SPEC_DIGEST, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getSpecDigest() { + return specDigest; + } + + + + /** + * TRUE, if Snowflake is in the process of upgrading the service. + * @return isUpgrading + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_IS_UPGRADING, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Boolean getIsUpgrading() { + return isUpgrading; + } + + + + /** + * The domain of the managing object (for example, the domain of the notebook that manages the service). NULL if the service is not managed by a Snowflake entity. + * @return managingObjectDomain + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_MANAGING_OBJECT_DOMAIN, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getManagingObjectDomain() { + return managingObjectDomain; + } + + + + /** + * The name of the managing object (for example, the name of the notebook that manages the service). NULL if the service is not managed by a Snowflake entity. + * @return managingObjectName + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_MANAGING_OBJECT_NAME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getManagingObjectName() { + return managingObjectName; + } + + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Service service = (Service) o; + return Objects.equals(this.name, service.name) && + Objects.equals(this.status, service.status) && + Objects.equals(this.computePool, service.computePool) && + Objects.equals(this.spec, service.spec) && + Objects.equals(this.externalAccessIntegrations, service.externalAccessIntegrations) && + Objects.equals(this.queryWarehouse, service.queryWarehouse) && + Objects.equals(this.comment, service.comment) && + Objects.equals(this.isAsyncJob, service.isAsyncJob) && + Objects.equals(this.autoResume, service.autoResume) && + Objects.equals(this.currentInstances, service.currentInstances) && + Objects.equals(this.targetInstances, service.targetInstances) && + Objects.equals(this.minReadyInstances, service.minReadyInstances) && + Objects.equals(this.minInstances, service.minInstances) && + Objects.equals(this.maxInstances, service.maxInstances) && + Objects.equals(this.databaseName, service.databaseName) && + Objects.equals(this.schemaName, service.schemaName) && + Objects.equals(this.owner, service.owner) && + Objects.equals(this.dnsName, service.dnsName) && + Objects.equals(this.createdOn, service.createdOn) && + Objects.equals(this.updatedOn, service.updatedOn) && + Objects.equals(this.resumedOn, service.resumedOn) && + Objects.equals(this.suspendedOn, service.suspendedOn) && + Objects.equals(this.autoSuspendSecs, service.autoSuspendSecs) && + Objects.equals(this.ownerRoleType, service.ownerRoleType) && + Objects.equals(this.isJob, service.isJob) && + Objects.equals(this.specDigest, service.specDigest) && + Objects.equals(this.isUpgrading, service.isUpgrading) && + Objects.equals(this.managingObjectDomain, service.managingObjectDomain) && + Objects.equals(this.managingObjectName, service.managingObjectName); + } + + @Override + public int hashCode() { + return Objects.hash(name, status, computePool, spec, externalAccessIntegrations, queryWarehouse, comment, isAsyncJob, autoResume, currentInstances, targetInstances, minReadyInstances, minInstances, maxInstances, databaseName, schemaName, owner, dnsName, createdOn, updatedOn, resumedOn, suspendedOn, autoSuspendSecs, ownerRoleType, isJob, specDigest, isUpgrading, managingObjectDomain, managingObjectName); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Service {\n"); + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append(" status: ").append(toIndentedString(status)).append("\n"); + sb.append(" computePool: ").append(toIndentedString(computePool)).append("\n"); + sb.append(" spec: ").append(toIndentedString(spec)).append("\n"); + sb.append(" externalAccessIntegrations: ").append(toIndentedString(externalAccessIntegrations)).append("\n"); + sb.append(" queryWarehouse: ").append(toIndentedString(queryWarehouse)).append("\n"); + sb.append(" comment: ").append(toIndentedString(comment)).append("\n"); + sb.append(" isAsyncJob: ").append(toIndentedString(isAsyncJob)).append("\n"); + sb.append(" autoResume: ").append(toIndentedString(autoResume)).append("\n"); + sb.append(" currentInstances: ").append(toIndentedString(currentInstances)).append("\n"); + sb.append(" targetInstances: ").append(toIndentedString(targetInstances)).append("\n"); + sb.append(" minReadyInstances: ").append(toIndentedString(minReadyInstances)).append("\n"); + sb.append(" minInstances: ").append(toIndentedString(minInstances)).append("\n"); + sb.append(" maxInstances: ").append(toIndentedString(maxInstances)).append("\n"); + sb.append(" databaseName: ").append(toIndentedString(databaseName)).append("\n"); + sb.append(" schemaName: ").append(toIndentedString(schemaName)).append("\n"); + sb.append(" owner: ").append(toIndentedString(owner)).append("\n"); + sb.append(" dnsName: ").append(toIndentedString(dnsName)).append("\n"); + sb.append(" createdOn: ").append(toIndentedString(createdOn)).append("\n"); + sb.append(" updatedOn: ").append(toIndentedString(updatedOn)).append("\n"); + sb.append(" resumedOn: ").append(toIndentedString(resumedOn)).append("\n"); + sb.append(" suspendedOn: ").append(toIndentedString(suspendedOn)).append("\n"); + sb.append(" autoSuspendSecs: ").append(toIndentedString(autoSuspendSecs)).append("\n"); + sb.append(" ownerRoleType: ").append(toIndentedString(ownerRoleType)).append("\n"); + sb.append(" isJob: ").append(toIndentedString(isJob)).append("\n"); + sb.append(" specDigest: ").append(toIndentedString(specDigest)).append("\n"); + sb.append(" isUpgrading: ").append(toIndentedString(isUpgrading)).append("\n"); + sb.append(" managingObjectDomain: ").append(toIndentedString(managingObjectDomain)).append("\n"); + sb.append(" managingObjectName: ").append(toIndentedString(managingObjectName)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceContainer.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceContainer.java new file mode 100644 index 00000000..7e673da3 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceContainer.java @@ -0,0 +1,408 @@ +/* + * Snowflake Services API + * The Snowflake Services API is a REST API that you can use to access, update, and perform certain actions on Services resource in a Snowflake database. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Arrays; +import java.util.Locale; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * ServiceContainer + */ +@JsonPropertyOrder({ + ServiceContainer.JSON_PROPERTY_DATABASE_NAME, + ServiceContainer.JSON_PROPERTY_SCHEMA_NAME, + ServiceContainer.JSON_PROPERTY_SERVICE_NAME, + ServiceContainer.JSON_PROPERTY_SERVICE_STATUS, + ServiceContainer.JSON_PROPERTY_INSTANCE_ID, + ServiceContainer.JSON_PROPERTY_INSTANCE_STATUS, + ServiceContainer.JSON_PROPERTY_CONTAINER_NAME, + ServiceContainer.JSON_PROPERTY_STATUS, + ServiceContainer.JSON_PROPERTY_MESSAGE, + ServiceContainer.JSON_PROPERTY_IMAGE_NAME, + ServiceContainer.JSON_PROPERTY_IMAGE_DIGEST, + ServiceContainer.JSON_PROPERTY_RESTART_COUNT, + ServiceContainer.JSON_PROPERTY_START_TIME +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:41:25.529847700+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ServiceContainer { + public static final String JSON_PROPERTY_DATABASE_NAME = "database_name"; + @javax.annotation.Nullable + private String databaseName; + + public static final String JSON_PROPERTY_SCHEMA_NAME = "schema_name"; + @javax.annotation.Nullable + private String schemaName; + + public static final String JSON_PROPERTY_SERVICE_NAME = "service_name"; + @javax.annotation.Nullable + private String serviceName; + + public static final String JSON_PROPERTY_SERVICE_STATUS = "service_status"; + @javax.annotation.Nullable + private String serviceStatus; + + public static final String JSON_PROPERTY_INSTANCE_ID = "instance_id"; + @javax.annotation.Nullable + private String instanceId; + + public static final String JSON_PROPERTY_INSTANCE_STATUS = "instance_status"; + @javax.annotation.Nullable + private String instanceStatus; + + public static final String JSON_PROPERTY_CONTAINER_NAME = "container_name"; + @javax.annotation.Nullable + private String containerName; + + public static final String JSON_PROPERTY_STATUS = "status"; + @javax.annotation.Nullable + private String status; + + public static final String JSON_PROPERTY_MESSAGE = "message"; + @javax.annotation.Nullable + private String message; + + public static final String JSON_PROPERTY_IMAGE_NAME = "image_name"; + @javax.annotation.Nullable + private String imageName; + + public static final String JSON_PROPERTY_IMAGE_DIGEST = "image_digest"; + @javax.annotation.Nullable + private String imageDigest; + + public static final String JSON_PROPERTY_RESTART_COUNT = "restart_count"; + @javax.annotation.Nullable + private Integer restartCount; + + public static final String JSON_PROPERTY_START_TIME = "start_time"; + @javax.annotation.Nullable + private String startTime; + + public ServiceContainer() { + } + /** + * Constructor with only readonly parameters + */ + @JsonCreator + public ServiceContainer( + @JsonProperty(JSON_PROPERTY_SERVICE_STATUS) String serviceStatus, + @JsonProperty(JSON_PROPERTY_INSTANCE_ID) String instanceId, + @JsonProperty(JSON_PROPERTY_INSTANCE_STATUS) String instanceStatus, + @JsonProperty(JSON_PROPERTY_CONTAINER_NAME) String containerName, + @JsonProperty(JSON_PROPERTY_STATUS) String status, + @JsonProperty(JSON_PROPERTY_MESSAGE) String message, + @JsonProperty(JSON_PROPERTY_IMAGE_NAME) String imageName, + @JsonProperty(JSON_PROPERTY_IMAGE_DIGEST) String imageDigest, + @JsonProperty(JSON_PROPERTY_RESTART_COUNT) Integer restartCount, + @JsonProperty(JSON_PROPERTY_START_TIME) String startTime + ) { + this(); + this.serviceStatus = serviceStatus; + this.instanceId = instanceId; + this.instanceStatus = instanceStatus; + this.containerName = containerName; + this.status = status; + this.message = message; + this.imageName = imageName; + this.imageDigest = imageDigest; + this.restartCount = restartCount; + this.startTime = startTime; + } + + public ServiceContainer databaseName(@javax.annotation.Nullable String databaseName) { + + this.databaseName = databaseName; + return this; + } + + /** + * A Snowflake object identifier. If the identifier contains spaces or special characters, the entire string must be enclosed in double quotes. Identifiers enclosed in double quotes are also case-sensitive. + * @return databaseName + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_DATABASE_NAME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getDatabaseName() { + return databaseName; + } + + + @JsonProperty(value = JSON_PROPERTY_DATABASE_NAME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setDatabaseName(@javax.annotation.Nullable String databaseName) { + this.databaseName = databaseName; + } + + public ServiceContainer schemaName(@javax.annotation.Nullable String schemaName) { + + this.schemaName = schemaName; + return this; + } + + /** + * A Snowflake object identifier. If the identifier contains spaces or special characters, the entire string must be enclosed in double quotes. Identifiers enclosed in double quotes are also case-sensitive. + * @return schemaName + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_SCHEMA_NAME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getSchemaName() { + return schemaName; + } + + + @JsonProperty(value = JSON_PROPERTY_SCHEMA_NAME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setSchemaName(@javax.annotation.Nullable String schemaName) { + this.schemaName = schemaName; + } + + public ServiceContainer serviceName(@javax.annotation.Nullable String serviceName) { + + this.serviceName = serviceName; + return this; + } + + /** + * A Snowflake object identifier. If the identifier contains spaces or special characters, the entire string must be enclosed in double quotes. Identifiers enclosed in double quotes are also case-sensitive. + * @return serviceName + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_SERVICE_NAME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getServiceName() { + return serviceName; + } + + + @JsonProperty(value = JSON_PROPERTY_SERVICE_NAME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setServiceName(@javax.annotation.Nullable String serviceName) { + this.serviceName = serviceName; + } + + /** + * The current status of the service. + * @return serviceStatus + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_SERVICE_STATUS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getServiceStatus() { + return serviceStatus; + } + + + + /** + * ID of the service instance (this is the index of the service instance starting from 0). + * @return instanceId + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_INSTANCE_ID, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getInstanceId() { + return instanceId; + } + + + + /** + * The current status of the service instance. + * @return instanceStatus + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_INSTANCE_STATUS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getInstanceStatus() { + return instanceStatus; + } + + + + /** + * Name of the container. + * @return containerName + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_CONTAINER_NAME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getContainerName() { + return containerName; + } + + + + /** + * Service container status. + * @return status + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_STATUS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getStatus() { + return status; + } + + + + /** + * Additional clarification about status. + * @return message + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_MESSAGE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getMessage() { + return message; + } + + + + /** + * Image name used to create the service container. + * @return imageName + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_IMAGE_NAME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getImageName() { + return imageName; + } + + + + /** + * The unique and immutable identifier representing the image content. + * @return imageDigest + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_IMAGE_DIGEST, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getImageDigest() { + return imageDigest; + } + + + + /** + * Number of times Snowflake restarted the service. + * @return restartCount + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_RESTART_COUNT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Integer getRestartCount() { + return restartCount; + } + + + + /** + * Date and time when the container started. + * @return startTime + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_START_TIME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getStartTime() { + return startTime; + } + + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ServiceContainer serviceContainer = (ServiceContainer) o; + return Objects.equals(this.databaseName, serviceContainer.databaseName) && + Objects.equals(this.schemaName, serviceContainer.schemaName) && + Objects.equals(this.serviceName, serviceContainer.serviceName) && + Objects.equals(this.serviceStatus, serviceContainer.serviceStatus) && + Objects.equals(this.instanceId, serviceContainer.instanceId) && + Objects.equals(this.instanceStatus, serviceContainer.instanceStatus) && + Objects.equals(this.containerName, serviceContainer.containerName) && + Objects.equals(this.status, serviceContainer.status) && + Objects.equals(this.message, serviceContainer.message) && + Objects.equals(this.imageName, serviceContainer.imageName) && + Objects.equals(this.imageDigest, serviceContainer.imageDigest) && + Objects.equals(this.restartCount, serviceContainer.restartCount) && + Objects.equals(this.startTime, serviceContainer.startTime); + } + + @Override + public int hashCode() { + return Objects.hash(databaseName, schemaName, serviceName, serviceStatus, instanceId, instanceStatus, containerName, status, message, imageName, imageDigest, restartCount, startTime); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ServiceContainer {\n"); + sb.append(" databaseName: ").append(toIndentedString(databaseName)).append("\n"); + sb.append(" schemaName: ").append(toIndentedString(schemaName)).append("\n"); + sb.append(" serviceName: ").append(toIndentedString(serviceName)).append("\n"); + sb.append(" serviceStatus: ").append(toIndentedString(serviceStatus)).append("\n"); + sb.append(" instanceId: ").append(toIndentedString(instanceId)).append("\n"); + sb.append(" instanceStatus: ").append(toIndentedString(instanceStatus)).append("\n"); + sb.append(" containerName: ").append(toIndentedString(containerName)).append("\n"); + sb.append(" status: ").append(toIndentedString(status)).append("\n"); + sb.append(" message: ").append(toIndentedString(message)).append("\n"); + sb.append(" imageName: ").append(toIndentedString(imageName)).append("\n"); + sb.append(" imageDigest: ").append(toIndentedString(imageDigest)).append("\n"); + sb.append(" restartCount: ").append(toIndentedString(restartCount)).append("\n"); + sb.append(" startTime: ").append(toIndentedString(startTime)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceEndpoint.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceEndpoint.java new file mode 100644 index 00000000..f45547c5 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceEndpoint.java @@ -0,0 +1,265 @@ +/* + * Snowflake Services API + * The Snowflake Services API is a REST API that you can use to access, update, and perform certain actions on Services resource in a Snowflake database. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Arrays; +import java.util.Locale; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * ServiceEndpoint + */ +@JsonPropertyOrder({ + ServiceEndpoint.JSON_PROPERTY_NAME, + ServiceEndpoint.JSON_PROPERTY_PORT, + ServiceEndpoint.JSON_PROPERTY_PORT_RANGE, + ServiceEndpoint.JSON_PROPERTY_PROTOCOL, + ServiceEndpoint.JSON_PROPERTY_IS_PUBLIC, + ServiceEndpoint.JSON_PROPERTY_INGRESS_URL +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:41:25.529847700+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ServiceEndpoint { + public static final String JSON_PROPERTY_NAME = "name"; + @javax.annotation.Nullable + private String name; + + public static final String JSON_PROPERTY_PORT = "port"; + @javax.annotation.Nullable + private Integer port; + + public static final String JSON_PROPERTY_PORT_RANGE = "portRange"; + @javax.annotation.Nullable + private String portRange; + + public static final String JSON_PROPERTY_PROTOCOL = "protocol"; + @javax.annotation.Nullable + private String protocol = "HTTP"; + + public static final String JSON_PROPERTY_IS_PUBLIC = "is_public"; + @javax.annotation.Nullable + private Boolean isPublic = false; + + public static final String JSON_PROPERTY_INGRESS_URL = "ingress_url"; + @javax.annotation.Nullable + private String ingressUrl; + + public ServiceEndpoint() { + } + /** + * Constructor with only readonly parameters + */ + @JsonCreator + public ServiceEndpoint( + @JsonProperty(JSON_PROPERTY_INGRESS_URL) String ingressUrl + ) { + this(); + this.ingressUrl = ingressUrl; + } + + public ServiceEndpoint name(@javax.annotation.Nullable String name) { + + this.name = name; + return this; + } + + /** + * User-friendly endpoint name that represents the corresponding port. + * @return name + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_NAME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getName() { + return name; + } + + + @JsonProperty(value = JSON_PROPERTY_NAME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setName(@javax.annotation.Nullable String name) { + this.name = name; + } + + public ServiceEndpoint port(@javax.annotation.Nullable Integer port) { + + this.port = port; + return this; + } + + /** + * The network port the service is listening on. NULL, when portRange is specified. + * @return port + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_PORT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Integer getPort() { + return port; + } + + + @JsonProperty(value = JSON_PROPERTY_PORT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setPort(@javax.annotation.Nullable Integer port) { + this.port = port; + } + + public ServiceEndpoint portRange(@javax.annotation.Nullable String portRange) { + + this.portRange = portRange; + return this; + } + + /** + * The network port range the service is listening on. NULL, when port is specified. + * @return portRange + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_PORT_RANGE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getPortRange() { + return portRange; + } + + + @JsonProperty(value = JSON_PROPERTY_PORT_RANGE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setPortRange(@javax.annotation.Nullable String portRange) { + this.portRange = portRange; + } + + public ServiceEndpoint protocol(@javax.annotation.Nullable String protocol) { + + this.protocol = protocol; + return this; + } + + /** + * Supported network protocol (TCP, HTTP, or HTTPS). + * @return protocol + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_PROTOCOL, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getProtocol() { + return protocol; + } + + + @JsonProperty(value = JSON_PROPERTY_PROTOCOL, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setProtocol(@javax.annotation.Nullable String protocol) { + this.protocol = protocol; + } + + public ServiceEndpoint isPublic(@javax.annotation.Nullable Boolean isPublic) { + + this.isPublic = isPublic; + return this; + } + + /** + * True, if the endpoint is public, accessible from internet. + * @return isPublic + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_IS_PUBLIC, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Boolean getIsPublic() { + return isPublic; + } + + + @JsonProperty(value = JSON_PROPERTY_IS_PUBLIC, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setIsPublic(@javax.annotation.Nullable Boolean isPublic) { + this.isPublic = isPublic; + } + + /** + * Endpoint URL accessible from the internet. + * @return ingressUrl + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_INGRESS_URL, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getIngressUrl() { + return ingressUrl; + } + + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ServiceEndpoint serviceEndpoint = (ServiceEndpoint) o; + return Objects.equals(this.name, serviceEndpoint.name) && + Objects.equals(this.port, serviceEndpoint.port) && + Objects.equals(this.portRange, serviceEndpoint.portRange) && + Objects.equals(this.protocol, serviceEndpoint.protocol) && + Objects.equals(this.isPublic, serviceEndpoint.isPublic) && + Objects.equals(this.ingressUrl, serviceEndpoint.ingressUrl); + } + + @Override + public int hashCode() { + return Objects.hash(name, port, portRange, protocol, isPublic, ingressUrl); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ServiceEndpoint {\n"); + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append(" port: ").append(toIndentedString(port)).append("\n"); + sb.append(" portRange: ").append(toIndentedString(portRange)).append("\n"); + sb.append(" protocol: ").append(toIndentedString(protocol)).append("\n"); + sb.append(" isPublic: ").append(toIndentedString(isPublic)).append("\n"); + sb.append(" ingressUrl: ").append(toIndentedString(ingressUrl)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceInstance.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceInstance.java new file mode 100644 index 00000000..bed05c82 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceInstance.java @@ -0,0 +1,316 @@ +/* + * Snowflake Services API + * The Snowflake Services API is a REST API that you can use to access, update, and perform certain actions on Services resource in a Snowflake database. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Arrays; +import java.util.Locale; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * ServiceInstance + */ +@JsonPropertyOrder({ + ServiceInstance.JSON_PROPERTY_DATABASE_NAME, + ServiceInstance.JSON_PROPERTY_SCHEMA_NAME, + ServiceInstance.JSON_PROPERTY_SERVICE_NAME, + ServiceInstance.JSON_PROPERTY_SERVICE_STATUS, + ServiceInstance.JSON_PROPERTY_INSTANCE_ID, + ServiceInstance.JSON_PROPERTY_STATUS, + ServiceInstance.JSON_PROPERTY_SPEC_DIGEST, + ServiceInstance.JSON_PROPERTY_CREATION_TIME, + ServiceInstance.JSON_PROPERTY_START_TIME +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:41:25.529847700+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ServiceInstance { + public static final String JSON_PROPERTY_DATABASE_NAME = "database_name"; + @javax.annotation.Nullable + private String databaseName; + + public static final String JSON_PROPERTY_SCHEMA_NAME = "schema_name"; + @javax.annotation.Nullable + private String schemaName; + + public static final String JSON_PROPERTY_SERVICE_NAME = "service_name"; + @javax.annotation.Nullable + private String serviceName; + + public static final String JSON_PROPERTY_SERVICE_STATUS = "service_status"; + @javax.annotation.Nullable + private String serviceStatus; + + public static final String JSON_PROPERTY_INSTANCE_ID = "instance_id"; + @javax.annotation.Nullable + private String instanceId; + + public static final String JSON_PROPERTY_STATUS = "status"; + @javax.annotation.Nullable + private String status; + + public static final String JSON_PROPERTY_SPEC_DIGEST = "spec_digest"; + @javax.annotation.Nullable + private String specDigest; + + public static final String JSON_PROPERTY_CREATION_TIME = "creation_time"; + @javax.annotation.Nullable + private String creationTime; + + public static final String JSON_PROPERTY_START_TIME = "start_time"; + @javax.annotation.Nullable + private String startTime; + + public ServiceInstance() { + } + /** + * Constructor with only readonly parameters + */ + @JsonCreator + public ServiceInstance( + @JsonProperty(JSON_PROPERTY_SERVICE_STATUS) String serviceStatus, + @JsonProperty(JSON_PROPERTY_INSTANCE_ID) String instanceId, + @JsonProperty(JSON_PROPERTY_STATUS) String status, + @JsonProperty(JSON_PROPERTY_SPEC_DIGEST) String specDigest, + @JsonProperty(JSON_PROPERTY_CREATION_TIME) String creationTime, + @JsonProperty(JSON_PROPERTY_START_TIME) String startTime + ) { + this(); + this.serviceStatus = serviceStatus; + this.instanceId = instanceId; + this.status = status; + this.specDigest = specDigest; + this.creationTime = creationTime; + this.startTime = startTime; + } + + public ServiceInstance databaseName(@javax.annotation.Nullable String databaseName) { + + this.databaseName = databaseName; + return this; + } + + /** + * A Snowflake object identifier. If the identifier contains spaces or special characters, the entire string must be enclosed in double quotes. Identifiers enclosed in double quotes are also case-sensitive. + * @return databaseName + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_DATABASE_NAME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getDatabaseName() { + return databaseName; + } + + + @JsonProperty(value = JSON_PROPERTY_DATABASE_NAME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setDatabaseName(@javax.annotation.Nullable String databaseName) { + this.databaseName = databaseName; + } + + public ServiceInstance schemaName(@javax.annotation.Nullable String schemaName) { + + this.schemaName = schemaName; + return this; + } + + /** + * A Snowflake object identifier. If the identifier contains spaces or special characters, the entire string must be enclosed in double quotes. Identifiers enclosed in double quotes are also case-sensitive. + * @return schemaName + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_SCHEMA_NAME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getSchemaName() { + return schemaName; + } + + + @JsonProperty(value = JSON_PROPERTY_SCHEMA_NAME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setSchemaName(@javax.annotation.Nullable String schemaName) { + this.schemaName = schemaName; + } + + public ServiceInstance serviceName(@javax.annotation.Nullable String serviceName) { + + this.serviceName = serviceName; + return this; + } + + /** + * A Snowflake object identifier. If the identifier contains spaces or special characters, the entire string must be enclosed in double quotes. Identifiers enclosed in double quotes are also case-sensitive. + * @return serviceName + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_SERVICE_NAME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getServiceName() { + return serviceName; + } + + + @JsonProperty(value = JSON_PROPERTY_SERVICE_NAME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setServiceName(@javax.annotation.Nullable String serviceName) { + this.serviceName = serviceName; + } + + /** + * The current status of the service. + * @return serviceStatus + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_SERVICE_STATUS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getServiceStatus() { + return serviceStatus; + } + + + + /** + * ID of the service instance (this is the index of the service instance starting from 0). + * @return instanceId + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_INSTANCE_ID, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getInstanceId() { + return instanceId; + } + + + + /** + * The current status of the service instance. + * @return status + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_STATUS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getStatus() { + return status; + } + + + + /** + * The unique and immutable identifier that represents the service specification content. + * @return specDigest + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_SPEC_DIGEST, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getSpecDigest() { + return specDigest; + } + + + + /** + * The time when Snowflake started creating the service instance. + * @return creationTime + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_CREATION_TIME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getCreationTime() { + return creationTime; + } + + + + /** + * The time when Snowflake acknowledged the service instance is running on a node. + * @return startTime + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_START_TIME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getStartTime() { + return startTime; + } + + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ServiceInstance serviceInstance = (ServiceInstance) o; + return Objects.equals(this.databaseName, serviceInstance.databaseName) && + Objects.equals(this.schemaName, serviceInstance.schemaName) && + Objects.equals(this.serviceName, serviceInstance.serviceName) && + Objects.equals(this.serviceStatus, serviceInstance.serviceStatus) && + Objects.equals(this.instanceId, serviceInstance.instanceId) && + Objects.equals(this.status, serviceInstance.status) && + Objects.equals(this.specDigest, serviceInstance.specDigest) && + Objects.equals(this.creationTime, serviceInstance.creationTime) && + Objects.equals(this.startTime, serviceInstance.startTime); + } + + @Override + public int hashCode() { + return Objects.hash(databaseName, schemaName, serviceName, serviceStatus, instanceId, status, specDigest, creationTime, startTime); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ServiceInstance {\n"); + sb.append(" databaseName: ").append(toIndentedString(databaseName)).append("\n"); + sb.append(" schemaName: ").append(toIndentedString(schemaName)).append("\n"); + sb.append(" serviceName: ").append(toIndentedString(serviceName)).append("\n"); + sb.append(" serviceStatus: ").append(toIndentedString(serviceStatus)).append("\n"); + sb.append(" instanceId: ").append(toIndentedString(instanceId)).append("\n"); + sb.append(" status: ").append(toIndentedString(status)).append("\n"); + sb.append(" specDigest: ").append(toIndentedString(specDigest)).append("\n"); + sb.append(" creationTime: ").append(toIndentedString(creationTime)).append("\n"); + sb.append(" startTime: ").append(toIndentedString(startTime)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceRole.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceRole.java new file mode 100644 index 00000000..691adb27 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceRole.java @@ -0,0 +1,152 @@ +/* + * Snowflake Services API + * The Snowflake Services API is a REST API that you can use to access, update, and perform certain actions on Services resource in a Snowflake database. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Arrays; +import java.util.Locale; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import java.time.OffsetDateTime; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * ServiceRole + */ +@JsonPropertyOrder({ + ServiceRole.JSON_PROPERTY_CREATED_ON, + ServiceRole.JSON_PROPERTY_NAME, + ServiceRole.JSON_PROPERTY_COMMENT +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:41:25.529847700+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ServiceRole { + public static final String JSON_PROPERTY_CREATED_ON = "created_on"; + @javax.annotation.Nullable + private OffsetDateTime createdOn; + + public static final String JSON_PROPERTY_NAME = "name"; + @javax.annotation.Nullable + private String name; + + public static final String JSON_PROPERTY_COMMENT = "comment"; + @javax.annotation.Nullable + private String comment; + + public ServiceRole() { + } + /** + * Constructor with only readonly parameters + */ + @JsonCreator + public ServiceRole( + @JsonProperty(JSON_PROPERTY_CREATED_ON) OffsetDateTime createdOn, + @JsonProperty(JSON_PROPERTY_NAME) String name, + @JsonProperty(JSON_PROPERTY_COMMENT) String comment + ) { + this(); + this.createdOn = createdOn; + this.name = name; + this.comment = comment; + } + + /** + * Date and time when the service role was created + * @return createdOn + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_CREATED_ON, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public OffsetDateTime getCreatedOn() { + return createdOn; + } + + + + /** + * Service role name + * @return name + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_NAME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getName() { + return name; + } + + + + /** + * Comment, if any, for the service role + * @return comment + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_COMMENT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getComment() { + return comment; + } + + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ServiceRole serviceRole = (ServiceRole) o; + return Objects.equals(this.createdOn, serviceRole.createdOn) && + Objects.equals(this.name, serviceRole.name) && + Objects.equals(this.comment, serviceRole.comment); + } + + @Override + public int hashCode() { + return Objects.hash(createdOn, name, comment); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ServiceRole {\n"); + sb.append(" createdOn: ").append(toIndentedString(createdOn)).append("\n"); + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append(" comment: ").append(toIndentedString(comment)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceRoleGrantTo.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceRoleGrantTo.java new file mode 100644 index 00000000..5eb801b5 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceRoleGrantTo.java @@ -0,0 +1,221 @@ +/* + * Snowflake Services API + * The Snowflake Services API is a REST API that you can use to access, update, and perform certain actions on Services resource in a Snowflake database. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Arrays; +import java.util.Locale; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import java.time.OffsetDateTime; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * ServiceRoleGrantTo + */ +@JsonPropertyOrder({ + ServiceRoleGrantTo.JSON_PROPERTY_CREATED_ON, + ServiceRoleGrantTo.JSON_PROPERTY_PRIVILEGE, + ServiceRoleGrantTo.JSON_PROPERTY_GRANTED_ON, + ServiceRoleGrantTo.JSON_PROPERTY_NAME, + ServiceRoleGrantTo.JSON_PROPERTY_GRANTED_TO, + ServiceRoleGrantTo.JSON_PROPERTY_GRANTEE_NAME +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:41:25.529847700+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ServiceRoleGrantTo { + public static final String JSON_PROPERTY_CREATED_ON = "created_on"; + @javax.annotation.Nullable + private OffsetDateTime createdOn; + + public static final String JSON_PROPERTY_PRIVILEGE = "privilege"; + @javax.annotation.Nullable + private String privilege; + + public static final String JSON_PROPERTY_GRANTED_ON = "granted_on"; + @javax.annotation.Nullable + private String grantedOn; + + public static final String JSON_PROPERTY_NAME = "name"; + @javax.annotation.Nullable + private String name; + + public static final String JSON_PROPERTY_GRANTED_TO = "granted_to"; + @javax.annotation.Nullable + private String grantedTo; + + public static final String JSON_PROPERTY_GRANTEE_NAME = "grantee_name"; + @javax.annotation.Nullable + private String granteeName; + + public ServiceRoleGrantTo() { + } + /** + * Constructor with only readonly parameters + */ + @JsonCreator + public ServiceRoleGrantTo( + @JsonProperty(JSON_PROPERTY_CREATED_ON) OffsetDateTime createdOn, + @JsonProperty(JSON_PROPERTY_PRIVILEGE) String privilege, + @JsonProperty(JSON_PROPERTY_GRANTED_ON) String grantedOn, + @JsonProperty(JSON_PROPERTY_NAME) String name, + @JsonProperty(JSON_PROPERTY_GRANTED_TO) String grantedTo, + @JsonProperty(JSON_PROPERTY_GRANTEE_NAME) String granteeName + ) { + this(); + this.createdOn = createdOn; + this.privilege = privilege; + this.grantedOn = grantedOn; + this.name = name; + this.grantedTo = grantedTo; + this.granteeName = granteeName; + } + + /** + * Date and time when the grant was created + * @return createdOn + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_CREATED_ON, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public OffsetDateTime getCreatedOn() { + return createdOn; + } + + + + /** + * The name of the privilege + * @return privilege + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_PRIVILEGE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getPrivilege() { + return privilege; + } + + + + /** + * The type of of the securable + * @return grantedOn + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_GRANTED_ON, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getGrantedOn() { + return grantedOn; + } + + + + /** + * The name of the securable + * @return name + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_NAME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getName() { + return name; + } + + + + /** + * The type of the grantee + * @return grantedTo + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_GRANTED_TO, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getGrantedTo() { + return grantedTo; + } + + + + /** + * The name of the grantee + * @return granteeName + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_GRANTEE_NAME, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getGranteeName() { + return granteeName; + } + + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ServiceRoleGrantTo serviceRoleGrantTo = (ServiceRoleGrantTo) o; + return Objects.equals(this.createdOn, serviceRoleGrantTo.createdOn) && + Objects.equals(this.privilege, serviceRoleGrantTo.privilege) && + Objects.equals(this.grantedOn, serviceRoleGrantTo.grantedOn) && + Objects.equals(this.name, serviceRoleGrantTo.name) && + Objects.equals(this.grantedTo, serviceRoleGrantTo.grantedTo) && + Objects.equals(this.granteeName, serviceRoleGrantTo.granteeName); + } + + @Override + public int hashCode() { + return Objects.hash(createdOn, privilege, grantedOn, name, grantedTo, granteeName); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ServiceRoleGrantTo {\n"); + sb.append(" createdOn: ").append(toIndentedString(createdOn)).append("\n"); + sb.append(" privilege: ").append(toIndentedString(privilege)).append("\n"); + sb.append(" grantedOn: ").append(toIndentedString(grantedOn)).append("\n"); + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append(" grantedTo: ").append(toIndentedString(grantedTo)).append("\n"); + sb.append(" granteeName: ").append(toIndentedString(granteeName)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceSpec.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceSpec.java new file mode 100644 index 00000000..3c12e73f --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceSpec.java @@ -0,0 +1,119 @@ +/* + * Snowflake Services API + * The Snowflake Services API is a REST API that you can use to access, update, and perform certain actions on Services resource in a Snowflake database. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Arrays; +import java.util.Locale; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Specifies service specification. + */ +@JsonPropertyOrder({ + ServiceSpec.JSON_PROPERTY_SPEC_TYPE +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:41:25.529847700+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +@JsonIgnoreProperties( + value = "spec_type", // ignore manually set spec_type, it will be automatically generated by Jackson during serialization + allowSetters = true // allows the spec_type to be set during deserialization +) +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "spec_type", visible = true) +@JsonSubTypes({ + @JsonSubTypes.Type(value = ServiceSpecStageFile.class, name = "from_file"), + @JsonSubTypes.Type(value = ServiceSpecInlineText.class, name = "from_inline"), +}) + +public class ServiceSpec { + public static final String JSON_PROPERTY_SPEC_TYPE = "spec_type"; + // The discriminator does not have Nullability-annotation since it is added during serialization by the @JsonTypeName annotation + protected String specType; + + public ServiceSpec() { + } + + public ServiceSpec specType(@javax.annotation.Nullable String specType) { + + this.specType = specType; + return this; + } + + /** + * Type of the service specification, can be `from_file` or `from_inline`. + * @return specType + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_SPEC_TYPE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getSpecType() { + return specType; + } + + + @JsonProperty(value = JSON_PROPERTY_SPEC_TYPE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setSpecType(@javax.annotation.Nullable String specType) { + this.specType = specType; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ServiceSpec serviceSpec = (ServiceSpec) o; + return Objects.equals(this.specType, serviceSpec.specType); + } + + @Override + public int hashCode() { + return Objects.hash(specType); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ServiceSpec {\n"); + sb.append(" specType: ").append(toIndentedString(specType)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceSpecInlineText.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceSpecInlineText.java new file mode 100644 index 00000000..25c751b1 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceSpecInlineText.java @@ -0,0 +1,125 @@ +/* + * Snowflake Services API + * The Snowflake Services API is a REST API that you can use to access, update, and perform certain actions on Services resource in a Snowflake database. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Arrays; +import java.util.Locale; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceSpec; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * ServiceSpecInlineText + */ +@JsonPropertyOrder({ + ServiceSpecInlineText.JSON_PROPERTY_SPEC_TEXT +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:41:25.529847700+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +@JsonIgnoreProperties( + value = "spec_type", // ignore manually set spec_type, it will be automatically generated by Jackson during serialization + allowSetters = true // allows the spec_type to be set during deserialization +) +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "spec_type", visible = true) + +public class ServiceSpecInlineText extends ServiceSpec { + public static final String JSON_PROPERTY_SPEC_TEXT = "spec_text"; + @javax.annotation.Nonnull + private String specText; + + public ServiceSpecInlineText() { + + } + + public ServiceSpecInlineText specText(@javax.annotation.Nonnull String specText) { + + this.specText = specText; + return this; + } + + /** + * Specifies service specification. You can use a pair of dollar signs ($$) to delimit the beginning and ending of the specification string. + * @return specText + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_SPEC_TEXT, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + + public String getSpecText() { + return specText; + } + + + @JsonProperty(value = JSON_PROPERTY_SPEC_TEXT, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setSpecText(@javax.annotation.Nonnull String specText) { + this.specText = specText; + } + + + @Override + public ServiceSpecInlineText specType(@javax.annotation.Nullable String specType) { + this.setSpecType(specType); + return this; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ServiceSpecInlineText serviceSpecInlineText = (ServiceSpecInlineText) o; + return Objects.equals(this.specText, serviceSpecInlineText.specText) && + super.equals(o); + } + + @Override + public int hashCode() { + return Objects.hash(specText, super.hashCode()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ServiceSpecInlineText {\n"); + sb.append(" ").append(toIndentedString(super.toString())).append("\n"); + sb.append(" specText: ").append(toIndentedString(specText)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceSpecStageFile.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceSpecStageFile.java new file mode 100644 index 00000000..d2b74198 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceSpecStageFile.java @@ -0,0 +1,157 @@ +/* + * Snowflake Services API + * The Snowflake Services API is a REST API that you can use to access, update, and perform certain actions on Services resource in a Snowflake database. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Arrays; +import java.util.Locale; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceSpec; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * ServiceSpecStageFile + */ +@JsonPropertyOrder({ + ServiceSpecStageFile.JSON_PROPERTY_STAGE, + ServiceSpecStageFile.JSON_PROPERTY_SPEC_FILE +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:41:25.529847700+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +@JsonIgnoreProperties( + value = "spec_type", // ignore manually set spec_type, it will be automatically generated by Jackson during serialization + allowSetters = true // allows the spec_type to be set during deserialization +) +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "spec_type", visible = true) + +public class ServiceSpecStageFile extends ServiceSpec { + public static final String JSON_PROPERTY_STAGE = "stage"; + @javax.annotation.Nonnull + private String stage; + + public static final String JSON_PROPERTY_SPEC_FILE = "spec_file"; + @javax.annotation.Nonnull + private String specFile; + + public ServiceSpecStageFile() { + + } + + public ServiceSpecStageFile stage(@javax.annotation.Nonnull String stage) { + + this.stage = stage; + return this; + } + + /** + * Specifies the Snowflake internal stage where the specification file is stored; for example, @tutorial_stage. + * @return stage + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_STAGE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + + public String getStage() { + return stage; + } + + + @JsonProperty(value = JSON_PROPERTY_STAGE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setStage(@javax.annotation.Nonnull String stage) { + this.stage = stage; + } + + public ServiceSpecStageFile specFile(@javax.annotation.Nonnull String specFile) { + + this.specFile = specFile; + return this; + } + + /** + * Specifies the path to the service specification file on the stage; for example, 'some-dir/echo_spec.yaml'. + * @return specFile + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_SPEC_FILE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + + public String getSpecFile() { + return specFile; + } + + + @JsonProperty(value = JSON_PROPERTY_SPEC_FILE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setSpecFile(@javax.annotation.Nonnull String specFile) { + this.specFile = specFile; + } + + + @Override + public ServiceSpecStageFile specType(@javax.annotation.Nullable String specType) { + this.setSpecType(specType); + return this; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ServiceSpecStageFile serviceSpecStageFile = (ServiceSpecStageFile) o; + return Objects.equals(this.stage, serviceSpecStageFile.stage) && + Objects.equals(this.specFile, serviceSpecStageFile.specFile) && + super.equals(o); + } + + @Override + public int hashCode() { + return Objects.hash(stage, specFile, super.hashCode()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ServiceSpecStageFile {\n"); + sb.append(" ").append(toIndentedString(super.toString())).append("\n"); + sb.append(" stage: ").append(toIndentedString(stage)).append("\n"); + sb.append(" specFile: ").append(toIndentedString(specFile)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/SubmitStatementRequest.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/SubmitStatementRequest.java new file mode 100644 index 00000000..5069032d --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/SubmitStatementRequest.java @@ -0,0 +1,333 @@ +/* + * Snowflake SQL API + * The Snowflake SQL API is a REST API that you can use to access and update data in a Snowflake database. + * + * The version of the OpenAPI document: 2.0.0 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Arrays; +import java.util.Locale; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import eu.openanalytics.containerproxy.backend.spcs.client.model.SubmitStatementRequestParameters; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * SubmitStatementRequest + */ +@JsonPropertyOrder({ + SubmitStatementRequest.JSON_PROPERTY_STATEMENT, + SubmitStatementRequest.JSON_PROPERTY_TIMEOUT, + SubmitStatementRequest.JSON_PROPERTY_DATABASE, + SubmitStatementRequest.JSON_PROPERTY_SCHEMA, + SubmitStatementRequest.JSON_PROPERTY_WAREHOUSE, + SubmitStatementRequest.JSON_PROPERTY_ROLE, + SubmitStatementRequest.JSON_PROPERTY_BINDINGS, + SubmitStatementRequest.JSON_PROPERTY_PARAMETERS +}) +@JsonTypeName("SubmitStatement_request") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:41:35.116838100+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class SubmitStatementRequest { + public static final String JSON_PROPERTY_STATEMENT = "statement"; + @javax.annotation.Nullable + private String statement; + + public static final String JSON_PROPERTY_TIMEOUT = "timeout"; + @javax.annotation.Nullable + private Long timeout; + + public static final String JSON_PROPERTY_DATABASE = "database"; + @javax.annotation.Nullable + private String database; + + public static final String JSON_PROPERTY_SCHEMA = "schema"; + @javax.annotation.Nullable + private String schema; + + public static final String JSON_PROPERTY_WAREHOUSE = "warehouse"; + @javax.annotation.Nullable + private String warehouse; + + public static final String JSON_PROPERTY_ROLE = "role"; + @javax.annotation.Nullable + private String role; + + public static final String JSON_PROPERTY_BINDINGS = "bindings"; + @javax.annotation.Nullable + private Object bindings; + + public static final String JSON_PROPERTY_PARAMETERS = "parameters"; + @javax.annotation.Nullable + private SubmitStatementRequestParameters parameters; + + public SubmitStatementRequest() { + } + + public SubmitStatementRequest statement(@javax.annotation.Nullable String statement) { + + this.statement = statement; + return this; + } + + /** + * SQL statement or batch of SQL statements to execute. You can specify query, DML and DDL statements. The following statements are not supported: PUT, GET, USE, ALTER SESSION, BEGIN, COMMIT, ROLLBACK, statements that set session variables, and statements that create temporary tables and stages. + * @return statement + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_STATEMENT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getStatement() { + return statement; + } + + + @JsonProperty(value = JSON_PROPERTY_STATEMENT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setStatement(@javax.annotation.Nullable String statement) { + this.statement = statement; + } + + public SubmitStatementRequest timeout(@javax.annotation.Nullable Long timeout) { + + this.timeout = timeout; + return this; + } + + /** + * Timeout in seconds for statement execution. If the execution of a statement takes longer than the specified timeout, the execution is automatically canceled. To set the timeout to the maximum value (604800 seconds), set timeout to 0. + * minimum: 0 + * @return timeout + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_TIMEOUT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Long getTimeout() { + return timeout; + } + + + @JsonProperty(value = JSON_PROPERTY_TIMEOUT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setTimeout(@javax.annotation.Nullable Long timeout) { + this.timeout = timeout; + } + + public SubmitStatementRequest database(@javax.annotation.Nullable String database) { + + this.database = database; + return this; + } + + /** + * Database in which the statement should be executed. The value in this field is case-sensitive. + * @return database + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_DATABASE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getDatabase() { + return database; + } + + + @JsonProperty(value = JSON_PROPERTY_DATABASE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setDatabase(@javax.annotation.Nullable String database) { + this.database = database; + } + + public SubmitStatementRequest schema(@javax.annotation.Nullable String schema) { + + this.schema = schema; + return this; + } + + /** + * Schema in which the statement should be executed. The value in this field is case-sensitive. + * @return schema + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_SCHEMA, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getSchema() { + return schema; + } + + + @JsonProperty(value = JSON_PROPERTY_SCHEMA, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setSchema(@javax.annotation.Nullable String schema) { + this.schema = schema; + } + + public SubmitStatementRequest warehouse(@javax.annotation.Nullable String warehouse) { + + this.warehouse = warehouse; + return this; + } + + /** + * Warehouse to use when executing the statement. The value in this field is case-sensitive. + * @return warehouse + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_WAREHOUSE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getWarehouse() { + return warehouse; + } + + + @JsonProperty(value = JSON_PROPERTY_WAREHOUSE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setWarehouse(@javax.annotation.Nullable String warehouse) { + this.warehouse = warehouse; + } + + public SubmitStatementRequest role(@javax.annotation.Nullable String role) { + + this.role = role; + return this; + } + + /** + * Role to use when executing the statement. The value in this field is case-sensitive. + * @return role + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_ROLE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getRole() { + return role; + } + + + @JsonProperty(value = JSON_PROPERTY_ROLE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setRole(@javax.annotation.Nullable String role) { + this.role = role; + } + + public SubmitStatementRequest bindings(@javax.annotation.Nullable Object bindings) { + + this.bindings = bindings; + return this; + } + + /** + * Values of bind variables in the SQL statement. When executing the statement, Snowflake replaces placeholders ('?' and ':name') in the statement with these specified values. + * @return bindings + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_BINDINGS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Object getBindings() { + return bindings; + } + + + @JsonProperty(value = JSON_PROPERTY_BINDINGS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setBindings(@javax.annotation.Nullable Object bindings) { + this.bindings = bindings; + } + + public SubmitStatementRequest parameters(@javax.annotation.Nullable SubmitStatementRequestParameters parameters) { + + this.parameters = parameters; + return this; + } + + /** + * Get parameters + * @return parameters + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_PARAMETERS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public SubmitStatementRequestParameters getParameters() { + return parameters; + } + + + @JsonProperty(value = JSON_PROPERTY_PARAMETERS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setParameters(@javax.annotation.Nullable SubmitStatementRequestParameters parameters) { + this.parameters = parameters; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + SubmitStatementRequest submitStatementRequest = (SubmitStatementRequest) o; + return Objects.equals(this.statement, submitStatementRequest.statement) && + Objects.equals(this.timeout, submitStatementRequest.timeout) && + Objects.equals(this.database, submitStatementRequest.database) && + Objects.equals(this.schema, submitStatementRequest.schema) && + Objects.equals(this.warehouse, submitStatementRequest.warehouse) && + Objects.equals(this.role, submitStatementRequest.role) && + Objects.equals(this.bindings, submitStatementRequest.bindings) && + Objects.equals(this.parameters, submitStatementRequest.parameters); + } + + @Override + public int hashCode() { + return Objects.hash(statement, timeout, database, schema, warehouse, role, bindings, parameters); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class SubmitStatementRequest {\n"); + sb.append(" statement: ").append(toIndentedString(statement)).append("\n"); + sb.append(" timeout: ").append(toIndentedString(timeout)).append("\n"); + sb.append(" database: ").append(toIndentedString(database)).append("\n"); + sb.append(" schema: ").append(toIndentedString(schema)).append("\n"); + sb.append(" warehouse: ").append(toIndentedString(warehouse)).append("\n"); + sb.append(" role: ").append(toIndentedString(role)).append("\n"); + sb.append(" bindings: ").append(toIndentedString(bindings)).append("\n"); + sb.append(" parameters: ").append(toIndentedString(parameters)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/SubmitStatementRequestParameters.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/SubmitStatementRequestParameters.java new file mode 100644 index 00000000..ba347a8a --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/SubmitStatementRequestParameters.java @@ -0,0 +1,395 @@ +/* + * Snowflake SQL API + * The Snowflake SQL API is a REST API that you can use to access and update data in a Snowflake database. + * + * The version of the OpenAPI document: 2.0.0 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Arrays; +import java.util.Locale; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Session parameters that should be set before executing the statement. + */ +@JsonPropertyOrder({ + SubmitStatementRequestParameters.JSON_PROPERTY_TIMEZONE, + SubmitStatementRequestParameters.JSON_PROPERTY_QUERY_TAG, + SubmitStatementRequestParameters.JSON_PROPERTY_BINARY_OUTPUT_FORMAT, + SubmitStatementRequestParameters.JSON_PROPERTY_DATE_OUTPUT_FORMAT, + SubmitStatementRequestParameters.JSON_PROPERTY_TIME_OUTPUT_FORMAT, + SubmitStatementRequestParameters.JSON_PROPERTY_TIMESTAMP_OUTPUT_FORMAT, + SubmitStatementRequestParameters.JSON_PROPERTY_TIMESTAMP_LTZ_OUTPUT_FORMAT, + SubmitStatementRequestParameters.JSON_PROPERTY_TIMESTAMP_NTZ_OUTPUT_FORMAT, + SubmitStatementRequestParameters.JSON_PROPERTY_TIMESTAMP_TZ_OUTPUT_FORMAT, + SubmitStatementRequestParameters.JSON_PROPERTY_MULTI_STATEMENT_COUNT +}) +@JsonTypeName("SubmitStatement_request_parameters") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:41:35.116838100+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class SubmitStatementRequestParameters { + public static final String JSON_PROPERTY_TIMEZONE = "timezone"; + @javax.annotation.Nullable + private String timezone; + + public static final String JSON_PROPERTY_QUERY_TAG = "query_tag"; + @javax.annotation.Nullable + private String queryTag; + + public static final String JSON_PROPERTY_BINARY_OUTPUT_FORMAT = "binary_output_format"; + @javax.annotation.Nullable + private String binaryOutputFormat; + + public static final String JSON_PROPERTY_DATE_OUTPUT_FORMAT = "date_output_format"; + @javax.annotation.Nullable + private String dateOutputFormat; + + public static final String JSON_PROPERTY_TIME_OUTPUT_FORMAT = "time_output_format"; + @javax.annotation.Nullable + private String timeOutputFormat; + + public static final String JSON_PROPERTY_TIMESTAMP_OUTPUT_FORMAT = "timestamp_output_format"; + @javax.annotation.Nullable + private String timestampOutputFormat; + + public static final String JSON_PROPERTY_TIMESTAMP_LTZ_OUTPUT_FORMAT = "timestamp_ltz_output_format"; + @javax.annotation.Nullable + private String timestampLtzOutputFormat; + + public static final String JSON_PROPERTY_TIMESTAMP_NTZ_OUTPUT_FORMAT = "timestamp_ntz_output_format"; + @javax.annotation.Nullable + private String timestampNtzOutputFormat; + + public static final String JSON_PROPERTY_TIMESTAMP_TZ_OUTPUT_FORMAT = "timestamp_tz_output_format"; + @javax.annotation.Nullable + private String timestampTzOutputFormat; + + public static final String JSON_PROPERTY_MULTI_STATEMENT_COUNT = "multi_statement_count"; + @javax.annotation.Nullable + private Integer multiStatementCount = 1; + + public SubmitStatementRequestParameters() { + } + + public SubmitStatementRequestParameters timezone(@javax.annotation.Nullable String timezone) { + + this.timezone = timezone; + return this; + } + + /** + * Time zone to use when executing the statement. + * @return timezone + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_TIMEZONE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getTimezone() { + return timezone; + } + + + @JsonProperty(value = JSON_PROPERTY_TIMEZONE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setTimezone(@javax.annotation.Nullable String timezone) { + this.timezone = timezone; + } + + public SubmitStatementRequestParameters queryTag(@javax.annotation.Nullable String queryTag) { + + this.queryTag = queryTag; + return this; + } + + /** + * Query tag that you want to associate with the SQL statement. + * @return queryTag + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_QUERY_TAG, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getQueryTag() { + return queryTag; + } + + + @JsonProperty(value = JSON_PROPERTY_QUERY_TAG, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setQueryTag(@javax.annotation.Nullable String queryTag) { + this.queryTag = queryTag; + } + + public SubmitStatementRequestParameters binaryOutputFormat(@javax.annotation.Nullable String binaryOutputFormat) { + + this.binaryOutputFormat = binaryOutputFormat; + return this; + } + + /** + * Output format for binary values. + * @return binaryOutputFormat + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_BINARY_OUTPUT_FORMAT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getBinaryOutputFormat() { + return binaryOutputFormat; + } + + + @JsonProperty(value = JSON_PROPERTY_BINARY_OUTPUT_FORMAT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setBinaryOutputFormat(@javax.annotation.Nullable String binaryOutputFormat) { + this.binaryOutputFormat = binaryOutputFormat; + } + + public SubmitStatementRequestParameters dateOutputFormat(@javax.annotation.Nullable String dateOutputFormat) { + + this.dateOutputFormat = dateOutputFormat; + return this; + } + + /** + * Output format for DATE values. + * @return dateOutputFormat + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_DATE_OUTPUT_FORMAT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getDateOutputFormat() { + return dateOutputFormat; + } + + + @JsonProperty(value = JSON_PROPERTY_DATE_OUTPUT_FORMAT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setDateOutputFormat(@javax.annotation.Nullable String dateOutputFormat) { + this.dateOutputFormat = dateOutputFormat; + } + + public SubmitStatementRequestParameters timeOutputFormat(@javax.annotation.Nullable String timeOutputFormat) { + + this.timeOutputFormat = timeOutputFormat; + return this; + } + + /** + * Output format for TIME values. + * @return timeOutputFormat + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_TIME_OUTPUT_FORMAT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getTimeOutputFormat() { + return timeOutputFormat; + } + + + @JsonProperty(value = JSON_PROPERTY_TIME_OUTPUT_FORMAT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setTimeOutputFormat(@javax.annotation.Nullable String timeOutputFormat) { + this.timeOutputFormat = timeOutputFormat; + } + + public SubmitStatementRequestParameters timestampOutputFormat(@javax.annotation.Nullable String timestampOutputFormat) { + + this.timestampOutputFormat = timestampOutputFormat; + return this; + } + + /** + * Output format for TIMESTAMP values. + * @return timestampOutputFormat + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_TIMESTAMP_OUTPUT_FORMAT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getTimestampOutputFormat() { + return timestampOutputFormat; + } + + + @JsonProperty(value = JSON_PROPERTY_TIMESTAMP_OUTPUT_FORMAT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setTimestampOutputFormat(@javax.annotation.Nullable String timestampOutputFormat) { + this.timestampOutputFormat = timestampOutputFormat; + } + + public SubmitStatementRequestParameters timestampLtzOutputFormat(@javax.annotation.Nullable String timestampLtzOutputFormat) { + + this.timestampLtzOutputFormat = timestampLtzOutputFormat; + return this; + } + + /** + * Output format for TIMESTAMP_LTZ values. + * @return timestampLtzOutputFormat + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_TIMESTAMP_LTZ_OUTPUT_FORMAT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getTimestampLtzOutputFormat() { + return timestampLtzOutputFormat; + } + + + @JsonProperty(value = JSON_PROPERTY_TIMESTAMP_LTZ_OUTPUT_FORMAT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setTimestampLtzOutputFormat(@javax.annotation.Nullable String timestampLtzOutputFormat) { + this.timestampLtzOutputFormat = timestampLtzOutputFormat; + } + + public SubmitStatementRequestParameters timestampNtzOutputFormat(@javax.annotation.Nullable String timestampNtzOutputFormat) { + + this.timestampNtzOutputFormat = timestampNtzOutputFormat; + return this; + } + + /** + * Output format for TIMESTAMP_NTZ values. + * @return timestampNtzOutputFormat + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_TIMESTAMP_NTZ_OUTPUT_FORMAT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getTimestampNtzOutputFormat() { + return timestampNtzOutputFormat; + } + + + @JsonProperty(value = JSON_PROPERTY_TIMESTAMP_NTZ_OUTPUT_FORMAT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setTimestampNtzOutputFormat(@javax.annotation.Nullable String timestampNtzOutputFormat) { + this.timestampNtzOutputFormat = timestampNtzOutputFormat; + } + + public SubmitStatementRequestParameters timestampTzOutputFormat(@javax.annotation.Nullable String timestampTzOutputFormat) { + + this.timestampTzOutputFormat = timestampTzOutputFormat; + return this; + } + + /** + * Output format for TIMESTAMP_TZ values. + * @return timestampTzOutputFormat + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_TIMESTAMP_TZ_OUTPUT_FORMAT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getTimestampTzOutputFormat() { + return timestampTzOutputFormat; + } + + + @JsonProperty(value = JSON_PROPERTY_TIMESTAMP_TZ_OUTPUT_FORMAT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setTimestampTzOutputFormat(@javax.annotation.Nullable String timestampTzOutputFormat) { + this.timestampTzOutputFormat = timestampTzOutputFormat; + } + + public SubmitStatementRequestParameters multiStatementCount(@javax.annotation.Nullable Integer multiStatementCount) { + + this.multiStatementCount = multiStatementCount; + return this; + } + + /** + * Number of statements to execute when using multi-statement capability. 0 implies variable number of statements. Negative numbers are not allowed. + * @return multiStatementCount + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_MULTI_STATEMENT_COUNT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Integer getMultiStatementCount() { + return multiStatementCount; + } + + + @JsonProperty(value = JSON_PROPERTY_MULTI_STATEMENT_COUNT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setMultiStatementCount(@javax.annotation.Nullable Integer multiStatementCount) { + this.multiStatementCount = multiStatementCount; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + SubmitStatementRequestParameters submitStatementRequestParameters = (SubmitStatementRequestParameters) o; + return Objects.equals(this.timezone, submitStatementRequestParameters.timezone) && + Objects.equals(this.queryTag, submitStatementRequestParameters.queryTag) && + Objects.equals(this.binaryOutputFormat, submitStatementRequestParameters.binaryOutputFormat) && + Objects.equals(this.dateOutputFormat, submitStatementRequestParameters.dateOutputFormat) && + Objects.equals(this.timeOutputFormat, submitStatementRequestParameters.timeOutputFormat) && + Objects.equals(this.timestampOutputFormat, submitStatementRequestParameters.timestampOutputFormat) && + Objects.equals(this.timestampLtzOutputFormat, submitStatementRequestParameters.timestampLtzOutputFormat) && + Objects.equals(this.timestampNtzOutputFormat, submitStatementRequestParameters.timestampNtzOutputFormat) && + Objects.equals(this.timestampTzOutputFormat, submitStatementRequestParameters.timestampTzOutputFormat) && + Objects.equals(this.multiStatementCount, submitStatementRequestParameters.multiStatementCount); + } + + @Override + public int hashCode() { + return Objects.hash(timezone, queryTag, binaryOutputFormat, dateOutputFormat, timeOutputFormat, timestampOutputFormat, timestampLtzOutputFormat, timestampNtzOutputFormat, timestampTzOutputFormat, multiStatementCount); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class SubmitStatementRequestParameters {\n"); + sb.append(" timezone: ").append(toIndentedString(timezone)).append("\n"); + sb.append(" queryTag: ").append(toIndentedString(queryTag)).append("\n"); + sb.append(" binaryOutputFormat: ").append(toIndentedString(binaryOutputFormat)).append("\n"); + sb.append(" dateOutputFormat: ").append(toIndentedString(dateOutputFormat)).append("\n"); + sb.append(" timeOutputFormat: ").append(toIndentedString(timeOutputFormat)).append("\n"); + sb.append(" timestampOutputFormat: ").append(toIndentedString(timestampOutputFormat)).append("\n"); + sb.append(" timestampLtzOutputFormat: ").append(toIndentedString(timestampLtzOutputFormat)).append("\n"); + sb.append(" timestampNtzOutputFormat: ").append(toIndentedString(timestampNtzOutputFormat)).append("\n"); + sb.append(" timestampTzOutputFormat: ").append(toIndentedString(timestampTzOutputFormat)).append("\n"); + sb.append(" multiStatementCount: ").append(toIndentedString(multiStatementCount)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/SuccessAcceptedResponse.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/SuccessAcceptedResponse.java new file mode 100644 index 00000000..b797d873 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/SuccessAcceptedResponse.java @@ -0,0 +1,170 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Arrays; +import java.util.Locale; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Schema for a request in progress response returned by the server. + */ +@JsonPropertyOrder({ + SuccessAcceptedResponse.JSON_PROPERTY_CODE, + SuccessAcceptedResponse.JSON_PROPERTY_MESSAGE, + SuccessAcceptedResponse.JSON_PROPERTY_RESULT_HANDLER +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:42:29.597406700+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class SuccessAcceptedResponse { + public static final String JSON_PROPERTY_CODE = "code"; + @javax.annotation.Nullable + private String code; + + public static final String JSON_PROPERTY_MESSAGE = "message"; + @javax.annotation.Nullable + private String message; + + public static final String JSON_PROPERTY_RESULT_HANDLER = "resultHandler"; + @javax.annotation.Nullable + private String resultHandler; + + public SuccessAcceptedResponse() { + } + + public SuccessAcceptedResponse code(@javax.annotation.Nullable String code) { + + this.code = code; + return this; + } + + /** + * Message code returned by the server. + * @return code + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_CODE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getCode() { + return code; + } + + + @JsonProperty(value = JSON_PROPERTY_CODE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setCode(@javax.annotation.Nullable String code) { + this.code = code; + } + + public SuccessAcceptedResponse message(@javax.annotation.Nullable String message) { + + this.message = message; + return this; + } + + /** + * Message returned by the server + * @return message + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_MESSAGE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getMessage() { + return message; + } + + + @JsonProperty(value = JSON_PROPERTY_MESSAGE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setMessage(@javax.annotation.Nullable String message) { + this.message = message; + } + + public SuccessAcceptedResponse resultHandler(@javax.annotation.Nullable String resultHandler) { + + this.resultHandler = resultHandler; + return this; + } + + /** + * Opaque result ID used for checking for request completion through one or more subsequent completion check operations. + * @return resultHandler + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_RESULT_HANDLER, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getResultHandler() { + return resultHandler; + } + + + @JsonProperty(value = JSON_PROPERTY_RESULT_HANDLER, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setResultHandler(@javax.annotation.Nullable String resultHandler) { + this.resultHandler = resultHandler; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + SuccessAcceptedResponse successAcceptedResponse = (SuccessAcceptedResponse) o; + return Objects.equals(this.code, successAcceptedResponse.code) && + Objects.equals(this.message, successAcceptedResponse.message) && + Objects.equals(this.resultHandler, successAcceptedResponse.resultHandler); + } + + @Override + public int hashCode() { + return Objects.hash(code, message, resultHandler); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class SuccessAcceptedResponse {\n"); + sb.append(" code: ").append(toIndentedString(code)).append("\n"); + sb.append(" message: ").append(toIndentedString(message)).append("\n"); + sb.append(" resultHandler: ").append(toIndentedString(resultHandler)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/SuccessResponse.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/SuccessResponse.java new file mode 100644 index 00000000..02bc3fbd --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/SuccessResponse.java @@ -0,0 +1,106 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Arrays; +import java.util.Locale; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Schema for all the success responses returned by the server. + */ +@JsonPropertyOrder({ + SuccessResponse.JSON_PROPERTY_STATUS +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-03-02T16:42:29.597406700+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class SuccessResponse { + public static final String JSON_PROPERTY_STATUS = "status"; + @javax.annotation.Nullable + private String status; + + public SuccessResponse() { + } + + public SuccessResponse status(@javax.annotation.Nullable String status) { + + this.status = status; + return this; + } + + /** + * Message returned by the server. + * @return status + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_STATUS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getStatus() { + return status; + } + + + @JsonProperty(value = JSON_PROPERTY_STATUS, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setStatus(@javax.annotation.Nullable String status) { + this.status = status; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + SuccessResponse successResponse = (SuccessResponse) o; + return Objects.equals(this.status, successResponse.status); + } + + @Override + public int hashCode() { + return Objects.hash(status); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class SuccessResponse {\n"); + sb.append(" status: ").append(toIndentedString(status)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/test/java/eu/openanalytics/containerproxy/test/auth/SpcsAuthenticationTest.java b/src/test/java/eu/openanalytics/containerproxy/test/auth/SpcsAuthenticationTest.java new file mode 100644 index 00000000..85ca2eb6 --- /dev/null +++ b/src/test/java/eu/openanalytics/containerproxy/test/auth/SpcsAuthenticationTest.java @@ -0,0 +1,170 @@ +/* + * ContainerProxy + * + * Copyright (C) 2016-2025 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.test.auth; + +import eu.openanalytics.containerproxy.test.helpers.ShinyProxyInstance; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.time.Duration; + +public class SpcsAuthenticationTest { + + private static final String SNOWFLAKE_SERVICE_NAME_ENV = "SNOWFLAKE_SERVICE_NAME"; + private String originalServiceName; + + @BeforeEach + public void setUp() { + // Save original value and set SNOWFLAKE_SERVICE_NAME for SPCS authentication + // Spring Environment can read from system properties or environment variables + originalServiceName = System.getProperty(SNOWFLAKE_SERVICE_NAME_ENV); + if (originalServiceName == null) { + originalServiceName = System.getenv(SNOWFLAKE_SERVICE_NAME_ENV); + } + System.setProperty(SNOWFLAKE_SERVICE_NAME_ENV, "TEST_SERVICE"); + } + + @AfterEach + public void tearDown() { + // Restore original value + if (originalServiceName != null) { + System.setProperty(SNOWFLAKE_SERVICE_NAME_ENV, originalServiceName); + } else { + System.clearProperty(SNOWFLAKE_SERVICE_NAME_ENV); + } + } + + // curl -v http://localhost:7583/api/proxy -H "Sf-Context-Current-User: TEST_USER_123" + // should return 200 + @Test + public void authenticateUserWithHeader() throws Exception { + try (ShinyProxyInstance inst = new ShinyProxyInstance("application-test-spcs-auth.yml")) { + String baseUrl = "http://localhost:7583"; + String testUsername = "TEST_USER_123"; + + OkHttpClient client = new OkHttpClient.Builder() + .callTimeout(Duration.ofSeconds(120)) + .readTimeout(Duration.ofSeconds(120)) + .followRedirects(false) + .build(); + + Request request = new Request.Builder() + .url(baseUrl + "/api/proxy") + .header("Sf-Context-Current-User", testUsername) + .build(); + + try (Response response = client.newCall(request).execute()) { + // Should authenticate successfully and return 200 (or appropriate success code) + Assertions.assertEquals(200, response.code()); + Assertions.assertFalse(response.isRedirect()); + } + } + } + + // curl -v http://localhost:7583/api/proxy -H "Sf-Context-Current-User: TEST_USER_123" -H "Sf-Context-Current-User-Token: TEST_TOKEN_123" + // should return 200 + @Test + public void authenticateUserWithHeaderAndToken() throws Exception { + try (ShinyProxyInstance inst = new ShinyProxyInstance("application-test-spcs-auth.yml")) { + String baseUrl = "http://localhost:7583"; + String testUsername = "TEST_USER_456"; + String testToken = "TEST_TOKEN_123"; + + OkHttpClient client = new OkHttpClient.Builder() + .callTimeout(Duration.ofSeconds(120)) + .readTimeout(Duration.ofSeconds(120)) + .followRedirects(false) + .build(); + + Request request = new Request.Builder() + .url(baseUrl + "/api/proxy") + .header("Sf-Context-Current-User", testUsername) + .header("Sf-Context-Current-User-Token", testToken) + .build(); + + try (Response response = client.newCall(request).execute()) { + // Should authenticate successfully with both headers + Assertions.assertEquals(200, response.code()); + Assertions.assertFalse(response.isRedirect()); + } + } + } + + // curl -v http://localhost:7583/api/proxy + // should return 401 + @Test + public void authenticationFailsWithoutHeader() throws Exception { + try (ShinyProxyInstance inst = new ShinyProxyInstance("application-test-spcs-auth.yml")) { + String baseUrl = "http://localhost:7583"; + + OkHttpClient client = new OkHttpClient.Builder() + .callTimeout(Duration.ofSeconds(120)) + .readTimeout(Duration.ofSeconds(120)) + .followRedirects(false) + .build(); + + Request request = new Request.Builder() + .url(baseUrl + "/api/proxy") + // No Sf-Context-Current-User header + .build(); + + try (Response response = client.newCall(request).execute()) { + // Should fail authentication - filter returns 401 UNAUTHORIZED + Assertions.assertEquals(401, response.code()); + String responseBody = response.body() != null ? response.body().string() : ""; + Assertions.assertTrue(responseBody.contains("SPCS authentication failed")); + } + } + } + + // curl -v http://localhost:7583/api/proxy -H "Sf-Context-Current-User: " + // should return 401 + @Test + public void authenticationFailsWithEmptyHeader() throws Exception { + try (ShinyProxyInstance inst = new ShinyProxyInstance("application-test-spcs-auth.yml")) { + String baseUrl = "http://localhost:7583"; + + OkHttpClient client = new OkHttpClient.Builder() + .callTimeout(Duration.ofSeconds(120)) + .readTimeout(Duration.ofSeconds(120)) + .followRedirects(false) + .build(); + + Request request = new Request.Builder() + .url(baseUrl + "/api/proxy") + .header("Sf-Context-Current-User", "") // Empty header + .build(); + + try (Response response = client.newCall(request).execute()) { + // Should fail authentication - empty header is treated as missing + Assertions.assertEquals(401, response.code()); + String responseBody = response.body() != null ? response.body().string() : ""; + Assertions.assertTrue(responseBody.contains("SPCS authentication failed")); + } + } + } +} + diff --git a/src/test/java/eu/openanalytics/containerproxy/test/helpers/ContainerSetup.java b/src/test/java/eu/openanalytics/containerproxy/test/helpers/ContainerSetup.java index b1f032f2..ca4be836 100644 --- a/src/test/java/eu/openanalytics/containerproxy/test/helpers/ContainerSetup.java +++ b/src/test/java/eu/openanalytics/containerproxy/test/helpers/ContainerSetup.java @@ -123,6 +123,10 @@ public boolean checkDockerIsClean() { List pods2 = client.pods().inNamespace(overriddenNamespace).list().getItems(); return new Retrying.Result(pods1.isEmpty() && pods2.isEmpty()); } + case "ecs", "spcs" -> { + // Cloud services don't need local cleanup check + return Retrying.SUCCESS; + } } return Retrying.SUCCESS; } catch (DockerException | InterruptedException | DockerCertificateException e) { diff --git a/src/test/java/eu/openanalytics/containerproxy/test/proxy/TestIntegrationOnSpcs.java b/src/test/java/eu/openanalytics/containerproxy/test/proxy/TestIntegrationOnSpcs.java new file mode 100644 index 00000000..c256a3d9 --- /dev/null +++ b/src/test/java/eu/openanalytics/containerproxy/test/proxy/TestIntegrationOnSpcs.java @@ -0,0 +1,299 @@ +/* + * ContainerProxy + * + * Copyright (C) 2016-2025 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.test.proxy; + +import com.google.common.base.Throwables; +import eu.openanalytics.containerproxy.backend.spcs.client.ApiClient; +import eu.openanalytics.containerproxy.backend.spcs.client.ApiException; +import eu.openanalytics.containerproxy.backend.spcs.client.Configuration; +import eu.openanalytics.containerproxy.backend.spcs.client.auth.HttpBearerAuth; +import eu.openanalytics.containerproxy.backend.spcs.client.api.ServiceApi; +import eu.openanalytics.containerproxy.backend.spcs.client.model.Service; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceContainer; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceSpec; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceSpecInlineText; +import eu.openanalytics.containerproxy.model.runtime.Proxy; +import eu.openanalytics.containerproxy.model.runtime.runtimevalues.BackendContainerNameKey; +import eu.openanalytics.containerproxy.test.helpers.ContainerSetup; +import eu.openanalytics.containerproxy.test.helpers.ShinyProxyInstance; +import eu.openanalytics.containerproxy.test.helpers.TestHelperException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.Map; + +public class TestIntegrationOnSpcs { + + private final Logger logger = LoggerFactory.getLogger(getClass()); + private static ServiceApi serviceApi; + + private ServiceApi getServiceApi() { + if (serviceApi == null) { + String accountName = System.getenv("ITEST_SPCS_ACCOUNT_NAME"); + if (accountName == null || accountName.isEmpty()) { + throw new IllegalStateException("ITEST_SPCS_ACCOUNT_NAME environment variable not set"); + } + // Construct account URL from account name + String accountUrl = String.format("https://%s.snowflakecomputing.com", accountName); + + // For tests, use PAT (Programmatic Access Token) authentication + String authToken = System.getenv("ITEST_SPCS_PROGRAMMATIC_ACCESS_TOKEN"); + if (authToken == null || authToken.isEmpty()) { + throw new IllegalStateException("ITEST_SPCS_PROGRAMMATIC_ACCESS_TOKEN environment variable must be set"); + } + + ApiClient apiClient = Configuration.getDefaultApiClient(); + apiClient.setBasePath(accountUrl); + + HttpBearerAuth keyPairAuth = (HttpBearerAuth) apiClient.getAuthentication("KeyPair"); + keyPairAuth.setBearerToken(authToken); + + serviceApi = new ServiceApi(apiClient); + } + return serviceApi; + } + + @Test + public void launchProxy() { + Assumptions.assumeTrue(checkSnowflakeCredentials(), "Skipping SPCS tests"); + try (ContainerSetup containerSetup = new ContainerSetup("spcs")) { + try (ShinyProxyInstance inst = new ShinyProxyInstance("application-test-spcs.yml", Map.of(), true)) { + inst.enableCleanup(); + // launch a proxy on SPCS + String id = inst.client.startProxy("01_hello"); + Proxy proxy = inst.proxyService.getProxy(id); + inst.client.testProxyReachable(id); + + Service service = getService(proxy); + + // Verify service properties + Assertions.assertNotNull(service.getDnsName()); + Assertions.assertTrue(service.getDnsName().contains(".svc.spcs.internal")); + // Compare compute pool case-insensitively as Snowflake may return it in different case + String expectedComputePool = System.getenv("ITEST_SPCS_COMPUTE_POOL"); + String actualComputePool = service.getComputePool(); + Assertions.assertNotNull(actualComputePool, "Compute pool should not be null"); + Assertions.assertTrue(actualComputePool.equalsIgnoreCase(expectedComputePool), + () -> String.format("Compute pool mismatch: expected '%s' (case-insensitive), got '%s'", expectedComputePool, actualComputePool)); + Assertions.assertNotNull(service.getStatus()); + + // Verify service containers are running + List containers = getServiceContainers(proxy); + Assertions.assertFalse(containers.isEmpty()); + + ServiceContainer container = containers.get(0); + Assertions.assertNotNull(container.getStatus()); + Assertions.assertTrue( + container.getStatus().equals("RUNNING") || + container.getStatus().equals("UP") || + container.getStatus().equals("READY") + ); + + // Verify service spec contains expected configuration + Assertions.assertNotNull(service.getSpec()); + ServiceSpec spec = service.getSpec(); + + // Check spec_type to determine the actual type (API may return base ServiceSpec) + String specType = spec.getSpecType(); + Assertions.assertNotNull(specType, "Service spec type should not be null"); + + // The spec should be of type "from_inline" (ServiceSpecInlineText) + // Verify spec type matches expected value (accept both "from_inline" and class name) + Assertions.assertTrue("from_inline".equals(specType) || "ServiceSpecInlineText".equals(specType), + () -> String.format("Service spec type should be 'from_inline' or 'ServiceSpecInlineText', but got: %s", specType)); + + // If API properly deserialized as ServiceSpecInlineText, validate spec text content + if (spec instanceof ServiceSpecInlineText) { + ServiceSpecInlineText inlineSpec = (ServiceSpecInlineText) spec; + String specText = inlineSpec.getSpecText(); + Assertions.assertNotNull(specText, "Service spec text should not be null"); + Assertions.assertTrue(specText.contains("openanalytics/shinyproxy-integration-test-app"), + () -> String.format("Spec text should contain image name, but got: %s", specText.substring(0, Math.min(200, specText.length())))); + Assertions.assertTrue(specText.contains("SHINYPROXY_USERNAME"), + "Spec text should contain SHINYPROXY_USERNAME environment variable"); + Assertions.assertTrue(specText.contains("demo"), + "Spec text should contain demo user"); + } else { + // API returned base ServiceSpec (deserialization issue), but spec type is correct + // This is acceptable - the spec type is validated above + logger.debug("Service spec is base ServiceSpec type (not ServiceSpecInlineText), but spec_type is correct: {}", specType); + } + + inst.client.stopProxy(id); + + // Verify service is deleted or stopped + // Note: Service deletion may be asynchronous + containers = getServiceContainers(proxy); + // After stopping, containers should be stopped/suspended or service should be deleted + boolean allStopped = containers.isEmpty() || containers.stream().allMatch(c -> + c.getStatus() != null && ( + c.getStatus().equals("STOPPED") || + c.getStatus().equals("SUSPENDED") || + c.getStatus().equals("DELETED") + ) + ); + Assertions.assertTrue(allStopped, "Service containers should be stopped after proxy stop"); + } + } + } + + @Test + public void testInvalidConfig1() { + TestHelperException ex = Assertions.assertThrows(TestHelperException.class, () -> new ShinyProxyInstance("application-test-spcs-invalid-1.yml")); + Throwable rootCause = Throwables.getRootCause(ex); + Assertions.assertInstanceOf(IllegalStateException.class, rootCause); + Assertions.assertEquals("Error in configuration of SPCS backend: proxy.spcs.account-identifier not set", rootCause.getMessage()); + } + + @Test + public void testInvalidConfig2() { + TestHelperException ex = Assertions.assertThrows(TestHelperException.class, () -> new ShinyProxyInstance("application-test-spcs-invalid-2.yml")); + Throwable rootCause = Throwables.getRootCause(ex); + Assertions.assertInstanceOf(IllegalStateException.class, rootCause); + Assertions.assertEquals("Error in configuration of SPCS backend: one of the following must be set: proxy.spcs.private-rsa-key-path or proxy.spcs.programmatic-access-token", rootCause.getMessage()); + } + + @Test + public void testInvalidConfig3() { + TestHelperException ex = Assertions.assertThrows(TestHelperException.class, () -> new ShinyProxyInstance("application-test-spcs-invalid-3.yml")); + Throwable rootCause = Throwables.getRootCause(ex); + Assertions.assertInstanceOf(IllegalStateException.class, rootCause); + Assertions.assertEquals("Error in configuration of SPCS backend: proxy.spcs.database not set", rootCause.getMessage()); + } + + @Test + public void testInvalidConfig4() { + TestHelperException ex = Assertions.assertThrows(TestHelperException.class, () -> new ShinyProxyInstance("application-test-spcs-invalid-4.yml")); + Throwable rootCause = Throwables.getRootCause(ex); + Assertions.assertInstanceOf(IllegalStateException.class, rootCause); + Assertions.assertEquals("Error in configuration of SPCS backend: proxy.spcs.schema not set", rootCause.getMessage()); + } + + @Test + public void testInvalidConfig5() { + TestHelperException ex = Assertions.assertThrows(TestHelperException.class, () -> new ShinyProxyInstance("application-test-spcs-invalid-5.yml")); + Throwable rootCause = Throwables.getRootCause(ex); + Assertions.assertInstanceOf(IllegalStateException.class, rootCause); + Assertions.assertEquals("Error in configuration of SPCS backend: proxy.spcs.compute-pool not set", rootCause.getMessage()); + } + + @Test + public void testInvalidConfig6() { + TestHelperException ex = Assertions.assertThrows(TestHelperException.class, () -> new ShinyProxyInstance("application-test-spcs-invalid-6.yml")); + Throwable rootCause = Throwables.getRootCause(ex); + Assertions.assertInstanceOf(IllegalStateException.class, rootCause); + Assertions.assertTrue(rootCause.getMessage().contains("has no 'memory-request' configured"), rootCause.getMessage()); + Assertions.assertTrue(rootCause.getMessage().contains("required for running on Snowflake SPCS"), rootCause.getMessage()); + } + + @Test + public void testInvalidConfig7() { + TestHelperException ex = Assertions.assertThrows(TestHelperException.class, () -> new ShinyProxyInstance("application-test-spcs-invalid-7.yml")); + Throwable rootCause = Throwables.getRootCause(ex); + Assertions.assertInstanceOf(IllegalStateException.class, rootCause); + Assertions.assertTrue(rootCause.getMessage().contains("has no 'cpu-request' configured"), rootCause.getMessage()); + Assertions.assertTrue(rootCause.getMessage().contains("required for running on Snowflake SPCS"), rootCause.getMessage()); + } + + @Test + public void testInvalidConfig8() { + TestHelperException ex = Assertions.assertThrows(TestHelperException.class, () -> new ShinyProxyInstance("application-test-spcs-invalid-8.yml")); + Throwable rootCause = Throwables.getRootCause(ex); + Assertions.assertInstanceOf(IllegalStateException.class, rootCause); + Assertions.assertTrue(rootCause.getMessage().contains("has 'memory-limit' configured"), rootCause.getMessage()); + Assertions.assertTrue(rootCause.getMessage().contains("not supported by Snowflake SPCS"), rootCause.getMessage()); + } + + @Test + public void testInvalidConfig9() { + TestHelperException ex = Assertions.assertThrows(TestHelperException.class, () -> new ShinyProxyInstance("application-test-spcs-invalid-9.yml")); + Throwable rootCause = Throwables.getRootCause(ex); + Assertions.assertInstanceOf(IllegalStateException.class, rootCause); + Assertions.assertTrue(rootCause.getMessage().contains("has 'cpu-limit' configured"), rootCause.getMessage()); + Assertions.assertTrue(rootCause.getMessage().contains("not supported by Snowflake SPCS"), rootCause.getMessage()); + } + + @Test + public void testInvalidConfig10() { + TestHelperException ex = Assertions.assertThrows(TestHelperException.class, () -> new ShinyProxyInstance("application-test-spcs-invalid-10.yml")); + Throwable rootCause = Throwables.getRootCause(ex); + Assertions.assertInstanceOf(IllegalStateException.class, rootCause); + Assertions.assertTrue(rootCause.getMessage().contains("has 'privileged: true' configured"), rootCause.getMessage()); + Assertions.assertTrue(rootCause.getMessage().contains("not supported by Snowflake SPCS"), rootCause.getMessage()); + } + + private Service getService(Proxy proxy) { + String fullServiceName = proxy.getContainers().getFirst().getRuntimeValue(BackendContainerNameKey.inst); + String[] parts = fullServiceName.split("\\."); + Assertions.assertEquals(3, parts.length, "Service name should be in format database.schema.service"); + String serviceDb = parts[0]; + String serviceSchema = parts[1]; + String serviceName = parts[2]; + + try { + return getServiceApi().fetchService(serviceDb, serviceSchema, serviceName); + } catch (ApiException e) { + throw new TestHelperException("Error fetching service: " + fullServiceName, e); + } + } + + private List getServiceContainers(Proxy proxy) { + String fullServiceName = proxy.getContainers().getFirst().getRuntimeValue(BackendContainerNameKey.inst); + String[] parts = fullServiceName.split("\\."); + Assertions.assertEquals(3, parts.length, "Service name should be in format database.schema.service"); + String serviceDb = parts[0]; + String serviceSchema = parts[1]; + String serviceName = parts[2]; + + try { + return getServiceApi().listServiceContainers(serviceDb, serviceSchema, serviceName); + } catch (ApiException e) { + // Service might be deleted, return empty list + if (e.getCode() == 404) { + return List.of(); + } + throw new TestHelperException("Error listing service containers: " + fullServiceName, e); + } + } + + private boolean requireEnvVar(String name) { + if (System.getenv(name) == null) { + logger.info("Env var {} missing, skipping SPCS Tests", name); + return false; + } + return true; + } + + private boolean checkSnowflakeCredentials() { + return requireEnvVar("ITEST_SPCS_ACCOUNT_NAME") + && requireEnvVar("ITEST_SPCS_USERNAME") + && requireEnvVar("ITEST_SPCS_PROGRAMMATIC_ACCESS_TOKEN") + && requireEnvVar("ITEST_SPCS_DATABASE") + && requireEnvVar("ITEST_SPCS_SCHEMA") + && requireEnvVar("ITEST_SPCS_COMPUTE_POOL"); + } + +} + diff --git a/src/test/resources/application-test-spcs-auth.yml b/src/test/resources/application-test-spcs-auth.yml new file mode 100644 index 00000000..351d67ed --- /dev/null +++ b/src/test/resources/application-test-spcs-auth.yml @@ -0,0 +1,24 @@ +spring: + session: + store-type: none + data: + redis: + repositories: + enabled: false +proxy: + authentication: spcs + heartbeat-timeout: -1 + default-stop-proxy-on-logout: false + container-backend: spcs + spcs: + account-identifier: TEST_ACCOUNT + username: TEST_USER + programmatic-access-token: TEST_TOKEN + database: TEST_DB + schema: TEST_SCHEMA + compute-pool: TEST_POOL + specs: + - id: test_spec + container-specs: + - image: "test/image:latest" + diff --git a/src/test/resources/application-test-spcs.yml b/src/test/resources/application-test-spcs.yml new file mode 100644 index 00000000..c91bc8c1 --- /dev/null +++ b/src/test/resources/application-test-spcs.yml @@ -0,0 +1,38 @@ +spring: + session: + store-type: none + data: + redis: + repositories: + enabled: false +proxy: + authentication: simple + heartbeat-timeout: -1 + default-stop-proxy-on-logout: false + container-backend: spcs + spcs: + account-identifier: ${ITEST_SPCS_ACCOUNT_NAME} + username: ${ITEST_SPCS_USERNAME} + programmatic-access-token: ${ITEST_SPCS_PROGRAMMATIC_ACCESS_TOKEN} + database: ${ITEST_SPCS_DATABASE} + schema: ${ITEST_SPCS_SCHEMA} + compute-pool: ${ITEST_SPCS_COMPUTE_POOL} + users: + - name: demo + password: demo + - name: demo2 + password: demo2 + specs: + - id: 01_hello + container-specs: + - image: "/MYDB/images/shinyproxyimages/shinyproxy-integration-test-app:latest" + cmd: [ "R", "-e", "shinyproxy::run_01_hello()" ] + cpu-request: 1024 + memory-request: 2048 + port-mapping: + - name: default + port: 3838 + labels: + valid-label: myvalue + invalid-label: "$@$#$@" + invalid-label2: "value-is-too-looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"