diff --git a/.idea/dictionaries/bhale.xml b/.idea/dictionaries/bhale.xml
index 8c40705e96..db86f3320e 100644
--- a/.idea/dictionaries/bhale.xml
+++ b/.idea/dictionaries/bhale.xml
@@ -18,6 +18,7 @@
constantized
constantizes
cpio
+ cprof
creat
cryptoki
dhttp
@@ -55,6 +56,7 @@
libruxitagentloader
libyjpagent
ljust
+ logtostderr
lunaclient
lunajsp
mainclass
@@ -97,6 +99,7 @@
shellwords
simplecov
socketfactory
+ stackdriver
stderr
strftime
stringifies
diff --git a/README.md b/README.md
index ce33d4fc00..6298a7b621 100644
--- a/README.md
+++ b/README.md
@@ -83,6 +83,7 @@ The buildpack supports extension through the use of Git repository forking. The
* [Dynatrace Appmon Agent](docs/framework-dynatrace_appmon_agent.md) ([Configuration](docs/framework-dynatrace_appmon_agent.md#configuration))
* [Dynatrace SaaS/Managed OneAgent](docs/framework-dynatrace_one_agent.md) ([Configuration](docs/framework-dynatrace_one_agent.md#configuration))
* [Google Stackdriver Debugger](docs/framework-google_stackdriver_debugger.md) ([Configuration](docs/framework-google_stackdriver_debugger.md#configuration))
+ * [Google Stackdriver Profiler](docs/framework-google_stackdriver_profiler.md) ([Configuration](docs/framework-google_stackdriver_profiler.md#configuration))
* [Introscope Agent](docs/framework-introscope_agent.md) ([Configuration](docs/framework-introscope_agent.md#configuration))
* [JaCoCo Agent](docs/framework-jacoco_agent.md) ([Configuration](docs/framework-jacoco_agent.md#configuration))
* [Java Memory Assistant](docs/framework-java_memory_assistant.md) ([Configuration](docs/framework-java_memory_assistant.md#configuration))
diff --git a/config/components.yml b/config/components.yml
index 546f80aa48..e21195e799 100644
--- a/config/components.yml
+++ b/config/components.yml
@@ -51,6 +51,7 @@ frameworks:
- "JavaBuildpack::Framework::DynatraceAppmonAgent"
- "JavaBuildpack::Framework::DynatraceOneAgent"
- "JavaBuildpack::Framework::GoogleStackdriverDebugger"
+ - "JavaBuildpack::Framework::GoogleStackdriverProfiler"
- "JavaBuildpack::Framework::IntroscopeAgent"
- "JavaBuildpack::Framework::JacocoAgent"
- "JavaBuildpack::Framework::JavaMemoryAssistant"
diff --git a/config/google_stackdriver_profiler.yml b/config/google_stackdriver_profiler.yml
new file mode 100644
index 0000000000..6a65f9dfb4
--- /dev/null
+++ b/config/google_stackdriver_profiler.yml
@@ -0,0 +1,21 @@
+# Cloud Foundry Java Buildpack
+# Copyright 2013-2018 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.
+
+# Configuration for the Groovy container
+---
+version: 0.+
+repository_root: "{default.repository.root}/google-stackdriver-profiler/{platform}/{architecture}"
+application_name:
+application_version:
diff --git a/docs/framework-google_stackdriver_profiler.md b/docs/framework-google_stackdriver_profiler.md
new file mode 100644
index 0000000000..4781be1d1a
--- /dev/null
+++ b/docs/framework-google_stackdriver_profiler.md
@@ -0,0 +1,43 @@
+# Google Stackdriver Profielr Framework
+The Google Stackdriver Profiler Framework causes an application to be automatically configured to work with a bound [Google Stackdriver Profiler Service][].
+
+
+
+ Detection Criterion | Existence of a single bound Google Stackdriver Profiler service.
+
+ - Existence of a Google Stackdriver Profiler service is defined as the
VCAP_SERVICES payload containing a service who's name, label or tag has google-stackdriver-profiler as a substring.
+
+ |
+
+
+ Tags |
+ google-stackdriver-profiler=<version> |
+
+
+Tags are printed to standard output by the buildpack detect script
+
+## User-Provided Service (Optional)
+Users may optionally provide their own Google Stackdriver Profiler service. A user-provided Google Stackdriver Profiler service must have a name or tag with `google-stackdriver-profiler` in it so that the Google Stackdriver Profiler Agent Framework will automatically configure the application to work with the service.
+
+The credential payload of the service must contain the following entry:
+
+| Name | Description
+| ---- | -----------
+| `PrivateKeyData` | A Base64 encoded Service Account JSON payload
+
+## Configuration
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
+
+The framework can be configured by modifying the [`config/google_stackdriver_profiler.yml`][] file in the buildpack fork. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
+
+| Name | Description
+| ---- | -----------
+| `repository_root` | The URL of the Google Stackdriver Profiler repository index ([details][repositories]).
+| `version` | The version of Google Stackdriver Profiler to use. Candidate versions can be found in [this listing][].
+
+[Configuration and Extension]: ../README.md#configuration-and-extension
+[`config/google_stackdriver_profiler.yml`]: ../config/google_stackdriver_profiler.yml
+[Google Stackdriver Profiler Service]: https://cloud.google.com/profiler/
+[repositories]: extending-repositories.md
+[this listing]: http://download.pivotal.io.s3.amazonaws.com/google-stackdriver-profiler/trusty/x86_64/index.yml
+[version syntax]: extending-repositories.md#version-syntax-and-ordering
diff --git a/docs/jre-zulu_jre.md b/docs/jre-zulu_jre.md
old mode 100755
new mode 100644
diff --git a/lib/java_buildpack/framework/google_stackdriver_profiler.rb b/lib/java_buildpack/framework/google_stackdriver_profiler.rb
new file mode 100644
index 0000000000..856cd38225
--- /dev/null
+++ b/lib/java_buildpack/framework/google_stackdriver_profiler.rb
@@ -0,0 +1,101 @@
+# frozen_string_literal: true
+
+# Cloud Foundry Java Buildpack
+# Copyright 2013-2018 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 'base64'
+require 'json'
+require 'java_buildpack/component/versioned_dependency_component'
+require 'java_buildpack/framework'
+
+module JavaBuildpack
+ module Framework
+
+ # Encapsulates the functionality for enabling zero-touch Google Cloud Profiler support.
+ class GoogleStackdriverProfiler < JavaBuildpack::Component::VersionedDependencyComponent
+
+ # (see JavaBuildpack::Component::BaseComponent#compile)
+ def compile
+ download_tar false
+
+ write_json_file private_key_data
+ end
+
+ # (see JavaBuildpack::Component::BaseComponent#release)
+ def release
+ java_opts = @droplet.java_opts
+
+ java_opts
+ .add_agentpath_with_props(@droplet.sandbox + 'profiler_java_agent.so',
+ '--logtostderr' => 1,
+ '-cprof_project_id' => project_id,
+ '-cprof_service' => application_name,
+ '-cprof_service_version' => application_version)
+
+ @droplet.environment_variables.add_environment_variable 'GOOGLE_APPLICATION_CREDENTIALS', json_file
+ end
+
+ protected
+
+ # (see JavaBuildpack::Component::VersionedDependencyComponent#supports?)
+ def supports?
+ @application.services.one_service? FILTER, PRIVATE_KEY_DATA
+ end
+
+ FILTER = /google-stackdriver-profiler/
+
+ PRIVATE_KEY_DATA = 'PrivateKeyData'
+
+ private_constant :FILTER, :PRIVATE_KEY_DATA
+
+ private
+
+ def application_name
+ @configuration['application_name'] || @application.details['application_name']
+ end
+
+ def application_version
+ @configuration['application_version'] || @application.details['application_version']
+ end
+
+ def credentials
+ @application.services.find_service(FILTER, PRIVATE_KEY_DATA)['credentials']
+ end
+
+ def private_key_data
+ Base64.decode64 credentials[PRIVATE_KEY_DATA]
+ end
+
+ def project_id
+ JSON.parse(private_key_data)['project_id']
+ end
+
+ def json_file
+ @droplet.sandbox + 'svc.json'
+ end
+
+ def write_json_file(private_key_data)
+ FileUtils.mkdir_p json_file.parent
+ json_file.open(File::CREAT | File::WRONLY) do |f|
+ f.write "#{private_key_data}\n"
+ f.sync
+ f
+ end
+ end
+
+ end
+
+ end
+end
diff --git a/rakelib/versions_task.rb b/rakelib/versions_task.rb
index 0c75e6d1e0..dd7d75bf11 100644
--- a/rakelib/versions_task.rb
+++ b/rakelib/versions_task.rb
@@ -64,6 +64,7 @@ def initialize
'dynatrace_one_agent' => 'Dynatrace OneAgent',
'geode_store' => 'Geode Tomcat Session Store',
'google_stackdriver_debugger' => 'Google Stackdriver Debugger',
+ 'google_stackdriver_profiler' => 'Google Stackdriver Profiler',
'groovy' => 'Groovy',
'introscope_agent' => 'CA Introscope APM Framework',
'jacoco_agent' => 'JaCoCo Agent',
diff --git a/spec/fixtures/stub-google-stackdriver-profiler.tar.gz b/spec/fixtures/stub-google-stackdriver-profiler.tar.gz
new file mode 100644
index 0000000000..6f4deae0b1
Binary files /dev/null and b/spec/fixtures/stub-google-stackdriver-profiler.tar.gz differ
diff --git a/spec/java_buildpack/framework/google_stackdriver_profiler_spec.rb b/spec/java_buildpack/framework/google_stackdriver_profiler_spec.rb
new file mode 100644
index 0000000000..56218e5b40
--- /dev/null
+++ b/spec/java_buildpack/framework/google_stackdriver_profiler_spec.rb
@@ -0,0 +1,76 @@
+# frozen_string_literal: true
+
+# Cloud Foundry Java Buildpack
+# Copyright 2013-2018 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/google_stackdriver_profiler'
+
+describe JavaBuildpack::Framework::GoogleStackdriverProfiler do
+ include_context 'with component help'
+
+ it 'does not detect without google-stackdriver-profiler service' do
+ expect(component.detect).to be_nil
+ end
+
+ context do
+
+ before do
+ allow(services).to receive(:one_service?)
+ .with(/google-stackdriver-profiler/, 'PrivateKeyData').and_return(true)
+
+ allow(services).to receive(:find_service).and_return(
+ 'credentials' => {
+ 'PrivateKeyData' => 'eyJwcm9qZWN0X2lkIjoidGVzdC1wcm9qZWN0LWlkIn0='
+ }
+ )
+ end
+
+ it 'detects with google-stackdriver-profiler service' do
+ expect(component.detect).to eq("google-stackdriver-profiler=#{version}")
+ end
+
+ it 'unpacks the google stackdriver debugger tar',
+ cache_fixture: 'stub-google-stackdriver-profiler.tar.gz' do
+
+ component.compile
+
+ expect(sandbox + 'profiler_java_agent.so').to exist
+ end
+
+ it 'writes JSON file',
+ cache_fixture: 'stub-google-stackdriver-profiler.tar.gz' do
+
+ component.compile
+
+ expect(sandbox + 'svc.json').to exist
+ expect(File.read(sandbox + 'svc.json')).to eq("{\"project_id\":\"test-project-id\"}\n")
+ end
+
+ it 'updates JAVA_OPTS' do
+ component.release
+ expect(java_opts).to include('-agentpath:$PWD/.java-buildpack/google_stackdriver_profiler/' \
+ 'profiler_java_agent.so=--logtostderr=1,-cprof_project_id=test-project-id,' \
+ '-cprof_service=test-application-name,' \
+ '-cprof_service_version=test-application-version')
+
+ expect(environment_variables).to include('GOOGLE_APPLICATION_CREDENTIALS=' \
+ '$PWD/.java-buildpack/google_stackdriver_profiler/svc.json')
+ end
+
+ end
+
+end