Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix 1278 #1280

Merged
merged 36 commits into from
Mar 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
032014e
test
wind57 Dec 4, 2021
c3d0ad2
Merge branch 'main' of https://github.com/spring-cloud/spring-cloud-k…
wind57 Dec 13, 2021
10889fd
fix @Nested tests not running
wind57 Dec 16, 2021
8f0375a
merged main
wind57 Dec 17, 2021
96ebf42
Merge branch 'main' of https://github.com/spring-cloud/spring-cloud-k…
wind57 Jan 5, 2022
db8403e
Merge branch 'main' of https://github.com/spring-cloud/spring-cloud-k…
wind57 Jan 12, 2022
90a5345
Merge branch 'main' of https://github.com/spring-cloud/spring-cloud-k…
wind57 Jan 12, 2022
b041c00
trigger again
wind57 Jan 13, 2022
9580444
Merge branch 'main' of https://github.com/spring-cloud/spring-cloud-k…
wind57 Mar 15, 2022
a34ac47
Add renovate.json
renovate[bot] Jul 13, 2022
6613f78
Merge branch 'spring-cloud:main' into main
wind57 Jul 13, 2022
1b3eae9
Merge pull request #1 from wind57/renovate/configure
wind57 Jul 13, 2022
4275382
Merge branch 'spring-cloud:main' into main
wind57 Mar 13, 2023
618f25a
Delete renovate.json
wind57 Mar 14, 2023
100a9cd
Delete delme.sh
wind57 Mar 14, 2023
4b9056b
Merge branch 'main' of https://github.com/spring-cloud/spring-cloud-k…
wind57 Mar 14, 2023
315a85b
Merge branch 'main' of https://github.com/spring-cloud/spring-cloud-k…
wind57 Mar 15, 2023
ed3c264
Merge branch 'main' of https://github.com/spring-cloud/spring-cloud-k…
wind57 Mar 15, 2023
446d630
Merge branch 'main' of https://github.com/spring-cloud/spring-cloud-k…
wind57 Mar 16, 2023
6821a28
Merge branch 'main' of https://github.com/spring-cloud/spring-cloud-k…
wind57 Mar 16, 2023
9e95a8a
Merge branch 'main' of https://github.com/spring-cloud/spring-cloud-k…
wind57 Mar 16, 2023
02840b1
Merge branch 'main' of https://github.com/spring-cloud/spring-cloud-k…
wind57 Mar 16, 2023
7e31d65
Merge branch 'main' of https://github.com/spring-cloud/spring-cloud-k…
wind57 Mar 20, 2023
926f4d7
Merge branch 'main' of https://github.com/spring-cloud/spring-cloud-k…
wind57 Mar 20, 2023
344e1d4
Merge branch 'main' of https://github.com/spring-cloud/spring-cloud-k…
wind57 Mar 21, 2023
e91ac12
Merge branch 'main' of https://github.com/spring-cloud/spring-cloud-k…
wind57 Mar 23, 2023
ba6e088
Merge branch 'main' of https://github.com/spring-cloud/spring-cloud-k…
wind57 Mar 28, 2023
36780a3
started
wind57 Mar 30, 2023
cffc9ce
fix
wind57 Mar 30, 2023
002c975
Merge branch 'main' of https://github.com/spring-cloud/spring-cloud-k…
wind57 Mar 30, 2023
56a02be
Merge branch 'main' into fix-1278
wind57 Mar 30, 2023
870f211
fix
wind57 Mar 30, 2023
06c5465
Merge branch 'main' of https://github.com/spring-cloud/spring-cloud-k…
wind57 Mar 30, 2023
6a6c765
Merge branch 'main' into fix-1278
wind57 Mar 30, 2023
32939ae
renamed image
wind57 Mar 31, 2023
a946ea4
renamed image
wind57 Mar 31, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
package org.springframework.cloud.kubernetes.fabric8.discovery;

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties;
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
import org.springframework.cloud.kubernetes.fabric8.Fabric8AutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
Expand All @@ -29,6 +32,7 @@
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty("spring.cloud.config.discovery.enabled")
@Import({ Fabric8AutoConfiguration.class, KubernetesDiscoveryClientAutoConfiguration.class })
@EnableConfigurationProperties({ KubernetesDiscoveryProperties.class, KubernetesClientProperties.class })
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the core problem right here. this bootstrap imports two configurations:

  • Fabric8AutoConfiguration, which internally requires KubernetesClientProperties
  • KubernetesDiscoveryClientAutoConfiguration which internally requires KubernetesDiscoveryProperties

These work just fine on their own if used by auto-configuration only, but once we use bootstrap annotations like @AutoConfigureBefore break.

The one change that I did not account for was the fact that before this change, we used to provide an explicit KubernetesDiscoveryProperties @Bean and I dropped it once I fixed that issue. Totally my mistake here.


The other one with KubernetesClientProperties was still present, but as said in the issue itself, we got very lucky that no one actually stepped on it.

It's kind of sad that I spent so much time thinking into not breaking anything once I make my changes, and it still happens...

public class KubernetesDiscoveryClientConfigClientBootstrapConfiguration {

}
3 changes: 2 additions & 1 deletion spring-cloud-kubernetes-integration-tests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -92,5 +92,6 @@
<module>spring-cloud-kubernetes-client-secrets-event-reload-multiple-apps</module>
<module>spring-cloud-kubernetes-fabric8-client-catalog-watcher</module>
<module>spring-cloud-kubernetes-client-catalog-watcher</module>
</modules>
<module>spring-cloud-kubernetes-fabric8-client-discovery-with-bootstrap</module>
</modules>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-kubernetes-integration-tests</artifactId>
<groupId>org.springframework.cloud</groupId>
<version>3.0.3-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>spring-cloud-kubernetes-fabric8-client-discovery-with-bootstrap</artifactId>

<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-kubernetes-fabric8-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-kubernetes-test-support</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.github.docker-java</groupId>
<artifactId>docker-java-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.docker-java</groupId>
<artifactId>docker-java-transport-httpclient5</artifactId>
<scope>test</scope>
</dependency>

</dependencies>
<build>
<resources>
<resource>
<directory>../src/main/resources</directory>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>

<plugins>
<!-- build image in the 'package' phase, and ignore plain tests -->
<!-- via maven-surefire-plugin::skipTests -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<imageName>docker.io/springcloud/${project.artifactId}:${project.version}</imageName>
<imageBuilder>paketobuildpacks/builder</imageBuilder>
</configuration>
<executions>
<execution>
<id>build-image</id>
<configuration>
<skip>${skip.build.image}</skip>
</configuration>
<phase>package</phase>
<goals>
<goal>build-image</goal>
</goals>
</execution>
<execution>
<id>repackage</id>
<phase>package</phase>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>

<!-- ignore plain tests (in the 'test' phase), so that we could build the image first, see above -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>

<!-- run tests in the 'integration-tests' phase, one that is after 'package' (where we build the image) -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
</goals>
</execution>
</executions>
<configuration>
<includes>
<include>${testsToRun}</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>

<profiles>
<profile>
<id>imagename</id>
<activation>
<property>
<name>!env.IMAGE</name>
</property>
</activation>
<properties>
<env.IMAGE>springcloud/${project.artifactId}:${project.version}</env.IMAGE>
</properties>
</profile>
</profiles>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright 2013-2021 the original author or 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
*
* https://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 org.springframework.cloud.kubernetes.fabric8.discovery.bootstrap;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
* @author wind57
*/
@SpringBootApplication
public class Fabric8DiscoveryBootstrapApp {

public static void main(String[] args) {
SpringApplication.run(Fabric8DiscoveryBootstrapApp.class, args);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright 2013-2021 the original author or 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
*
* https://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 org.springframework.cloud.kubernetes.fabric8.discovery.bootstrap;

import java.util.List;

import org.springframework.cloud.kubernetes.fabric8.discovery.KubernetesDiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* @author wind57
*/
@RestController
public class Fabric8DiscoveryBootstrapController {

private final KubernetesDiscoveryClient discoveryClient;

public Fabric8DiscoveryBootstrapController(KubernetesDiscoveryClient discoveryClient) {
this.discoveryClient = discoveryClient;
}

@GetMapping("/services")
public List<String> allServices() {
return discoveryClient.getServices();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
spring:
application:
name: fabric8-discovery-with-bootstrap
cloud:
config:
discovery:
enabled: true
fail-fast: true
retry:
max-attempts: 60
enabled: true
request-connect-timeout: 1000
request-read-timeout: 1000
logging:
level:
root: DEBUG
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/*
* Copyright 2013-2023 the original author or 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
*
* https://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 org.springframework.cloud.kubernetes.fabric8.discovery.bootstrap;

import java.io.InputStream;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import io.fabric8.kubernetes.api.model.EnvVar;
import io.fabric8.kubernetes.api.model.EnvVarBuilder;
import io.fabric8.kubernetes.api.model.Service;
import io.fabric8.kubernetes.api.model.apps.Deployment;
import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
import io.fabric8.kubernetes.client.KubernetesClient;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.testcontainers.k3s.K3sContainer;
import reactor.netty.http.client.HttpClient;
import reactor.util.retry.Retry;
import reactor.util.retry.RetryBackoffSpec;

import org.springframework.cloud.kubernetes.integration.tests.commons.Commons;
import org.springframework.cloud.kubernetes.integration.tests.commons.Phase;
import org.springframework.cloud.kubernetes.integration.tests.commons.fabric8_client.Util;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.WebClient;

/**
* @author wind57
*/
class Fabric8DiscoveryBootstrapIT {

private static final String NAMESPACE = "default";

private static final String IMAGE_NAME = "spring-cloud-kubernetes-fabric8-client-discovery-with-bootstrap";

private static KubernetesClient client;

private static Util util;

private static final K3sContainer K3S = Commons.container();

@BeforeAll
static void beforeAll() throws Exception {
K3S.start();
Commons.validateImage(IMAGE_NAME, K3S);
Commons.loadSpringCloudKubernetesImage(IMAGE_NAME, K3S);

util = new Util(K3S);
client = util.client();

util.setUp(NAMESPACE);

manifests(Phase.CREATE);
util.wiremock(NAMESPACE, "/wiremock", Phase.CREATE);
}

@AfterAll
static void after() throws Exception {
util.wiremock(NAMESPACE, "/wiremock", Phase.DELETE);
manifests(Phase.DELETE);
Commons.cleanUp(IMAGE_NAME, K3S);
}

/**
* A simple test to discover services.
*/
@Test
void testSimple() {
WebClient client = builder().baseUrl("http://localhost/services").build();

List<String> result = client.method(HttpMethod.GET).retrieve()
.bodyToMono(new ParameterizedTypeReference<List<String>>() {

}).retryWhen(retrySpec()).block();

Assertions.assertEquals(result.size(), 3);
Assertions.assertTrue(result.contains("kubernetes"));
Assertions.assertTrue(result.contains("spring-cloud-kubernetes-fabric8-client-discovery"));
Assertions.assertTrue(result.contains("service-wiremock"));
}

private static void manifests(Phase phase) {

InputStream deploymentStream = util.inputStream("fabric8-discovery-deployment.yaml");
InputStream serviceStream = util.inputStream("fabric8-discovery-service.yaml");
InputStream ingressStream = util.inputStream("fabric8-discovery-ingress.yaml");

Deployment deployment = client.apps().deployments().load(deploymentStream).get();

List<EnvVar> existing = new ArrayList<>(
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv());
existing.add(new EnvVarBuilder().withName("SPRING_CLOUD_KUBERNETES_DISCOVERY_INCLUDEEXTERNALNAMESERVICES")
.withValue("true").build());
existing.add(
new EnvVarBuilder().withName("LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_FABRIC8_DISCOVERY")
.withValue("DEBUG").build());
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(existing);

Service service = client.services().load(serviceStream).get();
Ingress ingress = client.network().v1().ingresses().load(ingressStream).get();

if (phase.equals(Phase.CREATE)) {
util.createAndWait(NAMESPACE, null, deployment, service, ingress, true);
}
else {
util.deleteAndWait(NAMESPACE, deployment, service, ingress);
}

}

private WebClient.Builder builder() {
return WebClient.builder().clientConnector(new ReactorClientHttpConnector(HttpClient.create()));
}

private RetryBackoffSpec retrySpec() {
return Retry.fixedDelay(15, Duration.ofSeconds(1)).filter(Objects::nonNull);
}

}
Loading