diff --git a/.idea/dictionaries/bhale.xml b/.idea/dictionaries/bhale.xml index 42f7cc42eb..bf6ad475e0 100644 --- a/.idea/dictionaries/bhale.xml +++ b/.idea/dictionaries/bhale.xml @@ -65,6 +65,7 @@ myhost mypass myuser + networkaddress newrelic newrelicagent overweaving diff --git a/.rubocop.yml b/.rubocop.yml index 236b840043..e9846b9ead 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -31,9 +31,9 @@ Metrics/CyclomaticComplexity: Metrics/LineLength: Max: 120 Metrics/MethodLength: - Max: 20 + Max: 25 Metrics/ParameterLists: - Max: 8 + Max: 10 Metrics/PerceivedComplexity: Max: 10 RSpec/ExampleLength: diff --git a/config/components.yml b/config/components.yml index ec8c8ff1f0..13e389518b 100644 --- a/config/components.yml +++ b/config/components.yml @@ -66,5 +66,5 @@ frameworks: - "JavaBuildpack::Framework::SpringInsight" - "JavaBuildpack::Framework::YourKitProfiler" - "JavaBuildpack::Framework::TakipiAgent" - - "JavaBuildpack::Framework::SecurityProviders" + - "JavaBuildpack::Framework::JavaSecurity" - "JavaBuildpack::Framework::JavaOpts" diff --git a/lib/java_buildpack/buildpack.rb b/lib/java_buildpack/buildpack.rb index e7083fa7c0..0a19c140d5 100644 --- a/lib/java_buildpack/buildpack.rb +++ b/lib/java_buildpack/buildpack.rb @@ -23,6 +23,7 @@ require 'java_buildpack/component/immutable_java_home' require 'java_buildpack/component/java_opts' require 'java_buildpack/component/mutable_java_home' +require 'java_buildpack/component/networking' require 'java_buildpack/component/security_providers' require 'java_buildpack/logging/logger_factory' require 'java_buildpack/util/cache/application_cache' @@ -131,6 +132,7 @@ def initialize(app_dir, application) 'env_vars' => Component::EnvironmentVariables.new(app_dir), 'extension_directories' => Component::ExtensionDirectories.new(app_dir), 'java_opts' => @java_opts, + 'networking' => Component::Networking.new, 'security_providers' => Component::SecurityProviders.new } @@ -181,7 +183,7 @@ def instantiate(components, java_home, component_info) droplet: Component::Droplet.new(component_info['additional_libraries'], component_id, component_info['env_vars'], component_info['extension_directories'], java_home, component_info['java_opts'], component_info['app_dir'], - component_info['security_providers']) + component_info['networking'], component_info['security_providers']) } component.constantize.new(context) end diff --git a/lib/java_buildpack/component/droplet.rb b/lib/java_buildpack/component/droplet.rb index 4f602a8434..db8f90a4b3 100644 --- a/lib/java_buildpack/component/droplet.rb +++ b/lib/java_buildpack/component/droplet.rb @@ -56,6 +56,10 @@ class Droplet # @return [JavaOpts] the shared +JavaOpts+ instance for all components attr_reader :java_opts + # @!attribute [r] networking + # @return [Networking] the shared +Networking+ instance for all components + attr_reader :networking + # @!attribute [r] root # @return [JavaBuildpack::Util::FilteringPathname] the root of the droplet's fileystem filtered so that it # excludes files in the sandboxes of other components @@ -83,10 +87,11 @@ class Droplet # be an instance of +MutableJavaHome+. Otherwise it should # be an instance of +ImmutableJavaHome+. # @param [JavaOpts] java_opts the shared +JavaOpts+ instance for all components + # @param [Networking] networking the shared +Networking+ instance for all components # @param [Pathname] root the root of the droplet # @param [SecurityProviders] security_providers the shared +SecurityProviders+ instance for all components def initialize(additional_libraries, component_id, env_vars, extension_directories, java_home, java_opts, root, - security_providers) + networking, security_providers) @additional_libraries = additional_libraries @component_id = component_id @@ -110,6 +115,7 @@ def initialize(additional_libraries, component_id, env_vars, extension_directori ->(path) { !in?(path, buildpack_root) || in?(path, @sandbox) }, true ) + @networking = networking @security_providers = security_providers end diff --git a/lib/java_buildpack/component/networking.rb b/lib/java_buildpack/component/networking.rb new file mode 100644 index 0000000000..7809ba3345 --- /dev/null +++ b/lib/java_buildpack/component/networking.rb @@ -0,0 +1,54 @@ +# Cloud Foundry Java Buildpack +# Copyright 2013-2017 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 +# +# http://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. + +require 'fileutils' +require 'java_buildpack/component' + +module JavaBuildpack + module Component + + # An abstraction around the networking configuration provided to a droplet by components. + # + # A new instance of this type should be created once for the application. + class Networking + + # @!attribute [rw] networkaddress_cache_ttl + # @return [Integer] the number of seconds to cache the successful lookup + attr_accessor :networkaddress_cache_ttl + + # @!attribute [rw] networkaddress_cache_negative_ttl + # @return [Integer] the number of seconds to cache the failure for un-successful lookups + attr_accessor :networkaddress_cache_negative_ttl + + # Write the networking configuration to a destination file + # + # @param [Pathname] destination the destination to write to + # @return [Void] + def write_to(destination) + FileUtils.mkdir_p destination.parent + + destination.open(File::CREAT | File::APPEND | File::WRONLY) do |f| + f.write "networkaddress.cache.ttl=#{@networkaddress_cache_ttl}\n" if @networkaddress_cache_ttl + + if @networkaddress_cache_negative_ttl + f.write "networkaddress.cache.negative.ttl=#{networkaddress_cache_negative_ttl}\n" + end + end + end + + end + + end +end diff --git a/lib/java_buildpack/component/security_providers.rb b/lib/java_buildpack/component/security_providers.rb index df7f26fcdd..097f118ccf 100644 --- a/lib/java_buildpack/component/security_providers.rb +++ b/lib/java_buildpack/component/security_providers.rb @@ -31,7 +31,7 @@ class SecurityProviders < Array def write_to(destination) FileUtils.mkdir_p destination.parent - destination.open(File::CREAT | File::WRONLY) do |f| + destination.open(File::CREAT | File::APPEND | File::WRONLY) do |f| each_with_index { |security_provider, index| f.write "security.provider.#{index + 1}=#{security_provider}\n" } end end diff --git a/lib/java_buildpack/framework/security_providers.rb b/lib/java_buildpack/framework/java_security.rb similarity index 91% rename from lib/java_buildpack/framework/security_providers.rb rename to lib/java_buildpack/framework/java_security.rb index 12a4e1b7ef..89e4d5b2e3 100644 --- a/lib/java_buildpack/framework/security_providers.rb +++ b/lib/java_buildpack/framework/java_security.rb @@ -21,15 +21,16 @@ module JavaBuildpack module Framework # Encapsulates the functionality for contributing custom Security Providers to an application. - class SecurityProviders < JavaBuildpack::Component::BaseComponent + class JavaSecurity < JavaBuildpack::Component::BaseComponent # (see JavaBuildpack::Component::BaseComponent#detect) def detect - SecurityProviders.to_s.dash_case + JavaSecurity.to_s.dash_case end # (see JavaBuildpack::Component::BaseComponent#compile) def compile + @droplet.networking.write_to java_security @droplet.security_providers.write_to java_security end diff --git a/lib/java_buildpack/jre/open_jdk_like_jre.rb b/lib/java_buildpack/jre/open_jdk_like_jre.rb index 424687050b..839db2865d 100644 --- a/lib/java_buildpack/jre/open_jdk_like_jre.rb +++ b/lib/java_buildpack/jre/open_jdk_like_jre.rb @@ -13,10 +13,12 @@ # See the License for the specific language governing permissions and # limitations under the License. +require 'ipaddr' require 'fileutils' require 'java_buildpack/component/versioned_dependency_component' require 'java_buildpack/jre' require 'java_buildpack/util/tokenized_version' +require 'resolv' module JavaBuildpack module Jre @@ -48,6 +50,7 @@ def detect def compile download_tar @droplet.copy_resources + disable_dns_caching if link_local_dns? return if @droplet.java_home.java_8_or_later? @@ -62,6 +65,25 @@ def release .add_system_property('java.io.tmpdir', '$TMPDIR') end + private + + LINK_LOCAL = IPAddr.new('169.254.0.0/16').freeze + + private_constant :LINK_LOCAL + + def disable_dns_caching + puts ' JVM DNS caching disabled in lieu of BOSH DNS caching' + + @droplet.networking.networkaddress_cache_ttl = 0 + @droplet.networking.networkaddress_cache_negative_ttl = 0 + end + + def link_local_dns? + Resolv::DNS::Config.new.lazy_initialize.nameserver_port.any? do |nameserver_port| + LINK_LOCAL.include? IPAddr.new(nameserver_port[0]) + end + end + end end diff --git a/spec/droplet_helper.rb b/spec/droplet_helper.rb index 18490ee3ea..f85e860910 100644 --- a/spec/droplet_helper.rb +++ b/spec/droplet_helper.rb @@ -22,6 +22,7 @@ require 'java_buildpack/component/extension_directories' require 'java_buildpack/component/immutable_java_home' require 'java_buildpack/component/java_opts' +require 'java_buildpack/component/networking' require 'java_buildpack/component/security_providers' require 'java_buildpack/util/snake_case' require 'pathname' @@ -38,7 +39,8 @@ let(:droplet) do JavaBuildpack::Component::Droplet.new(additional_libraries, component_id, environment_variables, - extension_directories, java_home, java_opts, app_dir, security_providers) + extension_directories, java_home, java_opts, app_dir, networking, + security_providers) end let(:extension_directories) { JavaBuildpack::Component::ExtensionDirectories.new app_dir } @@ -62,6 +64,8 @@ java_opts end + let(:networking) { JavaBuildpack::Component::Networking.new } + let(:security_providers) { JavaBuildpack::Component::SecurityProviders.new } before do diff --git a/spec/fixtures/framework_java_security_networking b/spec/fixtures/framework_java_security_networking new file mode 100644 index 0000000000..60738b2246 --- /dev/null +++ b/spec/fixtures/framework_java_security_networking @@ -0,0 +1,4 @@ +networkaddress.cache.ttl=-1 +networkaddress.cache.negative.ttl=-2 +security.provider.1=test-security-provider-1 +security.provider.2=test-security-provider-2 diff --git a/spec/fixtures/framework_java_security_security_providers b/spec/fixtures/framework_java_security_security_providers new file mode 100644 index 0000000000..b4e7d7fc84 --- /dev/null +++ b/spec/fixtures/framework_java_security_security_providers @@ -0,0 +1,2 @@ +security.provider.1=test-security-provider-1 +security.provider.2=test-security-provider-2 diff --git a/spec/java_buildpack/framework/security_providers_spec.rb b/spec/java_buildpack/framework/java_security_spec.rb similarity index 58% rename from spec/java_buildpack/framework/security_providers_spec.rb rename to spec/java_buildpack/framework/java_security_spec.rb index aaac041450..050298461e 100644 --- a/spec/java_buildpack/framework/security_providers_spec.rb +++ b/spec/java_buildpack/framework/java_security_spec.rb @@ -16,28 +16,40 @@ require 'spec_helper' require 'component_helper' require 'fileutils' -require 'java_buildpack/framework/security_providers' +require 'java_buildpack/framework/java_security' -describe JavaBuildpack::Framework::SecurityProviders do +describe JavaBuildpack::Framework::JavaSecurity do include_context 'component_helper' it 'adds extension directories to system properties' do component.release - expect(java_opts).to include('-Djava.ext.dirs=$PWD/.java-buildpack/security_providers/test-extension-directory-1:' \ - '$PWD/.java-buildpack/security_providers/test-extension-directory-2') + expect(java_opts).to include('-Djava.ext.dirs=$PWD/.java-buildpack/java_security/test-extension-directory-1:' \ + '$PWD/.java-buildpack/java_security/test-extension-directory-2') end - it 'writes new security properties' do + it 'writes security provider security properties' do component.compile expect(sandbox + 'java.security').to exist + expect(File.read(sandbox + 'java.security')) + .to eq File.read('spec/fixtures/framework_java_security_security_providers') + end + + it 'writes networking security properties' do + networking.networkaddress_cache_ttl = -1 + networking.networkaddress_cache_negative_ttl = -2 + + component.compile + + expect(sandbox + 'java.security').to exist + expect(File.read(sandbox + 'java.security')).to eq File.read('spec/fixtures/framework_java_security_networking') end it 'adds security properties to system properties' do component.release - expect(java_opts).to include('-Djava.security.properties=$PWD/.java-buildpack/security_providers/' \ + expect(java_opts).to include('-Djava.security.properties=$PWD/.java-buildpack/java_security/' \ 'java.security') end diff --git a/spec/java_buildpack/jre/open_jdk_like_jre_spec.rb b/spec/java_buildpack/jre/open_jdk_like_jre_spec.rb index 3504ac04c7..dba74a01d8 100644 --- a/spec/java_buildpack/jre/open_jdk_like_jre_spec.rb +++ b/spec/java_buildpack/jre/open_jdk_like_jre_spec.rb @@ -17,6 +17,7 @@ require 'component_helper' require 'java_buildpack/component/mutable_java_home' require 'java_buildpack/jre/open_jdk_like_jre' +require 'resolv' describe JavaBuildpack::Jre::OpenJDKLikeJre do include_context 'component_helper' @@ -49,4 +50,26 @@ expect(java_opts).to include('-Djava.io.tmpdir=$TMPDIR') end + it 'does not disable dns caching if no BOSH DNS', + cache_fixture: 'stub-java.tar.gz' do + + component.detect + component.compile + + expect(networking.networkaddress_cache_ttl).not_to be + expect(networking.networkaddress_cache_negative_ttl).not_to be + end + + it 'disables dns caching if BOSH DNS', + cache_fixture: 'stub-java.tar.gz' do + + allow_any_instance_of(Resolv::DNS::Config).to receive(:nameserver_port).and_return([['169.254.0.2', 53]]) + + component.detect + component.compile + + expect(networking.networkaddress_cache_ttl).to eq 0 + expect(networking.networkaddress_cache_negative_ttl).to eq 0 + end + end