Skip to content

Commit

Permalink
GH-5 Switch to josdk managed dependent resource
Browse files Browse the repository at this point in the history
  • Loading branch information
rameshmalla committed Dec 22, 2023
1 parent 5efa965 commit 7bd8107
Show file tree
Hide file tree
Showing 7 changed files with 305 additions and 58 deletions.
2 changes: 1 addition & 1 deletion install/cluster/Config-Operator.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ spec:
serviceAccountName: configs-operator
containers:
- name: operator
image: configs-operator:test_69
image: malla/configs-operator:latest
resources:
requests:
memory: 512Mi
Expand Down
39 changes: 38 additions & 1 deletion src/main/java/com/rcube/configmap/ConfigOperatorApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,24 @@
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.guava.GuavaModule;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.rcube.configmap.operator.config.SpringAwareBaseConfigService;
import com.rcube.configmap.operator.config.SpringAwareDependentResourceFactory;
import io.fabric8.kubernetes.client.utils.Serialization;
import io.javaoperatorsdk.operator.api.config.ConfigurationService;
import io.javaoperatorsdk.operator.api.config.ResourceClassResolver;
import io.javaoperatorsdk.operator.api.config.Utils;
import io.javaoperatorsdk.operator.api.monitoring.Metrics;
import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource;
import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResourceFactory;
import io.javaoperatorsdk.operator.monitoring.micrometer.MicrometerMetrics;
import io.javaoperatorsdk.operator.springboot.starter.OperatorConfigurationProperties;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;

import java.util.List;

@SpringBootApplication
public class ConfigOperatorApplication {
Expand All @@ -27,10 +39,35 @@ public class ConfigOperatorApplication {
}

@Bean
public MicrometerMetrics micrometerMetrics(final MeterRegistry meterRegistry){
public MicrometerMetrics micrometerMetrics(final MeterRegistry meterRegistry) {
return MicrometerMetrics.withoutPerResourceMetrics(meterRegistry);
}


@Bean
public DependentResourceFactory dependentResourceFactory(final List<DependentResource> dependentResources) {
return new SpringAwareDependentResourceFactory(dependentResources);
}

// Primary annotation is to ignore ConfigurationService auto configuration in
// io.javaoperatorsdk.operator.springboot.starter.OperatorAutoConfiguration
// and use SpringAwareBaseConfigService as the primary configuration service
@Bean
@Primary
public ConfigurationService customBaseConfigService(final ResourceClassResolver resourceClassResolver,
final Metrics metrics,
final OperatorConfigurationProperties configuration,
final DependentResourceFactory dependentResourceFactory) {
final SpringAwareBaseConfigService configService =
new SpringAwareBaseConfigService(Utils.loadFromProperties());
configService.setConcurrentReconciliationThreads(configuration.getConcurrentReconciliationThreads());
configService.setMetrics(metrics);
configService.setResourceClassResolver(resourceClassResolver);
configService.setCheckCRDAndValidateLocalModel(configuration.getCheckCrdAndValidateLocalModel());
configService.setDependentResourceFactory(dependentResourceFactory);
return configService;
}

public static void main(String[] args) {
SpringApplication.run(ConfigOperatorApplication.class, args);
}
Expand Down
71 changes: 15 additions & 56 deletions src/main/java/com/rcube/configmap/operator/ConfigMapController.java
Original file line number Diff line number Diff line change
@@ -1,33 +1,25 @@
package com.rcube.configmap.operator;

import com.rcube.configmap.validators.SpecValidator;
import com.rcube.configmap.operator.dependentresource.ConfigMapDependentResource;
import io.fabric8.kubernetes.api.model.ConfigMap;
import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration;
import io.javaoperatorsdk.operator.api.reconciler.Context;
import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext;
import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer;
import io.javaoperatorsdk.operator.api.reconciler.ErrorStatusHandler;
import io.javaoperatorsdk.operator.api.reconciler.ErrorStatusUpdateControl;
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
import io.javaoperatorsdk.operator.api.reconciler.UpdateControl;
import io.javaoperatorsdk.operator.processing.event.source.EventSource;
import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;
import java.util.Map;
import lombok.AllArgsConstructor;
import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.stereotype.Component;

@Slf4j
@Component
@AllArgsConstructor
@ControllerConfiguration
public class ConfigMapController implements Reconciler<ConfigMapCustomResource>, EventSourceInitializer<ConfigMapCustomResource> {

private final KubernetesClient kubernetesClient;

private final SpecValidator specValidator;
@ControllerConfiguration(dependents = {
@Dependent(type = ConfigMapDependentResource.class)
})
public class ConfigMapController implements Reconciler<ConfigMapCustomResource>,
ErrorStatusHandler<ConfigMapCustomResource> {

@Override
public UpdateControl<ConfigMapCustomResource> reconcile(final ConfigMapCustomResource resource, final Context<ConfigMapCustomResource> context) {
Expand All @@ -36,50 +28,17 @@ public UpdateControl<ConfigMapCustomResource> reconcile(final ConfigMapCustomRes
.map(map -> map.getMetadata().getName())
.orElse("None");
log.info("Context being reloaded for [{}]", reloadedResource);
specValidator.validateResourceContent(resource);
createConfigMap(resource);
resource.setStatus(ResourceStatus.builder().build());
resource.setStatus(ResourceStatus.builder().
build());
} catch (Exception ex) {
resource.setStatus(new ResourceStatus(ex.getMessage()));
}
return UpdateControl.updateResourceAndStatus(resource);
}

private void createConfigMap(final ConfigMapCustomResource resource) {
val configMapData = resource.getSpec().getConfig();
val configMap = buildConfigMap(resource);
configMap.setData(configMapData.getData());
configMap.setAdditionalProperties(configMap.getAdditionalProperties());
configMap.setBinaryData(configMapData.getBinaryData());
configMap.setImmutable(configMapData.getImmutable());
kubernetesClient.configMaps()
.inNamespace(resource.getMetadata().getNamespace())
.resource(configMap)
.createOrReplace();
}

private ConfigMap buildConfigMap(final ConfigMapCustomResource resource) {
return new ConfigMapBuilder().withNewMetadata()
.withName(resource.getMetadata().getName())
.withNamespace(resource.getMetadata().getNamespace())
.withLabels(resource.getMetadata().getLabels())
.addNewOwnerReference()
.withController(true)
.withKind(resource.getKind())
.withApiVersion(resource.getApiVersion())
.withName(resource.getMetadata().getName())
.withUid(resource.getMetadata().getUid())
.endOwnerReference()
.endMetadata()
.build();
}

@Override
public Map<String, EventSource> prepareEventSources(final EventSourceContext<ConfigMapCustomResource> context) {
final InformerConfiguration<ConfigMap> configuration =
InformerConfiguration.from(ConfigMap.class, context)
.build();
return EventSourceInitializer
.nameEventSources(new InformerEventSource<>(configuration, context));
public ErrorStatusUpdateControl<ConfigMapCustomResource> updateErrorStatus(final ConfigMapCustomResource resource, final Context<ConfigMapCustomResource> context, final Exception e) {
resource.setStatus(new ResourceStatus(e.getMessage()));
return ErrorStatusUpdateControl.updateStatus(resource);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.rcube.configmap.operator.config;

import io.javaoperatorsdk.operator.api.config.Version;
import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResourceFactory;
import io.javaoperatorsdk.operator.springboot.starter.OverridableBaseConfigService;

public class SpringAwareBaseConfigService extends OverridableBaseConfigService {

private DependentResourceFactory dependentResourceFactory = DependentResourceFactory.DEFAULT;

public SpringAwareBaseConfigService(final Version version) {
super(version);
}

public void setDependentResourceFactory(final DependentResourceFactory dependentResourceFactory) {
this.dependentResourceFactory = dependentResourceFactory;
}

@Override
public DependentResourceFactory dependentResourceFactory() {
return dependentResourceFactory;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.rcube.configmap.operator.config;

import io.javaoperatorsdk.operator.api.config.ControllerConfiguration;
import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceConfigurationResolver;
import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceSpec;
import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource;
import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResourceFactory;

import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

public class SpringAwareDependentResourceFactory implements DependentResourceFactory<ControllerConfiguration<?>> {

private final Map<String, DependentResource> dependentResourcesContainer;

public SpringAwareDependentResourceFactory(final List<DependentResource> dependentResources) {
this.dependentResourcesContainer = buildDependentResourcesContainer(dependentResources);
}

@Override
public DependentResource createFrom(final DependentResourceSpec spec, final ControllerConfiguration<?> configuration) {
final DependentResource dependentResourceFromSpringContext = dependentResourcesContainer.get(spec.getDependentResourceClass().getName());
if (dependentResourceFromSpringContext == null) {
return DependentResourceFactory.DEFAULT.createFrom(spec, configuration);
}
DependentResourceConfigurationResolver.configure(dependentResourceFromSpringContext, spec, configuration);
return dependentResourceFromSpringContext;
}

private Map<String, DependentResource> buildDependentResourcesContainer(List<DependentResource> dependentResources) {
return dependentResources.stream()
.collect(Collectors.toMap(dependentResource -> dependentResource.getClass().getName(), Function.identity()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.rcube.configmap.operator.dependentresource;

import com.rcube.configmap.operator.ConfigMapCustomResource;
import com.rcube.configmap.validators.SpecValidator;
import io.fabric8.kubernetes.api.model.ConfigMap;
import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
import io.javaoperatorsdk.operator.api.reconciler.Context;
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource;
import lombok.val;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class ConfigMapDependentResource extends CRUDKubernetesDependentResource<ConfigMap, ConfigMapCustomResource> {

@Autowired
private SpecValidator specValidator;

public ConfigMapDependentResource() {
super(ConfigMap.class);
}

@Override
protected ConfigMap desired(final ConfigMapCustomResource primary, final Context<ConfigMapCustomResource> context) {
specValidator.validateResourceContent(primary);
return createConfigMap(primary);
}

private ConfigMap createConfigMap(final ConfigMapCustomResource resource) {
val configMapData = resource.getSpec().getConfig();
val configMap = buildConfigMap(resource);
configMap.setData(configMapData.getData());
configMap.setAdditionalProperties(configMap.getAdditionalProperties());
configMap.setBinaryData(configMapData.getBinaryData());
configMap.setImmutable(configMapData.getImmutable());
return configMap;
}
private ConfigMap buildConfigMap(final ConfigMapCustomResource resource) {
return new ConfigMapBuilder()
.withNewMetadata()
.withName(resource.getMetadata().getName())
.withNamespace(resource.getMetadata().getNamespace())
.withLabels(resource.getMetadata().getLabels())
.addNewOwnerReference()
.withController(true)
.withKind(resource.getKind())
.withApiVersion(resource.getApiVersion())
.withName(resource.getMetadata().getName())
.withUid(resource.getMetadata().getUid())
.endOwnerReference()
.endMetadata()
.build();
}
}
Loading

0 comments on commit 7bd8107

Please sign in to comment.