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 CriterionExistence 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.
  • +
+
Tagsgoogle-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