diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 45fd68eac..3d20c859f 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -1,11 +1,28 @@ + + + + diff --git a/lib/java_buildpack/buildpack.rb b/lib/java_buildpack/buildpack.rb index a06a3d404..69827e412 100644 --- a/lib/java_buildpack/buildpack.rb +++ b/lib/java_buildpack/buildpack.rb @@ -73,6 +73,14 @@ def compile container.compile log_cache_contents + + return if @deps_dir.nil? || @index.nil? + + FileUtils.mkdir_p File.join(@deps_dir, @index) + File.write( + File.join(@deps_dir, @index, 'config.yml'), + { 'name' => 'java', 'config' => {}, 'version' => @buildpack_version.to_s(false) }.to_yaml + ) end # Generates the payload required to run the application. The payload format is defined by the @@ -114,9 +122,11 @@ def release private_constant :BUILDPACK_MESSAGE, :LOAD_ROOT - def initialize(app_dir, application) + def initialize(app_dir, deps_dir, index, application) @logger = Logging::LoggerFactory.instance.get_logger Buildpack @buildpack_version = BuildpackVersion.new + @deps_dir = deps_dir + @index = index log_arguments log_environment_variables @@ -260,12 +270,12 @@ class << self # @param [String] message an error message with an insert for the reason for failure # @yield [Buildpack] the buildpack to work with # @return [Object] the return value from the given block - def with_buildpack(app_dir, message) + def with_buildpack(app_dir, deps_dir, index, message) app_dir = Pathname.new(File.expand_path(app_dir)) Logging::LoggerFactory.instance.setup app_dir application = Component::Application.new(app_dir) - yield new(app_dir, application) if block_given? + yield new(app_dir, deps_dir, index, application) if block_given? rescue StandardError => e handle_error(e, message) end diff --git a/lib/java_buildpack/buildpack_version.rb b/lib/java_buildpack/buildpack_version.rb index 76501b7f5..f406a6014 100644 --- a/lib/java_buildpack/buildpack_version.rb +++ b/lib/java_buildpack/buildpack_version.rb @@ -85,7 +85,7 @@ def to_hash # @return [String] a +String+ representation of the version def to_s(human_readable = true) s = [] - s << @version.blue if @version + s << (human_readable ? @version.blue : @version) if @version s << (human_readable ? '(offline)'.blue : 'offline') if @offline if remote_string diff --git a/lib/java_buildpack/container/dist_zip_like.rb b/lib/java_buildpack/container/dist_zip_like.rb index d38d3aded..14f071736 100644 --- a/lib/java_buildpack/container/dist_zip_like.rb +++ b/lib/java_buildpack/container/dist_zip_like.rb @@ -47,7 +47,8 @@ def release @droplet.environment_variables.as_env_vars, @droplet.java_home.as_env_var, 'exec', - qualify_path(start_script(root), @droplet.root) + qualify_path(start_script(root), @droplet.root), + arguments ].flatten.compact.join(' ') end @@ -76,11 +77,17 @@ def supports? private + ARGUMENTS_PROPERTY = 'arguments' + PATTERN_APP_CLASSPATH = /^declare -r app_classpath=\"(.*)\"$/.freeze PATTERN_CLASSPATH = /^CLASSPATH=(.*)$/.freeze - private_constant :PATTERN_APP_CLASSPATH, :PATTERN_CLASSPATH + private_constant :ARGUMENTS_PROPERTY, :PATTERN_APP_CLASSPATH, :PATTERN_CLASSPATH + + def arguments + @configuration[ARGUMENTS_PROPERTY] + end def augment_app_classpath(content) additional_classpath = (@droplet.additional_libraries + @droplet.root_libraries).sort.map do |library| diff --git a/lib/java_buildpack/container/tomcat/tomcat_geode_store.rb b/lib/java_buildpack/container/tomcat/tomcat_geode_store.rb index 406bcc384..31ddfc84c 100644 --- a/lib/java_buildpack/container/tomcat/tomcat_geode_store.rb +++ b/lib/java_buildpack/container/tomcat/tomcat_geode_store.rb @@ -63,7 +63,7 @@ def supports? KEY_LOCATORS = 'locators' KEY_USERS = 'users' - SESSION_MANAGER_CLASS_NAME = 'org.apache.geode.modules.session.catalina.Tomcat8DeltaSessionManager' + SESSION_MANAGER_CLASS_NAME = 'org.apache.geode.modules.session.catalina.Tomcat9DeltaSessionManager' REGION_ATTRIBUTES_ID = 'PARTITION_REDUNDANT_HEAP_LRU' CACHE_CLIENT_LISTENER_CLASS_NAME = 'org.apache.geode.modules.session.catalina.ClientServerCacheLifecycleListener' @@ -71,16 +71,10 @@ def supports? SCHEMA_INSTANCE_URL = 'http://www.w3.org/2001/XMLSchema-instance' SCHEMA_LOCATION = 'http://geode.apache.org/schema/cache http://geode.apache.org/schema/cache/cache-1.0.xsd' LOCATOR_REGEXP = Regexp.new('([^\\[]+)\\[([^\\]]+)\\]').freeze - FUNCTION_SERVICE_CLASS_NAMES = [ - 'org.apache.geode.modules.util.CreateRegionFunction', - 'org.apache.geode.modules.util.TouchPartitionedRegionEntriesFunction', - 'org.apache.geode.modules.util.TouchReplicatedRegionEntriesFunction', - 'org.apache.geode.modules.util.RegionSizeFunction' - ].freeze private_constant :FILTER, :KEY_LOCATORS, :KEY_USERS, :SESSION_MANAGER_CLASS_NAME, :REGION_ATTRIBUTES_ID, :CACHE_CLIENT_LISTENER_CLASS_NAME, :SCHEMA_URL, :SCHEMA_INSTANCE_URL, :SCHEMA_LOCATION, - :LOCATOR_REGEXP, :FUNCTION_SERVICE_CLASS_NAMES + :LOCATOR_REGEXP def cluster_operator?(user) user['username'] == 'cluster_operator' || user['roles'] && (user['roles'].include? 'cluster_operator') @@ -94,20 +88,6 @@ def add_client_cache(document) 'version' => '1.0' add_pool client_cache - add_function_service client_cache - end - - def add_functions(function_service) - FUNCTION_SERVICE_CLASS_NAMES.each do |function_class_name| - function = function_service.add_element 'function' - class_name = function.add_element 'class-name' - class_name.add_text(function_class_name) - end - end - - def add_function_service(client_cache) - function_service = client_cache.add_element 'function-service' - add_functions function_service end def add_listener(server) diff --git a/lib/java_buildpack/framework/app_dynamics_agent.rb b/lib/java_buildpack/framework/app_dynamics_agent.rb index 82aafa4fb..ed763db97 100644 --- a/lib/java_buildpack/framework/app_dynamics_agent.rb +++ b/lib/java_buildpack/framework/app_dynamics_agent.rb @@ -39,7 +39,8 @@ def compile default_conf_dir = resources_dir + @droplet.component_id + 'defaults' copy_appd_default_configuration(default_conf_dir) - override_default_config_if_applicable + override_default_config_remote + override_default_config_local @droplet.copy_resources end @@ -80,7 +81,7 @@ def supports? def application_name(java_opts, credentials) name = credentials['application-name'] || @configuration['default_application_name'] || @application.details['application_name'] - java_opts.add_system_property('appdynamics.agent.applicationName', name.to_s) + java_opts.add_system_property('appdynamics.agent.applicationName', "\\\"#{name}\\\"") end def account_access_key(java_opts, credentials) @@ -145,8 +146,13 @@ def copy_appd_default_configuration(default_conf_dir) def check_if_resource_exists(resource_uri, conf_file) # check if resource exists on remote server begin - response = Net::HTTP.start(resource_uri.host, resource_uri.port) do |http| - http.request_head(resource_uri) + opts = { use_ssl: true } if resource_uri.scheme == 'https' + response = Net::HTTP.start(resource_uri.host, resource_uri.port, opts) do |http| + req = Net::HTTP::Head.new(resource_uri) + if resource_uri.user != '' || resource_uri.password != '' + req.basic_auth(resource_uri.user, resource_uri.password) + end + http.request(req) end rescue StandardError => e @logger.error { "Request failure: #{e.message}" } @@ -155,37 +161,62 @@ def check_if_resource_exists(resource_uri, conf_file) case response when Net::HTTPSuccess - return true + true when Net::HTTPRedirection location = response['location'] @logger.info { "redirected to #{location}" } - return check_if_resource_exists(location, conf_file) + check_if_resource_exists(location, conf_file) else @logger.info { "Could not retrieve #{resource_uri}. Code: #{response.code} Message: #{response.message}" } - return false + false end end # Check for configuration files on a remote server. If found, copy to conf dir under each ver* dir # @return [Void] - def override_default_config_if_applicable + def override_default_config_remote return unless @application.environment['APPD_CONF_HTTP_URL'] - agent_root = @application.environment['APPD_CONF_HTTP_URL'].chomp('/') + '/java/' - @logger.info { "Downloading override configuration files from #{agent_root}" } + JavaBuildpack::Util::Cache::InternetAvailability.instance.available( + true, 'The AppDynamics remote configuration download location is always accessible' + ) do + agent_root = @application.environment['APPD_CONF_HTTP_URL'].chomp('/') + '/java/' + @logger.info { "Downloading override configuration files from #{agent_root}" } + CONFIG_FILES.each do |conf_file| + uri = URI(agent_root + conf_file) + + # `download()` uses retries with exponential backoff which is expensive + # for situations like 404 File not Found. Also, `download()` doesn't expose + # an api to disable retries, which makes this check necessary to prevent + # long install times. + next unless check_if_resource_exists(uri, conf_file) + + download(false, uri.to_s) do |file| + Dir.glob(@droplet.sandbox + 'ver*') do |target_directory| + FileUtils.cp_r file, target_directory + '/conf/' + conf_file + end + end + end + end + end + + # Check for configuration files locally. If found, copy to conf dir under each ver* dir + # @return [Void] + def override_default_config_local + return unless @application.environment['APPD_CONF_DIR'] + + app_conf_dir = @application.root + @application.environment['APPD_CONF_DIR'] + + raise "AppDynamics configuration source dir #{app_conf_dir} does not exist" unless Dir.exist?(app_conf_dir) + + @logger.info { "Copy override configuration files from #{app_conf_dir}" } CONFIG_FILES.each do |conf_file| - uri = URI(agent_root + conf_file) + conf_file_path = app_conf_dir + conf_file - # `download()` uses retries with exponential backoff which is expensive - # for situations like 404 File not Found. Also, `download()` doesn't expose - # an api to disable retries, which makes this check necessary to prevent - # long install times. - next unless check_if_resource_exists(uri, conf_file) + next unless File.file?(conf_file_path) - download(false, uri.to_s) do |file| - Dir.glob(@droplet.sandbox + 'ver*') do |target_directory| - FileUtils.cp_r file, target_directory + '/conf/' + conf_file - end + Dir.glob(@droplet.sandbox + 'ver*') do |target_directory| + FileUtils.cp_r conf_file_path, target_directory + '/conf/' + conf_file end end end diff --git a/lib/java_buildpack/framework/checkmarx_iast_agent.rb b/lib/java_buildpack/framework/checkmarx_iast_agent.rb new file mode 100644 index 000000000..b92e7afa8 --- /dev/null +++ b/lib/java_buildpack/framework/checkmarx_iast_agent.rb @@ -0,0 +1,98 @@ +# frozen_string_literal: true + +# Cloud Foundry Java Buildpack +# Copyright 2013-2020 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 'java_buildpack/component/versioned_dependency_component' +require 'java_buildpack/framework' + +module JavaBuildpack + module Framework + + # Encapsulates the functionality for running with Checkmarx IAST Agent + class CheckmarxIastAgent < JavaBuildpack::Component::VersionedDependencyComponent + include JavaBuildpack::Util + + # Creates an instance. In addition to the functionality inherited from +BaseComponent+, +@version+ and +@uri+ + # instance variables are exposed. + # + # @param [Hash] context a collection of utilities used by components + def initialize(context) + @application = context[:application] + @component_name = self.class.to_s.space_case + @configuration = context[:configuration] + @droplet = context[:droplet] + + if supports? + @version = '' + @uri = @application.services.find_service(FILTER, 'server')['credentials']['server'].chomp + + '/iast/compilation/download/JAVA' + end + + @logger = JavaBuildpack::Logging::LoggerFactory.instance.get_logger CheckmarxIastAgent + end + + # (see JavaBuildpack::Component::BaseComponent#compile) + def compile + JavaBuildpack::Util::Cache::InternetAvailability.instance.available( + true, 'The Checkmarx IAST download location is always accessible' + ) do + download_zip(false) + end + + # Disable cache (no point, when running in a container) + File.open(@droplet.sandbox + 'cx_agent.override.properties', 'a') do |f| + f.write("\nenableWeavedClassCache=false\n") + end + end + + # (see JavaBuildpack::Component::BaseComponent#release) + def release + # Default cxAppTag to application name if not set as an env var + app_tag = ENV['cxAppTag'] || application_name + # Default team to CxServer if not set as env var + team = ENV['cxTeam'] || 'CxServer' + + @droplet.java_opts + .add_javaagent(@droplet.sandbox + 'cx-launcher.jar') + .add_preformatted_options('-Xverify:none') + .add_system_property('cx.logToConsole', 'true') + .add_system_property('cx.appName', application_name) + .add_system_property('cxAppTag', app_tag) + .add_system_property('cxTeam', team) + end + + protected + + # (see JavaBuildpack::Component::VersionedDependencyComponent#supports?) + def supports? + @application.services.find_service(FILTER, 'server') + end + + private + + FILTER = /^checkmarx-iast$/.freeze + + private_constant :FILTER + + def application_name + @application.details['application_name'] || 'ROOT' + end + + end + + end + +end diff --git a/lib/java_buildpack/framework/introscope_agent.rb b/lib/java_buildpack/framework/introscope_agent.rb index 25503d69e..3e43ce13f 100644 --- a/lib/java_buildpack/framework/introscope_agent.rb +++ b/lib/java_buildpack/framework/introscope_agent.rb @@ -125,7 +125,7 @@ def agent_manager_credential(credentials) end def export_all_properties(credentials, java_opts) - credentials.keys.each do |key| + credentials.each_key do |key| correct_key = key.tr('_', '.') if %w[agentManager.url.1 agent.manager.url].include?(correct_key) add_url(credentials, java_opts) diff --git a/lib/java_buildpack/framework/java_memory_assistant/agent.rb b/lib/java_buildpack/framework/java_memory_assistant/agent.rb index 89054fc54..825d34bb1 100644 --- a/lib/java_buildpack/framework/java_memory_assistant/agent.rb +++ b/lib/java_buildpack/framework/java_memory_assistant/agent.rb @@ -42,13 +42,24 @@ def release .add_system_property('jma.heap_dump_name', %("#{name_pattern}")) .add_system_property 'jma.log_level', normalized_log_level + if @droplet.java_home.java_9_or_later? + # Enable access to com.sun.management.HotSpotDiagnosticMXBean to circumvent + # Java modules limitations in Java 9+ + # See https://github.com/SAP/java-memory-assistant#running-the-java-memory-assistant-on-java-11 + @droplet.java_opts + .add_preformatted_options('--add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED') + end + add_system_prop_if_config_present 'check_interval', 'jma.check_interval' - add_system_prop_if_config_present 'max_frequency', 'jma.max_frequency' + + if @configuration.key?('max_frequency') + @droplet.java_opts.add_preformatted_options "'-Djma.max_frequency=#{@configuration['max_frequency']}'" + end return unless @configuration.key?('thresholds') @configuration['thresholds'].each do |key, value| - @droplet.java_opts.add_system_property "jma.thresholds.#{key}", value.to_s + @droplet.java_opts.add_preformatted_options "'-Djma.thresholds.#{key}=#{value}'" end end diff --git a/lib/java_buildpack/framework/riverbed_appinternals_agent.rb b/lib/java_buildpack/framework/riverbed_appinternals_agent.rb index f8e832f45..71e502af7 100644 --- a/lib/java_buildpack/framework/riverbed_appinternals_agent.rb +++ b/lib/java_buildpack/framework/riverbed_appinternals_agent.rb @@ -18,30 +18,17 @@ require 'fileutils' require 'java_buildpack/component/versioned_dependency_component' require 'java_buildpack/framework' + module JavaBuildpack module Framework # Encapsulates the functionality for running the Riverbed Appinternals Agent support. class RiverbedAppinternalsAgent < JavaBuildpack::Component::VersionedDependencyComponent - # Creates an instance - # - # @param [Hash] context a collection of utilities used the component - def initialize(context) - super(context) - @uri = download_url(credentials, @uri) - end - # (see JavaBuildpack::Component::BaseComponent#compile) def compile - JavaBuildpack::Util::Cache::InternetAvailability.instance.available( - true, 'Downloading from Riverbed AppInternals Service Broker' - ) do - download_zip(false, @droplet.sandbox, @component_name) - end + download_zip(false, @droplet.sandbox, @component_name) @droplet.copy_resources - rescue StandardError => e - raise "Riverbed AppInternals download failed: #{e}" end # (see JavaBuildpack::Component::BaseComponent#release) @@ -69,8 +56,6 @@ def supports? private - PROFILERURL = 'profilerUrlLinux' - FILTER = /appinternals/.freeze private_constant :FILTER @@ -107,10 +92,6 @@ def rvbd_moniker(credentials) credentials['rvbd_moniker'] || @configuration['rvbd_moniker'] end - def download_url(credentials, default_url) - (credentials[PROFILERURL] unless credentials.nil?) || default_url - end - end end end diff --git a/lib/java_buildpack/util/cache/download_cache.rb b/lib/java_buildpack/util/cache/download_cache.rb index a961097bc..81faffd7d 100644 --- a/lib/java_buildpack/util/cache/download_cache.rb +++ b/lib/java_buildpack/util/cache/download_cache.rb @@ -314,8 +314,11 @@ def proxy(uri) URI.parse(ENV['http_proxy'] || ENV['HTTP_PROXY'] || '') end - @logger.debug { "Proxy: #{proxy_uri.host}, #{proxy_uri.port}, #{proxy_uri.user}, #{proxy_uri.password}" } - Net::HTTP::Proxy(proxy_uri.host, proxy_uri.port, proxy_uri.user, proxy_uri.password) + proxy_user = proxy_uri.user ? URI.decode_www_form_component(proxy_uri.user) : nil + proxy_pass = proxy_uri.password ? URI.decode_www_form_component(proxy_uri.password) : nil + + @logger.debug { "Proxy: #{proxy_uri.host}, #{proxy_uri.port}, #{proxy_user}, #{proxy_pass}" } + Net::HTTP::Proxy(proxy_uri.host, proxy_uri.port, proxy_user, proxy_pass) end def redirect?(response) diff --git a/rakelib/dependency_cache_task.rb b/rakelib/dependency_cache_task.rb index 415411fa2..2a497e239 100644 --- a/rakelib/dependency_cache_task.rb +++ b/rakelib/dependency_cache_task.rb @@ -132,7 +132,7 @@ def configurations(component_id, configuration, sub_component_id = nil) if component_id == 'open_jdk_jre' && sub_component_id == 'jre' c1 = configuration.clone - c1['version'] = '13.+' + c1['version'] = '15.+' configurations << c1 end diff --git a/rakelib/versions_task.rb b/rakelib/versions_task.rb index 1c487109b..bfd1df31f 100644 --- a/rakelib/versions_task.rb +++ b/rakelib/versions_task.rb @@ -72,7 +72,7 @@ def initialize 'jprofiler_profiler' => 'JProfiler Profiler', 'jre' => 'OpenJDK JRE', 'jre-11' => 'OpenJDK JRE 11', - 'jre-13' => 'OpenJDK JRE 13', + 'jre-15' => 'OpenJDK JRE 15', 'jrebel_agent' => 'JRebel Agent', 'jvmkill_agent' => 'jvmkill Agent', 'lifecycle_support' => 'Tomcat Lifecycle Support', @@ -167,8 +167,8 @@ def configurations(component_id, configuration, sub_component_id = nil) if component_id == 'open_jdk_jre' && sub_component_id == 'jre' c1 = configuration.clone - c1['sub_component_id'] = 'jre-13' - c1['version'] = '13.+' + c1['sub_component_id'] = 'jre-15' + c1['version'] = '15.+' configurations << c1 end diff --git a/spec/fixtures/container_tomcat_geode_store_cache_client_after.xml b/spec/fixtures/container_tomcat_geode_store_cache_client_after.xml index b68c11814..41e41f161 100644 --- a/spec/fixtures/container_tomcat_geode_store_cache_client_after.xml +++ b/spec/fixtures/container_tomcat_geode_store_cache_client_after.xml @@ -4,18 +4,4 @@ - - - org.apache.geode.modules.util.CreateRegionFunction - - - org.apache.geode.modules.util.TouchPartitionedRegionEntriesFunction - - - org.apache.geode.modules.util.TouchReplicatedRegionEntriesFunction - - - org.apache.geode.modules.util.RegionSizeFunction - - diff --git a/spec/fixtures/container_tomcat_geode_store_context_after.xml b/spec/fixtures/container_tomcat_geode_store_context_after.xml index ea4a8b558..8eb45842b 100644 --- a/spec/fixtures/container_tomcat_geode_store_context_after.xml +++ b/spec/fixtures/container_tomcat_geode_store_context_after.xml @@ -16,5 +16,5 @@ ~ limitations under the License. --> - + diff --git a/spec/fixtures/framework_app_dynamics_agent/BOOT-INF/classes/appdynamics/conf/app-agent-config.xml b/spec/fixtures/framework_app_dynamics_agent/BOOT-INF/classes/appdynamics/conf/app-agent-config.xml new file mode 100644 index 000000000..b934fa90f --- /dev/null +++ b/spec/fixtures/framework_app_dynamics_agent/BOOT-INF/classes/appdynamics/conf/app-agent-config.xml @@ -0,0 +1,730 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + com.singularity.ee.agent.appagent.kernel.DynamicServiceManager + + + + + + + + + + BCIEngine,TransactionMonitoringService,SnapshotService + + + + + + + + BCIEngine + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BCIEngine + + + + + + + + + + + + + + + + + + + + + + + + + + + + BCIEngine,SnapshotService + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + JMXService + + + BCIEngine + + + + + + + + + + + + + + + + + + + + + + + + + + BCIEngine + + + + + + + + + + + + + + + + + + + + + + + BCIEngine + + + + + TransactionMonitoringService + + + + + + + + + + + + + + diff --git a/spec/fixtures/stub-app-dynamics-agent.zip b/spec/fixtures/stub-app-dynamics-agent.zip index a973e1e9d..5e879a4c5 100644 Binary files a/spec/fixtures/stub-app-dynamics-agent.zip and b/spec/fixtures/stub-app-dynamics-agent.zip differ diff --git a/spec/fixtures/stub-checkmarx-agent.zip b/spec/fixtures/stub-checkmarx-agent.zip new file mode 100644 index 000000000..853148a7d Binary files /dev/null and b/spec/fixtures/stub-checkmarx-agent.zip differ diff --git a/spec/java_buildpack/buildpack_spec.rb b/spec/java_buildpack/buildpack_spec.rb index 9c0860070..6953e0ea1 100644 --- a/spec/java_buildpack/buildpack_spec.rb +++ b/spec/java_buildpack/buildpack_spec.rb @@ -39,9 +39,11 @@ let(:stub_jre2) { instance_double('StubJre2', detect: nil, compile: nil, release: nil, component_name: 'StubJre2') } + let(:deps_dir) { Pathname.new Dir.mktmpdir } + let(:buildpack) do buildpack = nil - described_class.with_buildpack(app_dir, 'Error %s') { |b| buildpack = b } + described_class.with_buildpack(app_dir, deps_dir, '0', 'Error %s') { |b| buildpack = b } buildpack end @@ -64,6 +66,14 @@ allow(Test::StubJre2).to receive(:new).and_return(stub_jre2) end + after do |example| + if example.metadata[:no_cleanup] + puts "Deps Directory: #{deps_dir}" + else + FileUtils.rm_rf deps_dir + end + end + it 'raises an error if more than one container can run an application' do allow(stub_container1).to receive(:detect).and_return('stub-container-1') allow(stub_container2).to receive(:detect).and_return('stub-container-2') @@ -88,12 +98,11 @@ before do allow(JavaBuildpack::Util::ConfigurationUtils) - .to receive(:load).with('components') - .and_return( - 'containers' => [], - 'frameworks' => ['JavaBuildpack::Framework::JavaOpts'], - 'jres' => [] - ) + .to receive(:load).with('components').and_return( + 'containers' => [], + 'frameworks' => ['JavaBuildpack::Framework::JavaOpts'], + 'jres' => [] + ) end it 'requires files needed for components' do @@ -152,7 +161,7 @@ end def with_buildpack(&_) - described_class.with_buildpack(app_dir, 'Error %s') { |buildpack| yield buildpack } + described_class.with_buildpack(app_dir, nil, nil, 'Error %s') { |buildpack| yield buildpack } end end diff --git a/spec/java_buildpack/container/dist_zip_like_spec.rb b/spec/java_buildpack/container/dist_zip_like_spec.rb index f5e2fd4e5..94eb404ee 100644 --- a/spec/java_buildpack/container/dist_zip_like_spec.rb +++ b/spec/java_buildpack/container/dist_zip_like_spec.rb @@ -58,4 +58,14 @@ '$PWD/bin/application') end + context do + let(:configuration) { { 'arguments' => 'some arguments' } } + + it 'returns command line arguments when they are specified', + app_fixture: 'container_dist_zip' do + + expect(component.release).to end_with('some arguments') + end + end + end diff --git a/spec/java_buildpack/container/dist_zip_spec.rb b/spec/java_buildpack/container/dist_zip_spec.rb index 02e9b4025..6c9551cfa 100644 --- a/spec/java_buildpack/container/dist_zip_spec.rb +++ b/spec/java_buildpack/container/dist_zip_spec.rb @@ -52,4 +52,14 @@ expect(component.detect).to be_nil end + context do + let(:configuration) { { 'arguments' => 'some arguments' } } + + it 'returns command line arguments when they are specified', + app_fixture: 'container_dist_zip' do + + expect(component.release).to end_with('some arguments') + end + end + end diff --git a/spec/java_buildpack/framework/app_dynamics_agent_spec.rb b/spec/java_buildpack/framework/app_dynamics_agent_spec.rb index 19567dbf6..ac981959a 100644 --- a/spec/java_buildpack/framework/app_dynamics_agent_spec.rb +++ b/spec/java_buildpack/framework/app_dynamics_agent_spec.rb @@ -66,7 +66,7 @@ expect(java_opts).to include('-javaagent:$PWD/.java-buildpack/app_dynamics_agent/javaagent.jar') expect(java_opts).to include('-Dappdynamics.controller.hostName=test-host-name') - expect(java_opts).to include('-Dappdynamics.agent.applicationName=test-application-name') + expect(java_opts).to include('-Dappdynamics.agent.applicationName=\"test-application-name\"') expect(java_opts).to include('-Dappdynamics.agent.tierName=test-application-name') expect(java_opts).to include('-Dappdynamics.agent.nodeName=$(expr "$VCAP_APPLICATION" : ' \ '\'.*instance_index[": ]*\\([[:digit:]]*\\).*\')') @@ -88,7 +88,7 @@ it 'adds application_name from credentials to JAVA_OPTS if specified' do component.release - expect(java_opts).to include('-Dappdynamics.agent.applicationName=another-test-application-name') + expect(java_opts).to include('-Dappdynamics.agent.applicationName=\"another-test-application-name\"') end end @@ -164,6 +164,78 @@ end component.compile end + + end + + context do + let(:environment) { { 'APPD_CONF_HTTP_URL' => 'https://foo.com' } } + + it 'sets APPD_CONF_HTTP_URL env var to download config files over HTTPS', + cache_fixture: 'stub-app-dynamics-agent.zip' do + + config_files = %w[logging/log4j2.xml logging/log4j.xml app-agent-config.xml controller-info.xml + service-endpoint.xml transactions.xml custom-interceptors.xml + custom-activity-correlation.xml] + + config_files.each do |file| + uri = "https://foo.com/java/#{file}" + allow(application_cache).to receive(:get) + .with(uri) + allow(Net::HTTP).to receive(:start).with('foo.com', 443, use_ssl: true).and_call_original + stub_request(:head, uri) + .with(headers: { 'Accept' => '*/*', 'Host' => 'foo.com', 'User-Agent' => 'Ruby' }) + .to_return(status: 200, body: '', headers: {}) + end + component.compile + end + end + + context do + let(:environment) { { 'APPD_CONF_HTTP_URL' => 'https://user:pass@foo.com' } } + + it 'sets APPD_CONF_HTTP_URL env var to download config files over HTTPS with Basic Auth', + cache_fixture: 'stub-app-dynamics-agent.zip' do + + config_files = %w[logging/log4j2.xml logging/log4j.xml app-agent-config.xml controller-info.xml + service-endpoint.xml transactions.xml custom-interceptors.xml + custom-activity-correlation.xml] + + config_files.each do |file| + allow(application_cache).to receive(:get) + .with("https://user:pass@foo.com/java/#{file}") + allow(Net::HTTP).to receive(:start).with('foo.com', 443, use_ssl: true).and_call_original + stub_request(:head, "https://foo.com/java/#{file}") + .with(headers: { 'Accept' => '*/*', 'Host' => 'foo.com', 'User-Agent' => 'Ruby', + 'Authorization' => 'Basic dXNlcjpwYXNz' }) + .to_return(status: 200, body: '', headers: {}) + end + component.compile + end + end + + context do + + let(:environment) { { 'APPD_CONF_DIR' => 'BOOT-INF/classes/appdynamics/conf' } } + + it 'sets APPD_CONF_DIR env var to copy config files from app dir', + app_fixture: 'framework_app_dynamics_agent', + cache_fixture: 'stub-app-dynamics-agent.zip' do + + component.compile + expect(File.read(sandbox + 'ver21.1.0.31582/conf/app-agent-config.xml')).to include 'sourced by APPD_CONF_DIR' + end + end + + context do + + let(:environment) { { 'APPD_CONF_DIR' => 'BOOT-INF/classes/appdynamics/conf-false' } } + + it 'sets APPD_CONF_DIR env var to copy config files from incorrect app dir', + app_fixture: 'framework_app_dynamics_agent', + cache_fixture: 'stub-app-dynamics-agent.zip' do + + expect { component.compile }.to raise_error(RuntimeError, /AppDynamics configuration source dir/) + end end end end diff --git a/spec/java_buildpack/framework/checkmarx_iast_agent_spec.rb b/spec/java_buildpack/framework/checkmarx_iast_agent_spec.rb new file mode 100644 index 000000000..631ecd62b --- /dev/null +++ b/spec/java_buildpack/framework/checkmarx_iast_agent_spec.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +# Cloud Foundry Java Buildpack +# Copyright 2013-2020 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 'spec_helper' +require 'component_helper' +require 'java_buildpack/framework/checkmarx_iast_agent' + +describe JavaBuildpack::Framework::CheckmarxIastAgent do + include_context 'with component help' + + it 'does not detect without checkmarx-iast service' do + expect(component.detect).to be_nil + end + + context do + + before do + allow(services).to receive(:one_service?).with(/^checkmarx-iast$/, 'server').and_return(true) + allow(services).to receive(:find_service).and_return('credentials' => { 'server' => 'test-server' }) + + allow(application_cache).to receive(:get) + .with('test-server/iast/compilation/download/JAVA') + .and_yield(Pathname.new('spec/fixtures/stub-checkmarx-agent.zip').open, false) + end + + it 'detects with checkmarx-iast service' do + expect(component.detect).to eq('checkmarx-iast-agent=') + end + + it 'downloads agent', + cache_fixture: 'stub-checkmarx-agent.zip' do + + component.compile + + expect(sandbox + 'cx-launcher.jar').to exist + end + + it 'appends override configuration', + cache_fixture: 'stub-checkmarx-agent.zip' do + + component.compile + + expect(File.read(sandbox + 'cx_agent.override.properties')).to eq('test-data + +enableWeavedClassCache=false +') + end + + it 'updates JAVA_OPTS' do + component.release + + expect(java_opts).to include('-javaagent:$PWD/.java-buildpack/checkmarx_iast_agent/cx-launcher.jar') + expect(java_opts).to include('-Dcx.logToConsole=true') + expect(java_opts).to include('-Dcx.appName=test-application-name') + expect(java_opts).to include('-DcxAppTag=test-application-name') + expect(java_opts).to include('-DcxTeam=CxServer') + end + + end + +end diff --git a/spec/java_buildpack/framework/java_memory_assistant/agent_spec.rb b/spec/java_buildpack/framework/java_memory_assistant/agent_spec.rb index 84564840e..760ae58a6 100644 --- a/spec/java_buildpack/framework/java_memory_assistant/agent_spec.rb +++ b/spec/java_buildpack/framework/java_memory_assistant/agent_spec.rb @@ -52,15 +52,54 @@ it 'updates JAVA_OPTS with default values' do component.release + expect(java_opts).not_to include('--add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED') + expect(java_opts).to include('-javaagent:$PWD/.java-buildpack/java_memory_assistant_agent/' \ 'java-memory-assistant-1.2.3.jar') expect(java_opts).to include('-Djma.enabled=true') expect(java_opts).to include('-Djma.check_interval=5s') - expect(java_opts).to include('-Djma.max_frequency=1/1m') + expect(java_opts).to include('\'-Djma.max_frequency=1/1m\'') + + expect(java_opts).to include('\'-Djma.thresholds.heap=90\'') + expect(java_opts).to include('\'-Djma.thresholds.old_gen=90\'') + + end + + context do + + let(:java_home_delegate) do + delegate = JavaBuildpack::Component::MutableJavaHome.new + delegate.root = app_dir + '.test-java-home' + delegate.version = JavaBuildpack::Util::TokenizedVersion.new('1.8.0_55') + + delegate + end + + it 'does not add the --add-opens on Java 8' do + component.release + + expect(java_opts).not_to include('--add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED') + end + + end + + context do + + let(:java_home_delegate) do + delegate = JavaBuildpack::Component::MutableJavaHome.new + delegate.root = app_dir + '.test-java-home' + delegate.version = JavaBuildpack::Util::TokenizedVersion.new('9.0.1') + + delegate + end + + it 'adds the --add-opens on Java 11' do + component.release + + expect(java_opts).to include('--add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED') + end - expect(java_opts).to include('-Djma.thresholds.heap=90') - expect(java_opts).to include('-Djma.thresholds.old_gen=90') end end @@ -93,15 +132,15 @@ 'java-memory-assistant-0.1.0.jar') expect(java_opts).to include('-Djma.enabled=true') expect(java_opts).to include('-Djma.check_interval=10m') - expect(java_opts).to include('-Djma.max_frequency=4/10h') + expect(java_opts).to include('\'-Djma.max_frequency=4/10h\'') expect(java_opts).to include('-Djma.log_level=DEBUG') - expect(java_opts).to include('-Djma.thresholds.heap=60') - expect(java_opts).to include('-Djma.thresholds.code_cache=30') - expect(java_opts).to include('-Djma.thresholds.metaspace=5') - expect(java_opts).to include('-Djma.thresholds.perm_gen=45.5') - expect(java_opts).to include('-Djma.thresholds.eden=90') - expect(java_opts).to include('-Djma.thresholds.survivor=95.5') - expect(java_opts).to include('-Djma.thresholds.old_gen=30') + expect(java_opts).to include('\'-Djma.thresholds.heap=60\'') + expect(java_opts).to include('\'-Djma.thresholds.code_cache=30\'') + expect(java_opts).to include('\'-Djma.thresholds.metaspace=5\'') + expect(java_opts).to include('\'-Djma.thresholds.perm_gen=45.5\'') + expect(java_opts).to include('\'-Djma.thresholds.eden=90\'') + expect(java_opts).to include('\'-Djma.thresholds.survivor=95.5\'') + expect(java_opts).to include('\'-Djma.thresholds.old_gen=30\'') end end @@ -121,6 +160,30 @@ end + context do + let(:configuration) do + { + 'thresholds' => { + 'heap' => '>600MB', + 'eden' => '< 30MB' + } + } + end + + let(:version) { '0.1.0' } + + it 'escapses redirection characters' do + component.release + + expect(java_opts).to include('-javaagent:$PWD/.java-buildpack/java_memory_assistant_agent/' \ + 'java-memory-assistant-0.1.0.jar') + + expect(java_opts).to include('\'-Djma.thresholds.heap=>600MB\'') + expect(java_opts).to include('\'-Djma.thresholds.eden=< 30MB\'') + end + + end + context do let(:configuration) do { diff --git a/spec/java_buildpack/framework/riverbed_appinternals_agent_spec.rb b/spec/java_buildpack/framework/riverbed_appinternals_agent_spec.rb index 3b03bf076..5f8de5678 100644 --- a/spec/java_buildpack/framework/riverbed_appinternals_agent_spec.rb +++ b/spec/java_buildpack/framework/riverbed_appinternals_agent_spec.rb @@ -31,9 +31,6 @@ before do allow(services).to receive(:one_service?).with(/appinternals/).and_return(true) - allow(services).to receive(:find_service).and_return('credentials' => { 'profilerUrlLinux' => - 'http://testfoobar/profiler.zip' }) - allow(application_cache).to receive(:get).with('http://testfoobar/profiler.zip') .and_yield(Pathname.new('spec/fixtures/'\ 'stub-riverbed-appinternals-agent.zip').open, false) 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 1e7488a46..df43a4dc2 100644 --- a/spec/java_buildpack/jre/open_jdk_like_jre_spec.rb +++ b/spec/java_buildpack/jre/open_jdk_like_jre_spec.rb @@ -56,6 +56,8 @@ it 'does not disable dns caching if no BOSH DNS', cache_fixture: 'stub-java.tar.gz' do + allow_any_instance_of(Resolv::DNS::Config).to receive(:nameserver_port).and_return([['8.8.8.8', 53]]) + component.detect component.compile diff --git a/spec/java_buildpack/util/cache/download_cache_spec.rb b/spec/java_buildpack/util/cache/download_cache_spec.rb index 52ee0c397..9a8c352e0 100644 --- a/spec/java_buildpack/util/cache/download_cache_spec.rb +++ b/spec/java_buildpack/util/cache/download_cache_spec.rb @@ -223,6 +223,22 @@ end + context do + + let(:environment) { { 'HTTP_PROXY' => 'http://user%21:pass%40@proxy:9000', 'http_proxy' => nil } } + + it 'decodes user/pass from HTTP_PROXY if encoded' do + stub_request(:get, uri) + .to_return(status: 200, body: 'foo-cached', headers: { Etag: 'foo-etag', + 'Last-Modified' => 'foo-last-modified' }) + + allow(Net::HTTP).to receive(:Proxy).with('proxy', 9000, /user!/, /pass@/).and_call_original + + download_cache.get(uri) {} + end + + end + context do let(:environment) { { 'https_proxy' => 'http://proxy:9000', 'HTTPS_PROXY' => nil } } @@ -257,6 +273,22 @@ end + context do + + let(:environment) { { 'HTTPS_PROXY' => 'http://user%21:pass%40@proxy:9000', 'https_proxy' => nil } } + + it 'decodes user/pass from HTTPS_PROXY if encoded' do + stub_request(:get, uri_secure) + .to_return(status: 200, body: 'foo-cached', headers: { Etag: 'foo-etag', + 'Last-Modified' => 'foo-last-modified' }) + + allow(Net::HTTP).to receive(:Proxy).with('proxy', 9000, /user!/, /pass@/).and_call_original + + download_cache.get(uri_secure) {} + end + + end + context do let(:environment) { { 'NO_PROXY' => '127.0.0.1,localhost,foo-uri,.foo-uri', 'HTTPS_PROXY' => 'http://proxy:9000' } }