Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions examples/schedule-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Example configuration for time-based cluster activation
# This file shows how to configure cluster schedules for the Trino Gateway

# Main configuration
server:
applicationConnectors:
- type: http
port: 8080
adminConnectors:
- type: http
port: 8081

# Database configuration
dataStore:
jdbcUrl: jdbc:h2:./gateway-ha/gateway-ha;DB_CLOSE_DELAY=-1;MODE=MYSQL
user: sa
password: ""
driverClass: org.h2.Driver

# Monitor configuration
monitor:
active: true
connectionTimeout: 10s
refreshInterval: 10s
backends: ["trino-1", "trino-2"]

# Backend configurations
backends:
- name: trino-1
proxyTo: http://localhost:8080
active: true
routingGroup: adhoc
externalUrl: http://localhost:8080
- name: trino-2
proxyTo: http://localhost:8081
active: true
routingGroup: adhoc
externalUrl: http://localhost:8081

# Schedule configuration for time-based activation
scheduleConfiguration:
enabled: true
checkInterval: 5m # Check every 5 minutes
schedules:
- clusterName: trino-1
cronExpression: "0 0 9-17 * * ?" # Active from 9 AM to 5 PM every day
activeDuringCron: true # Active when cron matches
- clusterName: trino-2
cronExpression: "0 0 17-9 * * ?" # Active from 5 PM to 9 AM every day
activeDuringCron: true # Active when cron matches

# Authentication configuration (example)
authentication:
type: none

# Authorization configuration (example)
authorization:
type: none
11 changes: 11 additions & 0 deletions gateway-ha/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@
<version>0.22.1</version>
</dependency>

<dependency>
<groupId>com.cronutils</groupId>
<artifactId>cron-utils</artifactId>
<version>9.2.1</version>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
Expand Down Expand Up @@ -201,6 +207,11 @@
<artifactId>jakarta.annotation-api</artifactId>
</dependency>

<dependency>
<groupId>jakarta.inject</groupId>
<artifactId>jakarta.inject-api</artifactId>
</dependency>

<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.trino.gateway.ha.config;

import com.google.inject.Inject;
import io.airlift.log.Logger;
import io.trino.gateway.ha.scheduler.ClusterScheduler;
import jakarta.annotation.Nullable;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;

public class ClusterSchedulerConfiguration
{
private static final Logger log = Logger.get(ClusterSchedulerConfiguration.class);

private final ClusterScheduler scheduler;

@Inject
public ClusterSchedulerConfiguration(@Nullable ClusterScheduler scheduler)
{
this.scheduler = scheduler;
}

@PostConstruct
public void start()
{
if (scheduler != null) {
scheduler.start();
}
}

@PreDestroy
public void stop()
{
if (scheduler != null) {
try {
scheduler.close();
}
catch (Exception e) {
log.error(e, "Exception occurred while shutting down ClusterScheduler");
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
*/
package io.trino.gateway.ha.config;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Streams;

Expand Down Expand Up @@ -40,6 +41,7 @@ public class HaGatewayConfiguration
private List<String> extraWhitelistPaths = new ArrayList<>();
private OAuth2GatewayCookieConfiguration oauth2GatewayCookieConfiguration = new OAuth2GatewayCookieConfiguration();
private GatewayCookieConfiguration gatewayCookieConfiguration = new GatewayCookieConfiguration();
private ScheduleConfiguration scheduleConfiguration = new ScheduleConfiguration();
private List<String> statementPaths = ImmutableList.of(V1_STATEMENT_PATH);
private boolean includeClusterHostInResponse;
private ProxyResponseConfiguration proxyResponseConfiguration = new ProxyResponseConfiguration();
Expand Down Expand Up @@ -191,6 +193,18 @@ public OAuth2GatewayCookieConfiguration getOauth2GatewayCookieConfiguration()
return oauth2GatewayCookieConfiguration;
}

@JsonProperty
public ScheduleConfiguration getScheduleConfiguration()
{
return scheduleConfiguration;
}

@JsonProperty
public void setScheduleConfiguration(ScheduleConfiguration scheduleConfiguration)
{
this.scheduleConfiguration = scheduleConfiguration;
}

public void setOauth2GatewayCookieConfiguration(OAuth2GatewayCookieConfiguration oauth2GatewayCookieConfiguration)
{
this.oauth2GatewayCookieConfiguration = oauth2GatewayCookieConfiguration;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.trino.gateway.ha.config;

import com.fasterxml.jackson.annotation.JsonProperty;
import io.airlift.units.Duration;

import java.util.ArrayList;
import java.util.List;

import static java.util.Objects.requireNonNull;

public class ScheduleConfiguration
{
private boolean enabled;
private Duration checkInterval = new Duration(5, java.util.concurrent.TimeUnit.MINUTES);
private String timezone = "GMT"; // Default to GMT if not specified
private List<ClusterSchedule> schedules = new ArrayList<>();

@JsonProperty
public boolean isEnabled()
{
return enabled;
}

@JsonProperty
public void setEnabled(boolean enabled)
{
this.enabled = enabled;
}

@JsonProperty
public Duration getCheckInterval()
{
return checkInterval;
}

@JsonProperty
public void setCheckInterval(Duration checkInterval)
{
this.checkInterval = requireNonNull(checkInterval, "checkInterval is null");
}

@JsonProperty
public String getTimezone()
{
return timezone;
}

@JsonProperty
public void setTimezone(String timezone)
{
this.timezone = requireNonNull(timezone, "timezone is null");
}

@JsonProperty
public List<ClusterSchedule> getSchedules()
{
return schedules;
}

@JsonProperty
public void setSchedules(List<ClusterSchedule> schedules)
{
this.schedules = schedules;
}

public static class ClusterSchedule
{
private String clusterName;
private String cronExpression;
private boolean activeDuringCron;

@JsonProperty
public String getClusterName()
{
return clusterName;
}

@JsonProperty
public void setClusterName(String clusterName)
{
this.clusterName = requireNonNull(clusterName, "clusterName is null");
}

@JsonProperty
public String getCronExpression()
{
return cronExpression;
}

@JsonProperty
public void setCronExpression(String cronExpression)
{
this.cronExpression = requireNonNull(cronExpression, "cronExpression is null");
}

@JsonProperty
public boolean isActiveDuringCron()
{
return activeDuringCron;
}

@JsonProperty
public void setActiveDuringCron(boolean activeDuringCron)
{
this.activeDuringCron = activeDuringCron;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.trino.gateway.ha.module;

import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import io.airlift.log.Logger;
import io.trino.gateway.ha.config.HaGatewayConfiguration;
import io.trino.gateway.ha.config.ScheduleConfiguration;
import io.trino.gateway.ha.router.GatewayBackendManager;
import io.trino.gateway.ha.scheduler.ClusterScheduler;
import jakarta.inject.Singleton;

import static java.util.Objects.requireNonNull;

public class ClusterSchedulerModule
extends AbstractModule
{
private static final Logger log = Logger.get(ClusterSchedulerModule.class);
private final HaGatewayConfiguration configuration;

// We require all modules to take HaGatewayConfiguration as the only parameter
public ClusterSchedulerModule(HaGatewayConfiguration configuration)
{
this.configuration = requireNonNull(configuration, "configuration is null");
}

@Override
public void configure()
{
// Configuration-based binding is handled in the provider methods
if (configuration.getScheduleConfiguration() != null
&& configuration.getScheduleConfiguration().isEnabled()) {
log.info("ClusterScheduler configuration is enabled");
}
else {
log.info("ClusterScheduler is disabled or not configured");
}
}

@Provides
@Singleton
public ScheduleConfiguration provideScheduleConfiguration()
{
return configuration.getScheduleConfiguration();
}

@Provides
@Singleton
public ClusterScheduler provideClusterScheduler(
GatewayBackendManager backendManager,
ScheduleConfiguration scheduleConfiguration)
{
if (scheduleConfiguration == null || !scheduleConfiguration.isEnabled()) {
return null;
}
log.info("Creating ClusterScheduler instance");
return new ClusterScheduler(backendManager, scheduleConfiguration);
}
}
Loading