All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.microcks.operator.AbstractMicrocksDependantReconciler Maven / Gradle / Ivy

The newest version!
/*
 * Copyright The Microcks Authors.
 *
 * 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.github.microcks.operator;

import io.github.microcks.client.ApiClient;
import io.github.microcks.operator.api.base.v1alpha1.Microcks;
import io.github.microcks.operator.api.model.Status;
import io.github.microcks.operator.api.model.StatusPreserving;

import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.api.model.KubernetesResourceList;
import io.fabric8.kubernetes.client.CustomResource;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.dsl.MixedOperation;
import io.fabric8.kubernetes.client.dsl.Resource;
import io.javaoperatorsdk.operator.api.reconciler.DeleteControl;
import io.javaoperatorsdk.operator.api.reconciler.UpdateControl;
import org.jboss.logging.Logger;

import java.time.Duration;
import java.util.Map;

/**
 * Abstract class that provides common methods for reconcilers that depend on a Microcks instance.
 * @param  The custom resource type for the reconciler implementation
 * @param  The spec type for the custom resource
 * @param  The status type for the custom resource - must implement StatusPreserving
 */
public class AbstractMicrocksDependantReconciler, S, T extends StatusPreserving> {

   /** Get a JBoss logging logger. */
   private final Logger logger = Logger.getLogger(getClass());

   protected static final String API_EXCEPTION_ERROR_LOG = "Message '%s' and response body '%s'";

   protected KubernetesClient client;
   protected KeycloakHelper keycloakHelper;

   /**
    * For a given custom resource, prepare the reconciliation by checking that the Microcks instance
    * is specified, exists and is ready in the current namespace.
    * @param customResource The custom resource to reconcile
    * @return Either an UpdateControl is something goes wrong or the target Microcks instance.
    */
   public UpdateControlOrMicrocks prepareReconciliationWithMicrocksInstance(R customResource) {
      // Check that microcks instance specification is there.
      Map annotations = customResource.getMetadata().getAnnotations();
      String microcksName = annotations.get(MicrocksOperatorConfig.INSTANCE_SELECTOR);
      if (microcksName == null) {
         logger.errorf("No Microcks instance specified for %s '%s'", customResource.getKind(), customResource.getMetadata().getName());
         customResource.getStatus().setStatus(Status.ERROR);
         customResource.getStatus().setMessage("No Microcks instance specified for APISource. Expected annotation 'microcks.io/instance'");
         return new UpdateControlOrMicrocks<>(UpdateControl.updateStatus(customResource), null);
      }

      MixedOperation, Resource> microcksClient = client.resources(Microcks.class);

      // Check that microcks instance is found in current namespace.
      Microcks microcks = microcksClient.inNamespace(customResource.getMetadata().getNamespace()).withName(microcksName).get();
      if (microcks == null) {
         logger.errorf("No Microcks instance found for %s '%s'", customResource.getKind(), customResource.getMetadata().getName());
         customResource.getStatus().setStatus(Status.ERROR);
         customResource.getStatus().setMessage("No Microcks instance found for " + customResource.getKind() + ". Annotation 'microcks.io/instance' doesn't refer an existing instance");
         return new UpdateControlOrMicrocks<>(UpdateControl.updateStatus(customResource), null);
      }

      // Check that microcks instance is in ready status.
      if (microcks.getStatus().getStatus() != Status.READY) {
         logger.errorf("Microcks instance '%s' is not yet ready for %s '%s'", microcksName, customResource.getKind(), customResource.getMetadata().getName());
         customResource.getStatus().setStatus(Status.ERROR);
         customResource.getStatus().setMessage("Microcks instance is not yet ready for " + customResource.getKind() + ". Current status is " + microcks.getStatus().getStatus());
         return new UpdateControlOrMicrocks<>(UpdateControl.updateStatus(customResource).rescheduleAfter(Duration.ofSeconds(5)), null);
      }

      return new UpdateControlOrMicrocks<>(null, microcks);
   }

   /**
    * For a given custom resource, prepare the cleanup by checking that the Microcks instance
    * is specified and exists in the current namespace.
    * @param customResource The custom resource to cleanup
    * @return Either a DeleteControl is something goes wrong or the target Microcks instance.
    */
   public DeleteControlOrMicrocks prepareCleanupWithMicrocksInstance(R customResource) {
      // Check that microcks instance specification is there.
      Map annotations = customResource.getMetadata().getAnnotations();
      String microcksName = annotations.get(MicrocksOperatorConfig.INSTANCE_SELECTOR);
      if (microcksName == null) {
         logger.errorf("No Microcks instance specified for %s '%s'", customResource.getKind(), customResource.getMetadata().getName());
         return new DeleteControlOrMicrocks(DeleteControl.defaultDelete(), null);
      }

      MixedOperation, Resource> microcksClient = client.resources(Microcks.class);

      // Check that microcks instance is found in current namespace.
      Microcks microcks = microcksClient.inNamespace(customResource.getMetadata().getNamespace()).withName(microcksName).get();
      if (microcks == null) {
         logger.errorf("No Microcks instance found for %s '%s'", customResource.getKind(), customResource.getMetadata().getName());
         return new DeleteControlOrMicrocks(DeleteControl.defaultDelete(), null);
      }

      return new DeleteControlOrMicrocks(null, microcks);

   }

   /**
    * Build an ApiClient for a given custom resource and Microcks instance.
    * @param customResource The custom resource to get an ApiClient for
    * @param microcks The target Microcks instance
    * @return Either an UpdateControl is something goes wrong or the ApiClient to interact with Microcks API.
    */
   public UpdateControlOrApiClient buildApiClient(R customResource, Microcks microcks) {
      // Retrieve an authentication token from associated Keycloak.
      String oauthToken;
      try {
         oauthToken = keycloakHelper.getOAuthToken(customResource.getMetadata(), microcks);
      } catch (UnsatisfiedRequirementException ure) {
         logger.errorf("Unsatisfied requirement for connecting to Keycloak: %s", ure.getMessage());
         return new UpdateControlOrApiClient<>(UpdateControl.updateStatus(customResource).rescheduleAfter(Duration.ofSeconds(120)), null);
      } catch (Exception e) {
         logger.errorf("Error while getting OAuth token for Keycloak server: %s", e.getMessage());
         return new UpdateControlOrApiClient<>(UpdateControl.updateStatus(customResource).rescheduleAfter(Duration.ofSeconds(10)), null);
      }

      // Build a needed ApiCLient to interact with Microcks API.
      ApiClient apiClient = new ApiClient();
      apiClient.updateBaseUri("http://" + microcks.getMetadata().getName() + "." + microcks.getMetadata().getNamespace() + ".svc.cluster.local:8080/api");
      apiClient.setRequestInterceptor(request -> request.header("Authorization", "Bearer " + oauthToken));

      return new UpdateControlOrApiClient<>(null, apiClient);
   }

   public record UpdateControlOrMicrocks(UpdateControl updateControl, Microcks microcks) {
   }

   public record DeleteControlOrMicrocks(DeleteControl deleteControl, Microcks microcks) {
   }

   public record UpdateControlOrApiClient(UpdateControl updateControl, ApiClient apiClient) {
   }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy