Search in sources :

Example 11 with SerializedEntandoResource

use of org.entando.kubernetes.controller.spi.client.SerializedEntandoResource in project entando-k8s-controller-coordinator by entando-k8s.

the class DefaultSimpleKubernetesClient method performStatusUpdate.

private SerializedEntandoResource performStatusUpdate(SerializedEntandoResource customResource, Consumer<SerializedEntandoResource> consumer, UnaryOperator<EventBuilder> eventPopulator) {
    final EventBuilder doneableEvent = new EventBuilder().withNewMetadata().withNamespace(customResource.getMetadata().getNamespace()).withName(customResource.getMetadata().getName() + "-" + NameUtils.randomNumeric(8)).withOwnerReferences(ResourceUtils.buildOwnerReference(customResource)).withLabels(ResourceUtils.labelsFromResource(customResource)).endMetadata().withCount(1).withFirstTimestamp(dateTimeFormatter.get().format(LocalDateTime.now())).withLastTimestamp(dateTimeFormatter.get().format(LocalDateTime.now())).withNewSource(NameUtils.controllerNameOf(customResource), null).withNewInvolvedObject().withKind(customResource.getKind()).withNamespace(customResource.getMetadata().getNamespace()).withName(customResource.getMetadata().getName()).withUid(customResource.getMetadata().getUid()).withResourceVersion(customResource.getMetadata().getResourceVersion()).withApiVersion(customResource.getApiVersion()).withFieldPath("status").endInvolvedObject();
    client.v1().events().inNamespace(customResource.getMetadata().getNamespace()).create(eventPopulator.apply(doneableEvent).build());
    return ioSafe(() -> {
        SerializedEntandoResource ser = customResource;
        CustomResourceDefinitionContext definition = Optional.ofNullable(ser.getDefinition()).orElse(resolveDefinitionContext(ser));
        ser.setDefinition(definition);
        RawCustomResourceOperationsImpl resource = client.customResource(definition).inNamespace(customResource.getMetadata().getNamespace()).withName(customResource.getMetadata().getName());
        final ObjectMapper objectMapper = new ObjectMapper();
        ser = objectMapper.readValue(objectMapper.writeValueAsString(resource.get()), SerializedEntandoResource.class);
        ser.setDefinition(definition);
        consumer.accept(ser);
        final Map<String, Object> map = resource.updateStatus(objectMapper.writeValueAsString(ser));
        return objectMapper.readValue(objectMapper.writeValueAsString(map), SerializedEntandoResource.class);
    });
}
Also used : CustomResourceDefinitionContext(io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext) RawCustomResourceOperationsImpl(io.fabric8.kubernetes.client.dsl.internal.RawCustomResourceOperationsImpl) EventBuilder(io.fabric8.kubernetes.api.model.EventBuilder) SerializedEntandoResource(org.entando.kubernetes.controller.spi.client.SerializedEntandoResource) ObjectMapper(com.fasterxml.jackson.databind.ObjectMapper)

Example 12 with SerializedEntandoResource

use of org.entando.kubernetes.controller.spi.client.SerializedEntandoResource in project entando-k8s-controller-coordinator by entando-k8s.

the class EntandoResourceObserver method processGenerationIncrement.

private boolean processGenerationIncrement(SerializedEntandoResource newResource) {
    OperatorProcessingInstruction instruction = CoordinatorUtils.resolveProcessingInstruction(newResource);
    if (instruction == OperatorProcessingInstruction.FORCE) {
        // Remove to avoid recursive updates
        final SerializedEntandoResource latestResource = operations.removeAnnotation(newResource, AnnotationNames.PROCESSING_INSTRUCTION.getName());
        markResourceVersionProcessed(latestResource);
        logResource(Level.FINE, "Processing of %s %s/%s has been forced using entando.org/processing-instruction.", latestResource);
        return true;
    } else if (instruction == OperatorProcessingInstruction.DEFER || instruction == OperatorProcessingInstruction.IGNORE) {
        logResource(Level.FINE, "Processing of %s %s/%s has been deferred or ignored using entando.org/processing-instruction.", newResource);
        return false;
    } else {
        final boolean needsObservation = newResource.getStatus().getObservedGeneration() == null || newResource.getMetadata().getGeneration() == null || newResource.getStatus().getObservedGeneration() < newResource.getMetadata().getGeneration();
        if (needsObservation) {
            logResource(Level.FINE, "%s %s/%s is processed after a metadata.generation increment.", newResource);
        } else {
            logResource(Level.FINE, "%s %s/%s was ignored because its metadata.generation is still the same as the status.observedGeneration.", newResource);
        }
        return needsObservation;
    }
}
Also used : SerializedEntandoResource(org.entando.kubernetes.controller.spi.client.SerializedEntandoResource)

Example 13 with SerializedEntandoResource

use of org.entando.kubernetes.controller.spi.client.SerializedEntandoResource in project entando-k8s-controller-coordinator by entando-k8s.

the class DefaultSimpleKubernetesClientTest method shouldUpdateStatusOfOpaqueCustomResource.

@Test
@Description("Should track phase updates on the status of opaque custom resources and in Kubernetes events")
void shouldUpdateStatusOfOpaqueCustomResource() throws IOException {
    ValueHolder<TestResource> testResource = new ValueHolder<>();
    step("Given I have created an instance of the CustomResourceDefinition TestResource", () -> {
        testResource.set(createTestResource(new TestResource().withNames(MY_APP_NAMESPACE_1, MY_APP).withSpec(new BasicDeploymentSpecBuilder().withReplicas(1).build())));
        attachResource("TestResource", testResource.get());
    });
    SerializedEntandoResource serializedEntandoResource = objectMapper.readValue(objectMapper.writeValueAsBytes(testResource.get()), SerializedEntandoResource.class);
    step("And it is represented in an opaque format using the SerializedEntandoResource class", () -> {
        serializedEntandoResource.setDefinition(CustomResourceDefinitionContext.fromCustomResourceType(TestResource.class));
        attachResource("Opaque Resource", serializedEntandoResource);
    });
    step("When I update its phase to 'successful'", () -> getMyClient().updatePhase(serializedEntandoResource, EntandoDeploymentPhase.SUCCESSFUL));
    step("Then the updated status reflects on the TestResource", () -> {
        final TestResource actual = getFabric8Client().customResources(TestResource.class).inNamespace(MY_APP_NAMESPACE_1).withName(MY_APP).get();
        assertThat(actual.getStatus().getPhase()).isEqualTo(EntandoDeploymentPhase.SUCCESSFUL);
        attachResource("TestResource", actual);
    });
    step("And a PHASE_CHANGE event has been issued to Kubernetes", () -> {
        final List<Event> events = getMyClient().listEventsFor(testResource.get());
        attachResources("Events", events);
        assertThat(events).allMatch(event -> event.getInvolvedObject().getName().equals(testResource.get().getMetadata().getName()));
        assertThat(events).anyMatch(event -> event.getAction().equals("PHASE_CHANGE"));
    });
}
Also used : SerializedEntandoResource(org.entando.kubernetes.controller.spi.client.SerializedEntandoResource) Event(io.fabric8.kubernetes.api.model.Event) TestResource(org.entando.kubernetes.fluentspi.TestResource) ValueHolder(org.entando.kubernetes.test.common.ValueHolder) BasicDeploymentSpecBuilder(org.entando.kubernetes.fluentspi.BasicDeploymentSpecBuilder) Description(io.qameta.allure.Description) Test(org.junit.jupiter.api.Test)

Example 14 with SerializedEntandoResource

use of org.entando.kubernetes.controller.spi.client.SerializedEntandoResource in project entando-k8s-controller-coordinator by entando-k8s.

the class LivenessTests method shouldCreateControllerPodPointingToResource.

@Test
@Description("Should create a  controller pod that points to the newly created resource")
void shouldCreateControllerPodPointingToResource() {
    System.setProperty(EntandoOperatorSpiConfigProperty.ENTANDO_CONTROLLER_POD_NAME.getJvmSystemProperty(), "my-pod");
    step("Given the Coordinator observes its own namespace", () -> {
        System.setProperty(EntandoOperatorConfigProperty.ENTANDO_NAMESPACES_TO_OBSERVE.getJvmSystemProperty(), clientDouble.getNamespace());
        coordinator.onStartup(new StartupEvent());
    });
    ValueHolder<SerializedEntandoResource> testResource = new ValueHolder<>();
    step("And I have created a new TestResource resource", () -> {
        final TestResource r = new TestResource().withNames(clientDouble.getNamespace(), "test-keycloak").withSpec(new BasicDeploymentSpecBuilder().withDbms(DbmsVendor.EMBEDDED).build());
        r.getMetadata().setGeneration(1L);
        testResource.set(clientDouble.createOrPatchEntandoResource(CoordinatorTestUtils.toSerializedResource(r)));
        attachment("TestResource", objectMapper.writeValueAsString(testResource.get()));
    });
    final File file = Paths.get("/tmp/EntandoControllerCoordinator.ready").toFile();
    clientDouble.getCluster().getResourceProcessor().getAllWatchers().forEach(watcher -> {
        Liveness.alive();
        step(format("When the watcher %s is closed", watcher.getClass().getSimpleName()), () -> {
            watcher.onClose(new WatcherException("Closed"));
        });
        step("Then the liveness probe will fail", () -> {
            assertThat(file).doesNotExist();
        });
    });
}
Also used : SerializedEntandoResource(org.entando.kubernetes.controller.spi.client.SerializedEntandoResource) StartupEvent(io.quarkus.runtime.StartupEvent) TestResource(org.entando.kubernetes.fluentspi.TestResource) ValueHolder(org.entando.kubernetes.test.common.ValueHolder) BasicDeploymentSpecBuilder(org.entando.kubernetes.fluentspi.BasicDeploymentSpecBuilder) File(java.io.File) WatcherException(io.fabric8.kubernetes.client.WatcherException) Description(io.qameta.allure.Description) Test(org.junit.jupiter.api.Test)

Example 15 with SerializedEntandoResource

use of org.entando.kubernetes.controller.spi.client.SerializedEntandoResource in project entando-k8s-controller-coordinator by entando-k8s.

the class ControllerCoordinatorProcessingCriteriaTest method testGenerationObservedIsCurrentButForceInstructed.

@Test
@Description("Resource modification events should be processed when using the annotation 'entando.org/processing-instruction=force' even " + "when the 'generation' property on the metadata of the resource is the same as the 'observedGeneration' property on" + " its status")
void testGenerationObservedIsCurrentButForceInstructed() {
    step("Given the Coordinator observes this namespace", () -> System.setProperty(EntandoOperatorConfigProperty.ENTANDO_NAMESPACES_TO_OBSERVE.getJvmSystemProperty(), OBSERVED_NAMESPACE));
    final ValueHolder<SerializedEntandoResource> testResource = new ValueHolder<>();
    step("And I have created an TestResource resource with the 'force' processing instruction", () -> {
        testResource.set(createTestResource(10L, Collections.singletonMap(AnnotationNames.PROCESSING_INSTRUCTION.getName(), "force")));
        attachment("TestResource", objectMapper.writeValueAsString(testResource.get()));
    });
    step("And the generation in the metadata is the same as the observedGeneration in the status", () -> {
        // NB This step assumes that the ClientDouble is holding this exact instance of the resource when the ControllerCoordinator
        // starts
        testResource.get().getStatus().updateDeploymentPhase(EntandoDeploymentPhase.STARTED, 10L);
        attachment("TestResource", objectMapper.writeValueAsString(testResource.get()));
    });
    step("When I start the ControllerCoordinator", () -> coordinator.onStartup(new StartupEvent()));
    step("Then a new pod gets created", () -> {
        coordinator.getObserver(CustomResourceDefinitionContext.fromCustomResourceType(TestResource.class)).shutDownAndWait(1, SECONDS);
        await().ignoreExceptions().atMost(3, TimeUnit.SECONDS).until(() -> {
            final Map<String, String> labels = labelsFromResource(testResource.get());
            return clientDouble.loadPod(CONTROLLER_NAMESPACE, labels) != null;
        });
    });
    step("And the 'force' processing instruction has been removed to avoid recursive processing", () -> {
        final SerializedEntandoResource latestKeycloakServer = clientDouble.load(TestResource.class, testResource.get().getMetadata().getNamespace(), testResource.get().getMetadata().getName());
        assertThat(CoordinatorUtils.resolveProcessingInstruction(latestKeycloakServer)).isEqualTo(OperatorProcessingInstruction.NONE);
        attachment("TestResource", objectMapper.writeValueAsString(testResource.get()));
    });
    step("And the forced event was logged", () -> {
        final Optional<String> logEntry = LogInterceptor.getLogEntries().stream().filter(s -> s.contains("has been forced")).findFirst();
        assertThat(logEntry).isPresent();
    });
}
Also used : BeforeEach(org.junit.jupiter.api.BeforeEach) Allure.attachment(io.qameta.allure.Allure.attachment) SerializedEntandoResource(org.entando.kubernetes.controller.spi.client.SerializedEntandoResource) DbmsVendor(org.entando.kubernetes.model.common.DbmsVendor) Assertions.assertThat(org.assertj.core.api.Assertions.assertThat) TimeoutException(java.util.concurrent.TimeoutException) Action(io.fabric8.kubernetes.client.Watcher.Action) ValueHolder(org.entando.kubernetes.test.common.ValueHolder) CustomResourceDefinitionContext(io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext) EntandoOperatorConfigProperty(org.entando.kubernetes.controller.support.common.EntandoOperatorConfigProperty) Feature(io.qameta.allure.Feature) LabelNames(org.entando.kubernetes.controller.spi.common.LabelNames) ExtendWith(org.junit.jupiter.api.extension.ExtendWith) LogInterceptor(org.entando.kubernetes.test.common.LogInterceptor) Map(java.util.Map) YAMLFactory(com.fasterxml.jackson.dataformat.yaml.YAMLFactory) ResourceUtils(org.entando.kubernetes.controller.spi.common.ResourceUtils) Tag(org.junit.jupiter.api.Tag) Issue(io.qameta.allure.Issue) CoordinatorTestUtils(org.entando.kubernetes.controller.coordinator.common.CoordinatorTestUtils) BasicDeploymentSpecBuilder(org.entando.kubernetes.fluentspi.BasicDeploymentSpecBuilder) ObjectMetaBuilder(io.fabric8.kubernetes.api.model.ObjectMetaBuilder) SimpleKubernetesClientDouble(org.entando.kubernetes.controller.coordinator.common.SimpleKubernetesClientDouble) CommonLabels(org.entando.kubernetes.test.common.CommonLabels) FluentIntegrationTesting(org.entando.kubernetes.controller.support.client.impl.integrationtesthelpers.FluentIntegrationTesting) MockitoExtension(org.mockito.junit.jupiter.MockitoExtension) ObjectMapper(com.fasterxml.jackson.databind.ObjectMapper) Pod(io.fabric8.kubernetes.api.model.Pod) JsonProcessingException(com.fasterxml.jackson.core.JsonProcessingException) IOException(java.io.IOException) CustomResourceDefinitionBuilder(io.fabric8.kubernetes.api.model.apiextensions.v1beta1.CustomResourceDefinitionBuilder) StandardCapability(org.entando.kubernetes.model.capability.StandardCapability) TestResource(org.entando.kubernetes.fluentspi.TestResource) TimeUnit(java.util.concurrent.TimeUnit) Test(org.junit.jupiter.api.Test) EntandoResourceClientDouble(org.entando.kubernetes.controller.support.client.doubles.EntandoResourceClientDouble) AfterEach(org.junit.jupiter.api.AfterEach) Allure.step(io.qameta.allure.Allure.step) ProvidedCapabilityBuilder(org.entando.kubernetes.model.capability.ProvidedCapabilityBuilder) Optional(java.util.Optional) Tags(org.junit.jupiter.api.Tags) RandomStringUtils(org.apache.commons.lang3.RandomStringUtils) StartupEvent(io.quarkus.runtime.StartupEvent) Description(io.qameta.allure.Description) Collections(java.util.Collections) CustomResourceDefinition(io.fabric8.kubernetes.api.model.apiextensions.v1beta1.CustomResourceDefinition) EntandoDeploymentPhase(org.entando.kubernetes.model.common.EntandoDeploymentPhase) SerializedEntandoResource(org.entando.kubernetes.controller.spi.client.SerializedEntandoResource) StartupEvent(io.quarkus.runtime.StartupEvent) ValueHolder(org.entando.kubernetes.test.common.ValueHolder) Description(io.qameta.allure.Description) Test(org.junit.jupiter.api.Test)

Aggregations

SerializedEntandoResource (org.entando.kubernetes.controller.spi.client.SerializedEntandoResource)25 Description (io.qameta.allure.Description)19 Test (org.junit.jupiter.api.Test)19 TestResource (org.entando.kubernetes.fluentspi.TestResource)15 StartupEvent (io.quarkus.runtime.StartupEvent)13 ObjectMapper (com.fasterxml.jackson.databind.ObjectMapper)12 ValueHolder (org.entando.kubernetes.test.common.ValueHolder)12 BasicDeploymentSpecBuilder (org.entando.kubernetes.fluentspi.BasicDeploymentSpecBuilder)10 YAMLFactory (com.fasterxml.jackson.dataformat.yaml.YAMLFactory)9 CustomResourceDefinition (io.fabric8.kubernetes.api.model.apiextensions.v1beta1.CustomResourceDefinition)9 CustomResourceDefinitionBuilder (io.fabric8.kubernetes.api.model.apiextensions.v1beta1.CustomResourceDefinitionBuilder)9 ObjectMetaBuilder (io.fabric8.kubernetes.api.model.ObjectMetaBuilder)8 IOException (java.io.IOException)7 Pod (io.fabric8.kubernetes.api.model.Pod)6 CustomResourceDefinitionContext (io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext)6 Allure.attachment (io.qameta.allure.Allure.attachment)6 Allure.step (io.qameta.allure.Allure.step)6 Feature (io.qameta.allure.Feature)6 Issue (io.qameta.allure.Issue)6 TimeUnit (java.util.concurrent.TimeUnit)6