Skip to content

Commit 309e8c5

Browse files
author
Christopher Frost
committed
Support nil configuration values
This commit makes a number of changes all required to support `nil` or empty values in the configuration files. Any `key` with a `nil` value will be ignored but as it is present it can be modified with a new value via an environment variable. Aditional changes ensure offline buildpacks still contain `nil` configuration values after version pinning. Updates the Java Opts suppport to have a `nil` `java_opts` configuration. Add in some additional `nil` configuration for the memory calculator so these can also be updated via environment variables. closes cloudfoundry#202 and closes cloudfoundry#204 [#98822486]
1 parent 64f1fde commit 309e8c5

15 files changed

Lines changed: 84 additions & 44 deletions

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ The following are _very_ simple examples for deploying the artifact types that w
2727
## Configuration and Extension
2828
The buildpack supports extension through the use of Git repository forking. The easiest way to accomplish this is to use [GitHub's forking functionality][] to create a copy of this repository. Make the required extension changes in the copy of the repository. Then specify the URL of the new repository when pushing Cloud Foundry applications. If the modifications are generally applicable to the Cloud Foundry community, please submit a [pull request][] with the changes.
2929

30-
Buildpack configuration can be overridden with an environment variable matching the configuration file you wish to override minus the `.yml` extension and with a prefix of `JBP_CONFIG`. The value of the variable should be valid inline yaml. For example, to change the default version of Java to 7 and adjust the memory heuristics apply this environment variable to the application.
30+
Buildpack configuration can be overridden with an environment variable matching the configuration file you wish to override minus the `.yml` extension and with a prefix of `JBP_CONFIG`. It is not possible to add new configuration properties and properties with `nil` or empty values will be ignored by the buildpack. The value of the variable should be valid inline yaml. For example, to change the default version of Java to 7 and adjust the memory heuristics apply this environment variable to the application.
3131

3232
```cf set-env my-application JBP_CONFIG_OPEN_JDK_JRE '[jre: {version: 1.7.0_+}, memory_calculator: {memory_heuristics: {heap: 85, stack: 10}}]'```
3333

config/java_opts.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@
1616
# JAVA_OPTS configuration
1717
---
1818
from_environment: true
19-
# java_opts:
19+
java_opts:

config/open_jdk_jre.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,14 @@ memory_calculator:
2323
version: 1.+
2424
repository_root: ! '{default.repository.root}/memory-calculator/{platform}/{architecture}'
2525
memory_sizes:
26+
heap:
2627
metaspace: 64m..
28+
native:
2729
permgen: 64m..
30+
stack:
2831
memory_heuristics:
2932
heap: 75
3033
metaspace: 10
34+
native: 10
3135
permgen: 10
3236
stack: 5
33-
native: 10

config/oracle_jre.yml

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,25 @@
1515

1616
# Configuration for JRE repositories keyed by vendor
1717
# Pre Java 1.8, permgen was used instead of metaspace. Please see the documentation for more detail.
18-
---
18+
1919
# You must specify a the repository root of an Oracle JRE repository. Please see the documentation for more detail.
2020
# e.g. repository_root: "http://example.com/oracle-jre/{platform}/{architecture}"
21-
21+
---
2222
jre:
2323
version: 1.8.0_+
2424
repository_root: ""
2525
memory_calculator:
2626
version: 1.+
27-
repository_root: "{default.repository.root}/memory-calculator/{platform}/{architecture}"
27+
repository_root: ! '{default.repository.root}/memory-calculator/{platform}/{architecture}'
2828
memory_sizes:
29+
heap:
2930
metaspace: 64m..
31+
native:
3032
permgen: 64m..
33+
stack:
3134
memory_heuristics:
3235
heap: 75
3336
metaspace: 10
37+
native: 10
3438
permgen: 10
3539
stack: 5
36-
native: 10

docs/jre-open_jdk_jre.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ The JRE can be configured by modifying the [`config/open_jdk_jre.yml`][] file in
2626
| `version` | The version of Java runtime to use. Candidate versions can be found in the listings for [centos6][], [lucid][], [mountainlion][], and [precise][]. Note: version 1.8.0 and higher require the `memory_sizes` and `memory_heuristics` mappings to specify `metaspace` rather than `permgen`.
2727

2828
### Additional Resources
29-
The JRE can also be configured by overlaying a set of resources on the default distribution. To do this, add files to the `resources/open_jdk_jre` directory in the buildpack fork. For example, to add the JCE Unlimited Strength `local_policy.jar` add your file to `resources/open_jdk_jre/lib/security/local_policy.jar`.
29+
The JRE can also be configured by overlaying a set of resources on the default distribution. To do this, add files to the `resources/open_jdk_jre` directory in the buildpack fork. For example, to add the JCE Unlimited Strength `local_policy.jar` add your file to `resources/open_jdk_jre/lib/security/local_policy.jar`.
3030

3131
### Memory
3232
The total available memory is specified when an application is pushed as part of it's configuration. The Java buildpack uses this value to control the JRE's use of various regions of memory. The JRE memory settings can be influenced by configuring the `memory_sizes` and/or `memory_heuristics` mappings.
@@ -48,7 +48,7 @@ Memory sizes together with _memory weightings_ (described in the next section) a
4848

4949
Memory sizes consist of a non-negative integer followed by a unit (`k` for kilobytes, `m` for megabytes, `g` for gigabytes; the case is not significant). Only the memory size `0` may be specified without a unit.
5050

51-
The above memory size properties may be omitted, specified as a single value, or specified as a range. Ranges use the syntax `<lower bound>..<upper bound>`, although either bound may be omitted in which case the defaults of zero and the total available memory are used for the lower bound and upper bound, respectively. Examples of ranges are `100m..200m` (any value between 100 and 200 megabytes, inclusive) and `100m..` (any value greater than or equal to 100 megabytes).
51+
The above memory size properties may be omitted with an empty value, specified as a single value, or specified as a range. Ranges use the syntax `<lower bound>..<upper bound>`, although either bound may be omitted in which case the defaults of zero and the total available memory are used for the lower bound and upper bound, respectively. Examples of ranges are `100m..200m` (any value between 100 and 200 megabytes, inclusive) and `100m..` (any value greater than or equal to 100 megabytes).
5252

5353
Each form of memory size is equivalent to a range. Omitting a memory size is equivalent to specifying the range `0..`. Specifying a single value is equivalent to specifying the range with that value as both the lower and upper bound, for example `128m` is equivalent to the range `128m..128m`.
5454

@@ -58,26 +58,28 @@ Memory weightings are configured in the `memory_heuristics` mapping of [`config/
5858
```yaml
5959
memory_heuristics:
6060
heap: 15
61+
native: 2
6162
permgen: 5
6263
stack: 1
63-
native: 2
6464
```
6565
6666
represent a maximum heap size three times as large as the maximum PermGen size, and so on.
6767
6868
Memory weightings are used together with memory ranges to calculate the amount of memory for each memory type, as follows.
6969
7070
#### Memory Calculation
71-
The total available memory is allocated into heap, Metaspace or PermGen (depending on the version of OpenJDK), stack, and native memory types.
71+
Memory calculation happens before every `start` of an application and is performed by an external program, the [Java Buildpack Memory Calculator]. There is no need to `restage` an application after scaling the memory as restarting will cause the memory settings to be recalculated.
72+
73+
The total available memory is allocated into heap, Metaspace or PermGen (depending on the version of Oracle), stack, and native memory types.
7274

73-
The total available memory is allocated to each memory type in proportion to its weighting. If the resultant size of a memory type lies outside its range, the size is constrained to
74-
the range, the constrained size is excluded from the remaining memory, and no further calculation is required for the memory type. If the resultant size of a memory size lies within its range, the size is included in the remaining memory. The remaining memory is then allocated to the remaining memory types in a similar fashion. Allocation terminates when none of the sizes of the remaining memory types is constrained by the corresponding range.
75+
The total available memory is first allocated to each memory type in proportion to its weighting (this is called ‘balancing'). If the resultant size of any memory type lies outside its range, the size is constrained to the range, the constrained size is excluded from the remaining memory, and no further calculation is required for that memory type. The remaining memory is then balanced against the memory types that are left, and the check is repeated until no calculated memory sizes lie outside their ranges. The remaining memory is then allocated to the remaining memory types according to the last balance step. This iteration terminates when none of the sizes of the remaining memory types is constrained by their corresponding ranges.
7576

7677
Termination is guaranteed since there is a finite number of memory types and in each iteration either none of the remaining memory sizes is constrained by the corresponding range and allocation terminates or at least one memory size is constrained by the corresponding range and is omitted from the next iteration.
7778

7879
[`config/open_jdk_jre.yml`]: ../config/open_jdk_jre.yml
7980
[Configuration and Extension]: ../README.md#configuration-and-extension
8081
[centos6]: http://download.pivotal.io.s3.amazonaws.com/openjdk/centos6/x86_64/index.yml
82+
[Java Buildpack Memory Calculator]: https://github.com/cloudfoundry/java-buildpack-memory-calculator
8183
[lucid]: http://download.pivotal.io.s3.amazonaws.com/openjdk/lucid/x86_64/index.yml
8284
[mountainlion]: http://download.pivotal.io.s3.amazonaws.com/openjdk/mountainlion/x86_64/index.yml
8385
[OpenJDK]: http://openjdk.java.net

docs/jre-oracle_jre.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ The JRE can be configured by modifying the [`config/oracle_jre.yml`][] file in t
3535
| `version` | The version of Java runtime to use. Candidate versions can be found in the the repository that you have created to house the JREs. Note: version 1.8.0 and higher require the `memory_sizes` and `memory_heuristics` mappings to specify `metaspace` rather than `permgen`.
3636

3737
### Additional Resources
38-
The JRE can also be configured by overlaying a set of resources on the default distribution. To do this, add files to the `resources/oracle_jre` directory in the buildpack fork. For example, to add the JCE Unlimited Strength `local_policy.jar` add your file to `resources/oracle_jre/lib/security/local_policy.jar`.
38+
The JRE can also be configured by overlaying a set of resources on the default distribution. To do this, add files to the `resources/oracle_jre` directory in the buildpack fork. For example, to add the JCE Unlimited Strength `local_policy.jar` add your file to `resources/oracle_jre/lib/security/local_policy.jar`.
3939

4040
### Memory
4141
The total available memory is specified when an application is pushed as part of it's configuration. The Java buildpack uses this value to control the JRE's use of various regions of memory. The JRE memory settings can be influenced by configuring the `memory_sizes` and/or `memory_heuristics` mappings.
@@ -57,7 +57,7 @@ Memory sizes together with _memory weightings_ (described in the next section) a
5757

5858
Memory sizes consist of a non-negative integer followed by a unit (`k` for kilobytes, `m` for megabytes, `g` for gigabytes; the case is not significant). Only the memory size `0` may be specified without a unit.
5959

60-
The above memory size properties may be omitted, specified as a single value, or specified as a range. Ranges use the syntax `<lower bound>..<upper bound>`, although either bound may be omitted in which case the defaults of zero and the total available memory are used for the lower bound and upper bound, respectively. Examples of ranges are `100m..200m` (any value between 100 and 200 megabytes, inclusive) and `100m..` (any value greater than or equal to 100 megabytes).
60+
The above memory size properties may be omitted with an empty value, specified as a single value, or specified as a range. Ranges use the syntax `<lower bound>..<upper bound>`, although either bound may be omitted in which case the defaults of zero and the total available memory are used for the lower bound and upper bound, respectively. Examples of ranges are `100m..200m` (any value between 100 and 200 megabytes, inclusive) and `100m..` (any value greater than or equal to 100 megabytes).
6161

6262
Each form of memory size is equivalent to a range. Omitting a memory size is equivalent to specifying the range `0..`. Specifying a single value is equivalent to specifying the range with that value as both the lower and upper bound, for example `128m` is equivalent to the range `128m..128m`.
6363

@@ -67,26 +67,28 @@ Memory weightings are configured in the `memory_heuristics` mapping of [`config/
6767
```yaml
6868
memory_heuristics:
6969
heap: 15
70+
native: 2
7071
permgen: 5
7172
stack: 1
72-
native: 2
7373
```
7474
7575
represent a maximum heap size three times as large as the maximum PermGen size, and so on.
7676
7777
Memory weightings are used together with memory ranges to calculate the amount of memory for each memory type, as follows.
7878
7979
#### Memory Calculation
80+
Memory calculation happens before every `start` of an application and is performed by an external program, the [Java Buildpack Memory Calculator]. There is no need to `restage` an application after scaling the memory as restarting will cause the memory settings to be recalculated.
81+
8082
The total available memory is allocated into heap, Metaspace or PermGen (depending on the version of Oracle), stack, and native memory types.
8183

82-
The total available memory is allocated to each memory type in proportion to its weighting. If the resultant size of a memory type lies outside its range, the size is constrained to
83-
the range, the constrained size is excluded from the remaining memory, and no further calculation is required for the memory type. If the resultant size of a memory size lies within its range, the size is included in the remaining memory. The remaining memory is then allocated to the remaining memory types in a similar fashion. Allocation terminates when none of the sizes of the remaining memory types is constrained by the corresponding range.
84+
The total available memory is first allocated to each memory type in proportion to its weighting (this is called ‘balancing'). If the resultant size of any memory type lies outside its range, the size is constrained to the range, the constrained size is excluded from the remaining memory, and no further calculation is required for that memory type. The remaining memory is then balanced against the memory types that are left, and the check is repeated until no calculated memory sizes lie outside their ranges. The remaining memory is then allocated to the remaining memory types according to the last balance step. This iteration terminates when none of the sizes of the remaining memory types is constrained by their corresponding ranges.
8485

8586
Termination is guaranteed since there is a finite number of memory types and in each iteration either none of the remaining memory sizes is constrained by the corresponding range and allocation terminates or at least one memory size is constrained by the corresponding range and is omitted from the next iteration.
8687

8788
[`config/components.yml`]: ../config/components.yml
8889
[`config/oracle_jre.yml`]: ../config/oracle_jre.yml
8990
[Configuration and Extension]: ../README.md#configuration-and-extension
91+
[Java Buildpack Memory Calculator]: https://github.com/cloudfoundry/java-buildpack-memory-calculator
9092
[OpenJDK JRE]: jre-open_jdk_jre.md
9193
[Oracle]: http://www.oracle.com/technetwork/java/index.html
9294
[repositories]: extending-repositories.md

lib/java_buildpack/buildpack_version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class BuildpackVersion
4545

4646
# Creates a new instance
4747
def initialize(should_log = true)
48-
configuration = JavaBuildpack::Util::ConfigurationUtils.load 'version', should_log
48+
configuration = JavaBuildpack::Util::ConfigurationUtils.load('version', true, should_log)
4949
@hash = configuration['hash'] || hash
5050
@offline = configuration['offline'] || ENV['OFFLINE'].to_b
5151
@remote = configuration['remote'] || remote

lib/java_buildpack/framework/java_opts.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def parsed_java_opts
7575
end
7676

7777
def supports_configuration?
78-
@configuration.key? CONFIGURATION_PROPERTY
78+
@configuration.key?(CONFIGURATION_PROPERTY) && !@configuration[CONFIGURATION_PROPERTY].nil?
7979
end
8080

8181
def supports_environment?

lib/java_buildpack/logging/logger_factory.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ def ruby_mode
129129
def severity
130130
severity = ENV['JBP_LOG_LEVEL']
131131
severity = ruby_mode unless severity
132-
severity = JavaBuildpack::Util::ConfigurationUtils.load('logging', false)['default_log_level'] unless severity
132+
severity =
133+
JavaBuildpack::Util::ConfigurationUtils.load('logging', true, false)['default_log_level'] unless severity
133134
severity = 'INFO' unless severity
134135

135136
"::Logger::Severity::#{severity.upcase}".constantize

lib/java_buildpack/util/configuration_utils.rb

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,17 @@ class << self
3535
# configuration, if present. Will not add a new configuration key where an existing one does not exist.
3636
#
3737
# @param [String] identifier the identifier of the configuration to load
38+
# @param [Boolean] clean_nil_values whether empty/nil values should be removed along with their keys from the
39+
# returned configuration.
3840
# @param [Boolean] should_log whether the contents of the configuration file should be logged. This value
3941
# should be left to its default and exists to allow the logger to use the utility.
4042
# @return [Hash] the configuration or an empty hash if the configuration file does not exist
41-
def load(identifier, should_log = true)
43+
def load(identifier, clean_nil_values = true, should_log = true)
4244
file = file_name(identifier)
4345

4446
if file.exist?
4547
user_provided = ENV[environment_variable_name(identifier)]
46-
configuration = load_configuration(file, user_provided, should_log)
48+
configuration = load_configuration(file, user_provided, clean_nil_values, should_log)
4749
else
4850
logger.debug { "No configuration file #{file} found" } if should_log
4951
end
@@ -80,6 +82,17 @@ def write(identifier, new_content, should_log = true)
8082

8183
private_constant :CONFIG_DIRECTORY, :ENVIRONMENT_VARIABLE_PATTERN
8284

85+
def clean_nil_values(configuration)
86+
configuration.each do |key, value|
87+
if value.is_a?(Hash)
88+
configuration[key] = clean_nil_values value
89+
elsif value.nil?
90+
configuration.delete key
91+
end
92+
end
93+
configuration
94+
end
95+
8396
def file_name(identifier)
8497
CONFIG_DIRECTORY + "#{identifier}.yml"
8598
end
@@ -96,7 +109,7 @@ def header(file)
96109
header
97110
end
98111

99-
def load_configuration(file, user_provided, should_log)
112+
def load_configuration(file, user_provided, clean_nil_values, should_log)
100113
configuration = YAML.load_file(file)
101114
logger.debug { "Configuration from #{file}: #{configuration}" } if should_log
102115

@@ -105,15 +118,14 @@ def load_configuration(file, user_provided, should_log)
105118
if user_provided_value.is_a?(Hash)
106119
configuration = do_merge(configuration, user_provided_value, should_log)
107120
elsif user_provided_value.is_a?(Array)
108-
user_provided_value.each do |new_prop|
109-
configuration = do_merge(configuration, new_prop, should_log)
110-
end
121+
user_provided_value.each { |new_prop| configuration = do_merge(configuration, new_prop, should_log) }
111122
else
112123
fail "User configuration value is not valid: #{user_provided_value}"
113124
end
114125
logger.debug { "Configuration from #{file} modified with: #{user_provided}" } if should_log
115126
end
116127

128+
clean_nil_values configuration if clean_nil_values
117129
configuration
118130
end
119131

0 commit comments

Comments
 (0)