From fc68b2dbba0e0846e3e893e350cc406cbad3a61e Mon Sep 17 00:00:00 2001 From: Aquilino Viveiros Date: Thu, 3 May 2018 14:58:58 +0100 Subject: [PATCH 1/3] Feature request: Adding refresh rate to GIT repositories (#1001) --- .../JGitEnvironmentRepository.java | 35 +++++++++++ .../MultipleJGitEnvironmentRepository.java | 3 + .../JGitEnvironmentRepositoryTests.java | 61 +++++++++++++++++++ ...EnvironmentRepositoryIntegrationTests.java | 20 ++++++ 4 files changed, 119 insertions(+) diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepository.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepository.java index 1fd7ed7e..64d792e3 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepository.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepository.java @@ -92,6 +92,16 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository */ private int timeout = 5; + /** + * Time (in seconds) between refresh of the git repository + */ + private int refreshRate = 0; + + /** + * Time of the last refresh of the git repository + */ + private long lastRefresh; + /** * Flag to indicate that the repository should be cloned on startup (not on demand). * Generally leads to slower startup but faster first query. @@ -144,6 +154,15 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository this.timeout = timeout; } + public int getRefreshRate() { + return refreshRate; + } + + public void setRefreshRate(int refreshRate) { + this.refreshRate = refreshRate; + } + + public TransportConfigCallback getTransportConfigCallback() { return transportConfigCallback; } @@ -347,6 +366,11 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository protected boolean shouldPull(Git git) throws GitAPIException { boolean shouldPull; + + if (this.refreshRate > 0 && System.currentTimeMillis() - this.lastRefresh < (this.refreshRate * 1000)) { + return false; + } + Status gitStatus = git.status().call(); boolean isWorkingTreeClean = gitStatus.isClean(); String originUrl = git.getRepository().getConfig().getString("remote", "origin", @@ -392,6 +416,9 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository fetch.setRemote("origin"); fetch.setTagOpt(TagOpt.FETCH_TAGS); fetch.setRemoveDeletedRefs(deleteUntrackedBranches); + if (this.refreshRate > 0) { + this.setLastRefresh(System.currentTimeMillis()); + } configureCommand(fetch); try { @@ -617,6 +644,14 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository } } + public void setLastRefresh(long lastRefresh) { + this.lastRefresh = lastRefresh; + } + + public long getLastRefresh() { + return lastRefresh; + } + /** * Wraps the static method calls to {@link org.eclipse.jgit.api.Git} and * {@link org.eclipse.jgit.api.CloneCommand} allowing for easier unit testing. diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/MultipleJGitEnvironmentRepository.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/MultipleJGitEnvironmentRepository.java index 16d9deec..1fa8cbb8 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/MultipleJGitEnvironmentRepository.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/MultipleJGitEnvironmentRepository.java @@ -81,6 +81,9 @@ public class MultipleJGitEnvironmentRepository extends JGitEnvironmentRepository if (getTimeout() != 0 && repo.getTimeout() == 0) { repo.setTimeout(getTimeout()); } + if (getRefreshRate() != 0 && repo.getRefreshRate() == 0) { + repo.setRefreshRate(getRefreshRate()); + } String user = repo.getUsername(); String pass = repo.getPassword(); String passphrase = repo.getPassphrase(); diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepositoryTests.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepositoryTests.java index 23c555aa..bc9490d8 100644 --- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepositoryTests.java +++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepositoryTests.java @@ -325,6 +325,67 @@ public class JGitEnvironmentRepositoryTests { assertThat("shouldPull was false", shouldPull, is(true)); } + @Test + public void shouldNotRefresh() throws Exception { + Git git = mock(Git.class); + StatusCommand statusCommand = mock(StatusCommand.class); + Status status = mock(Status.class); + Repository repository = mock(Repository.class); + StoredConfig storedConfig = mock(StoredConfig.class); + + when(git.status()).thenReturn(statusCommand); + when(git.getRepository()).thenReturn(repository); + when(repository.getConfig()).thenReturn(storedConfig); + when(storedConfig.getString("remote", "origin", "url")).thenReturn("http://example/git"); + when(statusCommand.call()).thenReturn(status); + when(status.isClean()).thenReturn(true); + + JGitEnvironmentRepository repo = new JGitEnvironmentRepository(this.environment); + + repo.setLastRefresh(System.currentTimeMillis() - 5000); + repo.setRefreshRate(2); + + boolean shouldPull = repo.shouldPull(git); + + assertThat("shouldPull was false", shouldPull, is(true)); + + repo.setRefreshRate(30); + + shouldPull = repo.shouldPull(git); + + assertThat("shouldPull was true", shouldPull, is(false)); + } + + @Test + public void shouldUpdateLastRefresh() throws Exception { + Git git = mock(Git.class); + StatusCommand statusCommand = mock(StatusCommand.class); + Status status = mock(Status.class); + Repository repository = mock(Repository.class); + StoredConfig storedConfig = mock(StoredConfig.class); + FetchCommand fetchCommand = mock(FetchCommand.class); + FetchResult fetchResult = mock(FetchResult.class); + + when(git.status()).thenReturn(statusCommand); + when(git.getRepository()).thenReturn(repository); + when(fetchCommand.call()).thenReturn(fetchResult); + when(git.fetch()).thenReturn(fetchCommand); + when(repository.getConfig()).thenReturn(storedConfig); + when(storedConfig.getString("remote", "origin", "url")).thenReturn("http://example/git"); + when(statusCommand.call()).thenReturn(status); + when(status.isClean()).thenReturn(true); + + JGitEnvironmentRepository repo = new JGitEnvironmentRepository(this.environment); + + repo.setRefreshRate(1000); + repo.setLastRefresh(0); + repo.fetch(git, "master"); + + long timeDiff = System.currentTimeMillis() - repo.getLastRefresh(); + + assertThat("time difference ("+timeDiff+") was longer than 1 second", timeDiff < 1000L, is(true)); + } + @Test public void testFetchException() throws Exception { diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/MultipleJGitEnvironmentRepositoryIntegrationTests.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/MultipleJGitEnvironmentRepositoryIntegrationTests.java index e52df446..b3b08673 100644 --- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/MultipleJGitEnvironmentRepositoryIntegrationTests.java +++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/MultipleJGitEnvironmentRepositoryIntegrationTests.java @@ -102,6 +102,26 @@ public class MultipleJGitEnvironmentRepositoryIntegrationTests { assertEquals(2, environment.getPropertySources().size()); } + @Test + public void mappingRepoWithRefreshRate() throws IOException { + String defaultRepoUri = ConfigServerTestUtils.prepareLocalRepo("config-repo"); + String test1RepoUri = ConfigServerTestUtils.prepareLocalRepo("test1-config-repo"); + + Map repoMapping = new LinkedHashMap(); + repoMapping.put("spring.cloud.config.server.git.repos[test1].pattern", "*test1*"); + repoMapping.put("spring.cloud.config.server.git.repos[test1].uri", test1RepoUri); + repoMapping.put("spring.cloud.config.server.git.refreshRate", "30"); + this.context = new SpringApplicationBuilder(TestConfiguration.class).web(false) + .properties("spring.cloud.config.server.git.uri:" + defaultRepoUri) + .properties(repoMapping).run(); + EnvironmentRepository repository = this.context + .getBean(EnvironmentRepository.class); + repository.findOne("test1-svc", "staging", "master"); + Environment environment = repository.findOne("test1-svc", "staging", "master"); + assertEquals(2, environment.getPropertySources().size()); + assertEquals(((MultipleJGitEnvironmentRepository) repository).getRepos().get("test1").getRefreshRate(), 30); + } + @Test public void mappingRepoWithProfile() throws IOException { String defaultRepoUri = ConfigServerTestUtils.prepareLocalRepo("config-repo"); From 8da878bc02918b7ea57fd67158aa4d8901d0c341 Mon Sep 17 00:00:00 2001 From: Ryan Baxter Date: Mon, 4 Jun 2018 11:19:36 -0400 Subject: [PATCH 2/3] Document location of spring.cloud.config.server.encrypt.enabled. Fixes 887. --- docs/src/main/asciidoc/spring-cloud-config.adoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/src/main/asciidoc/spring-cloud-config.adoc b/docs/src/main/asciidoc/spring-cloud-config.adoc index f4ab6f8a..ec9e15e8 100644 --- a/docs/src/main/asciidoc/spring-cloud-config.adoc +++ b/docs/src/main/asciidoc/spring-cloud-config.adoc @@ -1035,9 +1035,9 @@ Sometimes you want the clients to decrypt the configuration locally, instead of doing it in the server. In that case you can still have /encrypt and /decrypt endpoints (if you provide the `encrypt.*` configuration to locate a key), but you need to explicitly switch off -the decryption of outgoing properties using -`spring.cloud.config.server.encrypt.enabled=false`. If you don't care -about the endpoints, then it should work if you configure neither the +the decryption of outgoing properties by placing +`spring.cloud.config.server.encrypt.enabled=false` in `bootstrap.[yml|properties]`. +If you don't care about the endpoints, then it should work if you configure neither the key nor the enabled flag. == Serving Alternative Formats From 484b74b4ed97ab31c1e3620474cc2979b19c7e3d Mon Sep 17 00:00:00 2001 From: Ryan Baxter Date: Mon, 4 Jun 2018 11:26:56 -0400 Subject: [PATCH 3/3] encrypt.* properties should be in bootstrap.yml not application.yml. Fixes #895. --- docs/src/main/asciidoc/spring-cloud-config.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/main/asciidoc/spring-cloud-config.adoc b/docs/src/main/asciidoc/spring-cloud-config.adoc index ec9e15e8..27c7ee19 100644 --- a/docs/src/main/asciidoc/spring-cloud-config.adoc +++ b/docs/src/main/asciidoc/spring-cloud-config.adoc @@ -980,7 +980,7 @@ $ keytool -genkeypair -alias mytestkey -keyalg RSA \ ---- Put the `server.jks` file in the classpath (for instance) and then in -your `application.yml` for the Config Server: +your `bootstrap.yml` for the Config Server: [source,yaml] ----