Fix Guardfile

This commit is contained in:
Dave Syer
2014-10-01 14:56:17 +01:00
parent f27b6abce6
commit f29859c252
6 changed files with 457 additions and 50 deletions

View File

@@ -1,11 +1,12 @@
require 'asciidoctor'
require 'erb'
require './src/main/ruby/readme.rb'
options = {:mkdirs => true, :safe => :unsafe, :attributes => 'linkcss'}
guard 'shell' do
watch(/^[A-Za-z].*\.adoc$/) {|m|
Asciidoctor.render_file('src/main/asciidoc/README.adoc', options.merge(:to_file => './README.md'))
watch(/^src\/[A-Za-z].*\.adoc$/) {|m|
SpringCloud::Build.render_file('src/main/asciidoc/README.adoc', :to_file => './README.adoc')
Asciidoctor.render_file('src/main/asciidoc/spring-cloud-config.adoc', options.merge(:to_dir => 'target/generated-docs'))
}
end

View File

@@ -6,13 +6,15 @@ Spring Cloud Config provides server and client-side support for externalized con
== Features
Spring Cloud Config Server features:
=== Spring Cloud Config Server
* HTTP, resource-based API for external configuration (name-value pairs, or equivalent YAML content)
* Encrypt and decrypt property values (symmetric or asymmetric)
* Embeddable easily in a Spring Boot application using `@EnableConfigServer`
Config Client features (for Spring applications):
=== Spring Cloud Config Client
Specifically for Spring applications:
* Bind to the Config Server and initialize Spring `Environment` with remote property sources
* Encrypt and decrypt property values (symmetric or asymmetric)
@@ -64,8 +66,80 @@ list of properties), and "label" is an optional git label (defaults to
=== Client Side Usage
To use these features in an application, just build it as a Spring
Boot application that depends on spring-cloud-config-client
(e.g. see the test cases for the config-client, or the sample app).
Boot application that depends on spring-cloud-config-client (e.g. see
the test cases for the config-client, or the sample app). The most
convenient way to add the dependency is via a Spring Boot starter
`org.springframework.cloud:spring-cloud-starter`. There is also a
parent pom and BOM (`spring-cloud-starters`) for Maven users and a
Spring IO version management properties file for Gradle and Spring CLI
users. Example Maven configuration:
[source,xml,indent=0]
.pom.xml
----
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.1.7.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starters</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<!-- repositories also needed for snapshots and milestones -->
----
Then you can create a standard Spring Boot application, like this simple HTTP server:
----
@Configuration
@EnableAutoConfiguration
@RestController
public class Application {
@RequestMapping("/")
public String home() {
return "Hello World!";
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
----
When it runs it will pick up the external configuration from the
default local config server on port 8888 if it is running. To modify
the startup behaviour you can change the location of the config server
@@ -73,7 +147,7 @@ using `bootstrap.properties` (like `application.properties` but for
the bootstrap phase of an application context), e.g.
----
spring.platform.config.uri: http://myconfigserver.com
spring.cloud.config.uri: http://myconfigserver.com
----
The bootstrap properties will show up in the `/env` endpoint as a

View File

@@ -3,13 +3,15 @@ include::intro.adoc[]
== Features
Spring Cloud Config Server features:
=== Spring Cloud Config Server
* HTTP, resource-based API for external configuration (name-value pairs, or equivalent YAML content)
* Encrypt and decrypt property values (symmetric or asymmetric)
* Embeddable easily in a Spring Boot application using `@EnableConfigServer`
Config Client features (for Spring applications):
=== Spring Cloud Config Client
Specifically for Spring applications:
* Bind to the Config Server and initialize Spring `Environment` with remote property sources
* Encrypt and decrypt property values (symmetric or asymmetric)
@@ -24,3 +26,39 @@ Config Client features (for Spring applications):
== Quick Start
include::quickstart.adoc[]
=== Sample Application
There is a sample application
https://github.com/spring-cloud/spring-cloud-config/tree/master/spring-cloud-config-sample[here]. It
is a Spring Boot application so you can run it using the usual
mechanisms (for instance "mvn spring-boot:run"). When it runs it will
look for the config server on "http://localhost:8888" by default, so
you could run the server as well to see it all working together.
The sample has a test case where the config server is also started in
the same JVM (with a different port), and the test asserts that an
environment property from the git configuration repo is present. To
change the location of the config server just set
"spring.platform.config.uri" in "bootstrap.yml" (or via System
properties etc.).
The test case has a `main()` method that runs the server in the same
way (watch the logs for its port), so you can run the whole system in
one process and play with it (e.g. right click on the main in your IDE
and run it). The `main()` method uses `target/config` for the working
directory of the git repository, so you can make local changes there
and see them reflected in the running app.
----
$ curl localhost:8080/env/foo
bar
$ vi target/config/bar.properties
.. change value of "foo", optionally commit
$ curl localhost:8080/refresh
["foo"]
$ curl localhost:8080/env/foo
baz
----
The refresh endpoint reports that the "foo" property changed.

View File

@@ -36,8 +36,80 @@ list of properties), and "label" is an optional git label (defaults to
=== Client Side Usage
To use these features in an application, just build it as a Spring
Boot application that depends on spring-cloud-config-client
(e.g. see the test cases for the config-client, or the sample app).
Boot application that depends on spring-cloud-config-client (e.g. see
the test cases for the config-client, or the sample app). The most
convenient way to add the dependency is via a Spring Boot starter
`org.springframework.cloud:spring-cloud-starter`. There is also a
parent pom and BOM (`spring-cloud-starters`) for Maven users and a
Spring IO version management properties file for Gradle and Spring CLI
users. Example Maven configuration:
[source,xml,indent=0]
.pom.xml
----
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.1.7.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starters</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<!-- repositories also needed for snapshots and milestones -->
----
Then you can create a standard Spring Boot application, like this simple HTTP server:
----
@Configuration
@EnableAutoConfiguration
@RestController
public class Application {
@RequestMapping("/")
public String home() {
return "Hello World!";
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
----
When it runs it will pick up the external configuration from the
default local config server on port 8888 if it is running. To modify
the startup behaviour you can change the location of the config server
@@ -45,7 +117,7 @@ using `bootstrap.properties` (like `application.properties` but for
the bootstrap phase of an application context), e.g.
----
spring.platform.config.uri: http://myconfigserver.com
spring.cloud.config.uri: http://myconfigserver.com
----
The bootstrap properties will show up in the `/env` endpoint as a
@@ -65,39 +137,3 @@ $ curl localhost:8080/env
(a property source called "configService:<URL of remote
repository>/<file name>" contains the property "foo" with value
"bar" and is highest priority).
=== Sample Application
There is a sample application
https://github.com/spring-cloud/spring-cloud-config/tree/master/spring-cloud-config-sample[here]. It
is a Spring Boot application so you can run it using the usual
mechanisms (for instance "mvn spring-boot:run"). When it runs it will
look for the config server on "http://localhost:8888" by default, so
you could run the server as well to see it all working together.
The sample has a test case where the config server is also started in
the same JVM (with a different port), and the test asserts that an
environment property from the git configuration repo is present. To
change the location of the config server just set
"spring.platform.config.uri" in "bootstrap.yml" (or via System
properties etc.).
The test case has a `main()` method that runs the server in the same
way (watch the logs for its port), so you can run the whole system in
one process and play with it (e.g. right click on the main in your IDE
and run it). The `main()` method uses `target/config` for the working
directory of the git repository, so you can make local changes there
and see them reflected in the running app.
----
$ curl localhost:8080/env/foo
bar
$ vi target/config/bar.properties
.. change value of "foo", optionally commit
$ curl localhost:8080/refresh
["foo"]
$ curl localhost:8080/env/foo
baz
----
The refresh endpoint reports that the "foo" property changed.

View File

@@ -6,3 +6,260 @@ include::intro.adoc[]
== Quick Start
include::quickstart.adoc[]
== Spring Cloud Config Server
The Server provides an HTTP, resource-based API for external
configuration (name-value pairs, or equivalent YAML content). The
server is easily embeddable in a Spring Boot application using the
`@EnableConfigServer` annotation.
=== Encryption and Decryption
The server exposes `/encrypt` and `/decrypt` endpoints (on the
assumption that these will be secured and only accessed by authorized
agents). If the remote property sources contain encryted content
(values starting with `{cipher}`) they will be decrypted before
sending to clients over HTTP. The main advantage of this set up is
that the property values don't have to be in plain text when they are
"at rest" (e.g. in a git repository).
If you are setting up a remote config repository for config client
applications it might contain an `application.yml` like this, for
instance:
.application.yml
----
spring:
datasource:
username: dbuser
password: {cipher}FKSAJDFGYOS8F7GLHAKERGFHLSAJ
----
You can safely push this plain text to a shared git repository and the
secret password is protected.
If you are editing a remote config file you can use the Config Server
to encrypt values by POSTing to the `/encrypt` endpoint, e.g.
----
$ curl localhost:8888/encrypt -d mysecret
682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda
----
The inverse operation is also available via `/decrypt` (provided the server is
configured with a symmetric key or a full key pair):
----
$ curl localhost:8888/edecrypt -d 682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda
mysecret
----
Take the encypted value and add the `{cipher}` prefix before you put
it in the YAML or properties file, and before you commit and push it
to a remote, potentially insecure store.
The `spring` command line client (with Spring Cloud CLI extensions
installed) can also be used to encrypt and decrypt, e.g.
----
$ spring encrypt mysecret --key foo
682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda
$ spring decrypt --key foo 682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda
mysecret
----
To use a key in a file (e.g. an RSA public key for encyption) prepend
the key value with "@" and provide the file path, e.g.
----
$ spring encrypt mysecret --key @${HOME}/.ssh/id_rsa.pub
AQAjPgt3eFZQXwt8tsHAVv/QHiY5sI2dRcR+...
----
=== Key Management
The Config Server can use a symmetric (shared) key or an asymmetric
one (RSA key pair). The asymmetric choice is superior in terms of
security, but it is often more convenient to use a symmetric key since
it is just a single property value to configure.
To configure a symmetric key you just need to set `encrypt.key` to a
secret String (or use an enviroment variable `ENCRYPT_KEY` to keep it
out of plain text configuration files). You can also POST a key value
to the `/key` endpoint (but that won't change any existing encrypted
values in remote repositories).
To configure an asymmetric key you can either set the key as a
PEM-encoded text value (in `encrypt.key`), or via a keystore (e.g. as
created by the `keytool` utility that comes with the JDK). The
keystore properties are `encrypt.keyStore.*` with `*` equals to
`location` (a `Resource` location), `password` (to unlock the
keystore) and `alias` (to identify which key in the store is to be
used).
The encryption is done with the public key, and a private key is
needed for decryption. Thus in principle you can configure only the
public key in the server if you only want to do encryption (and are
prepared to decrypt the values yourself locally with the private
key). In practice you might not want to do that because it spreads the
key management process around all the clients, instead of
concentrating it in the server. On the other hand it's a useful option
if your config server really is relatively insecure and only a
handful of clients need the encrypted properties.
=== Creating a Key Store for Testing
To create a keystore for testing you can do something like this:
----
$ keytool -genkeypair -alias mytestkey -keyalg RSA \
-dname "CN=Web Server,OU=Unit,O=Organization,L=City,S=State,C=US" \
-keypass changeme -keystore server.jks -storepass letmein
----
Put the `server.jks` file in the classpath (for instance) and then in
your `application.yml` for the Config Server:
----
encrypt:
keyStore:
location: classpath:/server.jks
alias: mytestkey
password: letmein
----
== Spring Cloud Config Client
A Spring Boot application can take immediate advantage of the Spring
Config Server (or other external property sources provided by the
application developer), and it will also pick up some additional
useful features related to `Environment` change events. When a config
client starts up it binds to the Config Server (via the bootstrap
configuration property `spring.cloud.config.uri`) and initializes
Spring `Environment` with remote property sources
=== Environment Changes
The application will listen for an `EnvironmentChangedEvent` and react
to the change in a couple of standard ways (additional
`ApplicationListeners` can be added as `@Beans` by the user in the
normal way). When an `EnvironmentChangedEvent` is observed it will
have a list of key values that have changed, and the application will
use those to:
* Re-bind any `@ConfigurationProperties` beans in the context
* Set the logger levels for any properties in `logging.level.*`
This covers a large class of refresh use cases, and you can verify the
changes by visiting the `/configprops` endpoint (normal Spring Boot
Actuator feature). For instance a `DataSource` can have its
`maxPoolSize` changed at runtime (the default `DataSource` created by
Spring Boot is an `@ConfigurationProperties` bean) and grow capacity
dynamically. It does not cover another large class of use cases, where
you need more control over the refresh, and where you need a
configuration change to be atomic over the whole
`ApplicationContext`. To address those concerns we have
`@RefreshScope`.
=== Refresh Scope
A Spring `@Bean` that is marked as `@RefreshScope` will get special
treatment when there is a configuration change. This addresses the
problem of stateful beans that only get their configuration injected
when they are initialized. For instance if a `DataSource` has open
connections when the database URL is changed via the `Environment`, we
probably want the holders of those connections to be able to complete
what they are doing. Then the next time someone borrows a connection
from the pool he gets one with the new URL.
Refresh scope beans are lazy proxies that initialize when they are
used (i.e. when a method is called), and the scope acts as a cache of
initialized values. To force a bean to re-initialize on the next
method call you just need to invalidate its cache entry.
The `RefreshScope` is a bean in the context and it has a public method
`refreshAll()` to refresh all beans in the scope by clearing the
target cache. There is also a `refresh(String)` method to refresh an
individual bean by name. This functionality is exposed in the
`/refresh` endpoint (over HTTP or JMX).
=== Encryption and Decryption
The Config Client has an `Environment` pre-processor for decrypting
property values locally. It follows the same rules as the Config
Server, and has the same external configuration via `encrypt.*`. Thus
you can use encrypted values in the form `{cipher}*` and as long as
there is a valid key then they will be decrypted before the main
application context gets the `Environment`.
=== Endpoints
For a Spring Boot Actuator application there are some additional management endpoints:
* POST to `/env` to update the `Environment` and rebind `@ConfigurationProperties` and log levels
* `/refresh` for re-loading the boot strap context and refreshing the `@RefreshScope` beans
* `/restart` for closing the `ApplicationContext` and restarting it (disabled by default)
* `/pause` and `/resume` for calling the `Lifecycle` methods (`stop()` and `start()` on the `ApplicationContext`)
=== The Bootstrap Application Context
The Config Client operates by creating a "bootstrap" application
context, which is a parent context for the main application. Out of
the box it is responsible for loading configuration properties from
the Config Server, and also decrypting properties in the local
external configuration files. The two contexts share an `Environment`
which is the source of external properties for any Spring
application. Bootstrap properties are added with hight precedence, so
they cannot be overridden by local configuration.
The bootstrap context uses a different convention for locating
external configuration than the main application context, so instead
of `application.yml` (or `.properties`) you use `bootstrap.yml`,
keeping the external configuration for bootstrap and main context
nicely separate. Example:
.bootstrap.yml
----
spring:
application:
name: foo
cloud:
config:
uri: ${SPRING_CONFIG_URI:http://localhost:8888}
----
It is a good idea to set the `spring.application.name` in
`bootstrap.yml` if your application needs any application-specific
configuration from the server.
You can disable the bootstrap process completely by setting
`spring.platform.bootstrap.enabled=false` (e.g. in System properties).
=== Customizing the Bootstrap
The bootstrap context can be trained to do anything you like by adding
entries to `/META-INF/spring.factories` under the key
`org.springframework.cloud.bootstrap.BootstrapConfiguration`. This is
a comma-separated list of Spring `@Configuration` classes which will
be used to create the context. Any beans that you want to be available
to the main application context for autowiring can be created here,
and also there is a special contract for `@Beans` of type
`ApplicationContextInitializer`.
The bootstrap process ends by injecting initializers into the main
`SpringApplication` instance (i.e. the normal Spring Boot startup
sequence, whether it is running as a standalone app or deployed in an
application server). First a bootstrap context is created from the
classes found in `spring.factories` and then all `@Beans` of type
`ApplicationContextInitializer` are added to the main
`SpringApplication` before it is started.
=== Customizing the Property Sources
The default property source for external configuration added by the
bootstrap process is the Config Server, but you can add additional
sources by adding beans of type `PropertySourceLocator` to the
bootstrap context (via `spring.factories`). You could use this to
insert additional properties from a different server, or from a
database, for instance.

View File

@@ -41,8 +41,9 @@ module SpringCloud
unless options[:to_file]
puts out
else
writer = File.new(options[:to_file],'w+')
out.each { |line| writer.write(line) }
File.open(options[:to_file],'w+') do |file|
out.each { |line| file.write(line) }
end
end
end