Skip to content

Commit

Permalink
feat: handle subscriptions and apikeys in local sync
Browse files Browse the repository at this point in the history
  • Loading branch information
phiz71 committed Jan 6, 2025
1 parent 491c002 commit a1be60c
Show file tree
Hide file tree
Showing 6 changed files with 352 additions and 122 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright © 2015 The Gravitee team (http://gravitee.io)
*
* 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.gravitee.gateway.services.sync.process.local.mapper;

import io.gravitee.gateway.api.service.ApiKey;
import io.gravitee.gateway.api.service.Subscription;
import java.util.Set;

public class ApiKeyMapper {

public ApiKey to(io.gravitee.repository.management.model.ApiKey apiKeyModel, Set<Subscription> subscriptions) {
ApiKey.ApiKeyBuilder apiKeyBuilder = ApiKey
.builder()
.id(apiKeyModel.getId())
.key(apiKeyModel.getKey())
.application(apiKeyModel.getApplication())
.expireAt(apiKeyModel.getExpireAt())
.revoked(apiKeyModel.isRevoked())
.paused(apiKeyModel.isPaused())
.active(false);

if (subscriptions != null) {
subscriptions
.stream()
.filter(subscription -> apiKeyModel.getSubscriptions().contains(subscription.getId()))
.findFirst()
.ifPresent(apiKeySubscription ->
apiKeyBuilder
.api(apiKeySubscription.getApi())
.plan(apiKeySubscription.getPlan())
.subscription(apiKeySubscription.getId())
.active(
!apiKeyModel.isPaused() &&
!apiKeyModel.isRevoked() &&
io.gravitee.repository.management.model.Subscription.Status.ACCEPTED
.name()
.equals(apiKeySubscription.getStatus())
)
);
}
return apiKeyBuilder.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright © 2015 The Gravitee team (http://gravitee.io)
*
* 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.gravitee.gateway.services.sync.process.local.mapper;

import static io.gravitee.repository.management.model.Event.EventProperties.API_ID;
import static io.gravitee.repository.management.model.Event.EventProperties.DEPLOYMENT_NUMBER;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.gravitee.definition.model.DefinitionVersion;
import io.gravitee.definition.model.v4.ApiType;
import io.gravitee.definition.model.v4.nativeapi.NativeApi;
import io.gravitee.gateway.reactor.ReactableApi;
import io.gravitee.gateway.services.sync.process.repository.service.EnvironmentService;
import io.gravitee.repository.management.model.Event;
import io.gravitee.repository.management.model.LifecycleState;
import io.reactivex.rxjava3.core.Maybe;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@RequiredArgsConstructor
@Slf4j
public class ApiMapper {

private final ObjectMapper objectMapper;
private final EnvironmentService environmentService;

public ReactableApi<?> to(Event apiEvent) {
try {
// Read API definition from event
var api = objectMapper.readValue(apiEvent.getPayload(), io.gravitee.repository.management.model.Api.class);

ReactableApi<?> reactableApi;

// Check the version of the API definition to read the right model entity
if (DefinitionVersion.V4 != api.getDefinitionVersion()) {
var eventApiDefinition = objectMapper.readValue(api.getDefinition(), io.gravitee.definition.model.Api.class);

// Update definition with required information for deployment phase
reactableApi = new io.gravitee.gateway.handlers.api.definition.Api(eventApiDefinition);
} else {
if (api.getType() == ApiType.NATIVE) {
var eventApiDefinition = objectMapper.readValue(api.getDefinition(), NativeApi.class);

// Update definition with required information for deployment phase
reactableApi = new io.gravitee.gateway.reactive.handlers.api.v4.NativeApi(eventApiDefinition);
} else if (api.getType() == ApiType.PROXY || api.getType() == ApiType.MESSAGE) {
var eventApiDefinition = objectMapper.readValue(api.getDefinition(), io.gravitee.definition.model.v4.Api.class);

// Update definition with required information for deployment phase
reactableApi = new io.gravitee.gateway.reactive.handlers.api.v4.Api(eventApiDefinition);
} else {
throw new IllegalArgumentException("Unsupported ApiType [" + api.getType() + "] for api: " + api.getId());
}
}

reactableApi.setEnabled(api.getLifecycleState() == LifecycleState.STARTED);
reactableApi.setDeployedAt(apiEvent.getCreatedAt());
reactableApi.setRevision(
Optional.ofNullable(apiEvent.getProperties()).map(props -> props.get(DEPLOYMENT_NUMBER.getValue())).orElse(null)
);

environmentService.fill(api.getEnvironmentId(), reactableApi);

return reactableApi;
} catch (Exception e) {
// Log the error and ignore this event.
log.error("Unable to extract api definition from event [{}].", apiEvent.getId(), e);
return null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright © 2015 The Gravitee team (http://gravitee.io)
*
* 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.gravitee.gateway.services.sync.process.local.mapper;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.gravitee.gateway.api.service.Subscription;
import io.gravitee.gateway.api.service.SubscriptionConfiguration;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@RequiredArgsConstructor
@Slf4j
public class SubscriptionMapper {

private final ObjectMapper objectMapper;

public Subscription to(io.gravitee.repository.management.model.Subscription subscriptionModel) {
try {
Subscription subscription = new Subscription();
subscription.setApi(subscriptionModel.getApi());
subscription.setApplication(subscriptionModel.getApplication());
subscription.setClientId(subscriptionModel.getClientId());
subscription.setClientCertificate(subscriptionModel.getClientCertificate());
subscription.setStartingAt(subscriptionModel.getStartingAt());
subscription.setEndingAt(subscriptionModel.getEndingAt());
subscription.setId(subscriptionModel.getId());
subscription.setPlan(subscriptionModel.getPlan());
if (subscriptionModel.getStatus() != null) {
subscription.setStatus(subscriptionModel.getStatus().name());
}
if (subscriptionModel.getConsumerStatus() != null) {
subscription.setConsumerStatus(Subscription.ConsumerStatus.valueOf(subscriptionModel.getConsumerStatus().name()));
}
if (subscriptionModel.getType() != null) {
subscription.setType(Subscription.Type.valueOf(subscriptionModel.getType().name().toUpperCase()));
}
if (subscriptionModel.getConfiguration() != null) {
subscription.setConfiguration(
objectMapper.readValue(subscriptionModel.getConfiguration(), SubscriptionConfiguration.class)
);
}
subscription.setMetadata(subscriptionModel.getMetadata());
subscription.setEnvironmentId(subscriptionModel.getEnvironmentId());
return subscription;
} catch (Exception e) {
log.error("Unable to map subscription from model [{}].", subscriptionModel.getId(), e);
return null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright © 2015 The Gravitee team (http://gravitee.io)
*
* 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.gravitee.gateway.services.sync.process.local.model;

import com.fasterxml.jackson.annotation.JsonProperty;
import io.gravitee.repository.management.model.ApiKey;
import io.gravitee.repository.management.model.Event;
import io.gravitee.repository.management.model.Subscription;
import java.util.List;
import lombok.Data;

@Data
public class LocalSyncFileDefinition {

@JsonProperty("apiEvent")
Event repositoryApiEvent;

@JsonProperty("subscriptions")
List<Subscription> repositorySubscriptionList;

@JsonProperty("apiKeys")
List<ApiKey> repositoryApiKeyList;
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,17 @@
import static io.gravitee.gateway.services.sync.SyncConfiguration.newThreadFactory;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.gravitee.gateway.api.service.ApiKeyService;
import io.gravitee.gateway.api.service.SubscriptionService;
import io.gravitee.gateway.handlers.api.manager.ApiManager;
import io.gravitee.gateway.services.sync.process.common.deployer.DeployerFactory;
import io.gravitee.gateway.services.sync.process.distributed.service.DistributedSyncService;
import io.gravitee.gateway.services.sync.process.local.LocalSyncManager;
import io.gravitee.gateway.services.sync.process.local.LocalSynchronizer;
import io.gravitee.gateway.services.sync.process.local.mapper.ApiKeyMapper;
import io.gravitee.gateway.services.sync.process.local.mapper.ApiMapper;
import io.gravitee.gateway.services.sync.process.local.mapper.SubscriptionMapper;
import io.gravitee.gateway.services.sync.process.local.synchronizer.LocalApiSynchronizer;
import io.gravitee.gateway.services.sync.process.repository.mapper.ApiMapper;
import io.gravitee.gateway.services.sync.process.repository.service.EnvironmentService;
import io.gravitee.gateway.services.sync.process.repository.synchronizer.api.ApiKeyAppender;
import io.gravitee.gateway.services.sync.process.repository.synchronizer.api.PlanAppender;
import io.gravitee.gateway.services.sync.process.repository.synchronizer.api.SubscriptionAppender;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
Expand Down Expand Up @@ -67,30 +67,43 @@ public ThreadPoolExecutor syncLocalExecutor(@Value("${services.sync.local.thread
return threadPoolExecutor;
}

@Bean
public ApiMapper localApiMapper(ObjectMapper objectMapper, EnvironmentService environmentService) {
return new ApiMapper(objectMapper, environmentService);
}

@Bean
public SubscriptionMapper localSubscriptionMapper(ObjectMapper objectMapper) {
return new SubscriptionMapper(objectMapper);
}

@Bean
public ApiKeyMapper localApiKeyMapper() {
return new ApiKeyMapper();
}

@Bean
public LocalApiSynchronizer localApiSynchronizer(
ObjectMapper objectMapper,
EnvironmentService environmentService,
ApiKeyMapper apiKeyMapper,
ApiKeyService apiKeyService,
ApiManager apiManager,
ApiMapper apiMapper,
PlanAppender planAppender,
SubscriptionAppender subscriptionAppender,
ApiKeyAppender apiKeyAppender,
DeployerFactory deployerFactory,
@Qualifier("syncLocalExecutor") ThreadPoolExecutor syncLocalExecutor,
@Qualifier("syncDeployerExecutor") ThreadPoolExecutor syncDeployerExecutor
EnvironmentService environmentService,
ObjectMapper objectMapper,
SubscriptionMapper subscriptionMapper,
SubscriptionService subscriptionService,
@Qualifier("syncLocalExecutor") ThreadPoolExecutor syncLocalExecutor
) {
return new LocalApiSynchronizer(
objectMapper,
environmentService,
apiKeyMapper,
apiKeyService,
apiManager,
apiMapper,
planAppender,
subscriptionAppender,
apiKeyAppender,
deployerFactory,
syncLocalExecutor,
syncDeployerExecutor
environmentService,
objectMapper,
subscriptionMapper,
subscriptionService,
syncLocalExecutor
);
}

Expand Down
Loading

0 comments on commit a1be60c

Please sign in to comment.