Skip to content

Commit f7a1b85

Browse files
committed
Add Google Stackdriver Debugger Framework
This change adds support for the Google Stackdriver Debugger (https://cloud.google.com/debugger/) to the buildpack. It expects a bound service (google-stackdriver-debugger) with module and version credentials. [resolves cloudfoundry#405]
1 parent 54f3900 commit f7a1b85

11 files changed

+234
-8
lines changed

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ To learn how to configure various properties of the buildpack, follow the "Confi
7979
* [Dyadic EKM Security Provider](docs/framework-dyadic_ekm_security_provider.md) ([Configuration](docs/framework-dyadic_ekm_security_provider.md#configuration))
8080
* [Dynatrace Appmon Agent](docs/framework-dynatrace_appmon_agent.md) ([Configuration](docs/framework-dynatrace_appmon_agent.md#configuration))
8181
* [Dynatrace SaaS/Managed OneAgent](docs/framework-dynatrace_one_agent.md) ([Configuration](docs/framework-dynatrace_one_agent.md#configuration))
82+
* [Google Stackdriver Debugger](docs/framework-google_stackdriver_debugger.md) ([Configuration](docs/framework-google_stackdriver_debugger.md#configuration))
8283
* [Introscope Agent](docs/framework-introscope_agent.md) ([Configuration](docs/framework-introscope_agent.md#configuration))
8384
* [Java Options](docs/framework-java_opts.md) ([Configuration](docs/framework-java_opts.md#configuration))
8485
* [JRebel Agent](docs/framework-jrebel_agent.md) ([Configuration](docs/framework-jrebel_agent.md#configuration))
@@ -115,7 +116,7 @@ To learn how to configure various properties of the buildpack, follow the "Confi
115116
* [Java Buildpack System Tests](https://github.com/cloudfoundry/java-buildpack-system-test)
116117

117118
## Building Packages
118-
The buildpack can be packaged up so that it can be uploaded to Cloud Foundry using the `cf create-buildpack` and `cf update-buildpack` commands. In order to create these packages, the rake `package` task is used.
119+
The buildpack can be packaged up so that it can be uploaded to Cloud Foundry using the `cf create-buildpack` and `cf update-buildpack` commands. In order to create these packages, the rake `package` task is used.
119120

120121
Note that this process is not currently supported on Windows. It is possible it will work, but it is not tested, and no additional functionality has been added to make it work.
121122

config/components.yml

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ frameworks:
4343
- "JavaBuildpack::Framework::Debug"
4444
- "JavaBuildpack::Framework::DynatraceAppmonAgent"
4545
- "JavaBuildpack::Framework::DynatraceOneAgent"
46+
- "JavaBuildpack::Framework::GoogleStackdriverDebugger"
4647
# - "JavaBuildpack::Framework::IntroscopeAgent"
4748
- "JavaBuildpack::Framework::Jmx"
4849
- "JavaBuildpack::Framework::JrebelAgent"
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Cloud Foundry Java Buildpack
2+
# Copyright 2013-2017 the original author or authors.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
# Configuration for the Groovy container
17+
---
18+
version: 2.+
19+
repository_root: "{default.repository.root}/google-stackdriver-debugger/{platform}/{architecture}"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Google Stackdriver Debugger Framework
2+
The Google Stackdriver Debugger Framework causes an application to be automatically configured to work with a bound [Google Stackdriver Debugger Service][].
3+
4+
<table>
5+
<tr>
6+
<td><strong>Detection Criterion</strong></td><td>Existence of a single bound Google Stackdriver Debugger service.
7+
<ul>
8+
<li>Existence of a Google Stackdriver Debugger service is defined as the <a href="http://docs.cloudfoundry.org/devguide/deploy-apps/environment-variable.html#VCAP-SERVICES"><code>VCAP_SERVICES</code></a> payload containing a service who's name, label or tag has <code>google-stackdriver-debugger</code> as a substring.</li>
9+
</ul>
10+
</td>
11+
</tr>
12+
<tr>
13+
<td><strong>Tags</strong></td>
14+
<td><tt>google-stackdriver-debugger=&lt;version&gt;</tt></td>
15+
</tr>
16+
</table>
17+
Tags are printed to standard output by the buildpack detect script
18+
19+
## User-Provided Service (Optional)
20+
Users may optionally provide their own Google Stackdriver Debugger service. A user-provided Google Stackdriver Debugger service must have a name or tag with `google-stackdriver-debugger` in it so that the Google Stackdriver Debugger Agent Framework will automatically configure the application to work with the service.
21+
22+
The credential payload of the service must contain the following entry:
23+
24+
| Name | Description
25+
| ---- | -----------
26+
| `PrivateKeyData` | A Base64 encoded Service Account JSON payload
27+
28+
## Configuration
29+
For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
30+
31+
The framework can be configured by modifying the [`config/google_stackdriver_debugger.yml`][] file in the buildpack fork. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
32+
33+
| Name | Description
34+
| ---- | -----------
35+
| `repository_root` | The URL of the Google Stackdriver Debugger repository index ([details][repositories]).
36+
| `version` | The version of Google Stackdriver Debugger to use. Candidate versions can be found in [this listing][].
37+
38+
[Configuration and Extension]: ../README.md#configuration-and-extension
39+
[`config/google_stackdriver_debugger.yml`]: ../config/google_stackdriver_debugger.yml
40+
[Google Stackdriver Debugger Service]: https://cloud.google.com/debugger/
41+
[repositories]: extending-repositories.md
42+
[this listing]: http://download.pivotal.io.s3.amazonaws.com/google-stackdriver-debugger/trusty/x86_64/index.yml
43+
[version syntax]: extending-repositories.md#version-syntax-and-ordering

java-buildpack.iml

+2-2
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@
255255
<method />
256256
</configuration>
257257
</component>
258-
<component name="NewModuleRootManager" inherit-compiler-output="false">
258+
<component name="NewModuleRootManager">
259259
<content url="file://$MODULE_DIR$">
260260
<sourceFolder url="file://$MODULE_DIR$/bin" isTestSource="false" />
261261
<sourceFolder url="file://$MODULE_DIR$/lib" isTestSource="false" />
@@ -269,7 +269,7 @@
269269
<orderEntry type="sourceFolder" forTests="false" />
270270
<orderEntry type="library" scope="PROVIDED" name="addressable (v2.5.0, rbenv: 2.2.6) [gem]" level="application" />
271271
<orderEntry type="library" scope="PROVIDED" name="ast (v2.3.0, rbenv: 2.2.6) [gem]" level="application" />
272-
<orderEntry type="library" scope="PROVIDED" name="bundler (v1.14.5, rbenv: 2.2.6) [gem]" level="application" />
272+
<orderEntry type="library" scope="PROVIDED" name="bundler (v1.14.6, rbenv: 2.2.6) [gem]" level="application" />
273273
<orderEntry type="library" scope="PROVIDED" name="crack (v0.4.3, rbenv: 2.2.6) [gem]" level="application" />
274274
<orderEntry type="library" scope="PROVIDED" name="diff-lcs (v1.3, rbenv: 2.2.6) [gem]" level="application" />
275275
<orderEntry type="library" scope="PROVIDED" name="hashdiff (v0.3.2, rbenv: 2.2.6) [gem]" level="application" />

lib/java_buildpack/component/base_component.rb

+7-2
Original file line numberDiff line numberDiff line change
@@ -114,21 +114,26 @@ def download_jar(version, uri, jar_name, target_directory = @droplet.sandbox, na
114114
#
115115
# @param [String] version the version of the download
116116
# @param [String] uri the uri of the download
117+
# @param [Boolean] strip_top_level whether to strip the top-level directory when expanding. Defaults to +true+.
117118
# @param [Pathname] target_directory the directory to expand the TAR file to. Defaults to the component's
118119
# sandbox.
119120
# @param [String] name an optional name for the download and expansion. Defaults to +@component_name+.
120121
# @return [Void]
121-
def download_tar(version, uri, target_directory = @droplet.sandbox, name = @component_name)
122+
def download_tar(version, uri, strip_top_level = true, target_directory = @droplet.sandbox,
123+
name = @component_name)
122124
download(version, uri, name) do |file|
123125
with_timing "Expanding #{name} to #{target_directory.relative_path_from(@droplet.root)}" do
124126
FileUtils.mkdir_p target_directory
125-
shell "tar x#{compression_flag(file)}f #{file.path} -C #{target_directory} --strip 1 2>&1"
127+
shell "tar x#{compression_flag(file)}f #{file.path} -C #{target_directory} " \
128+
"#{'--strip 1' if strip_top_level} 2>&1"
126129
end
127130
end
128131
end
129132

130133
# Downloads a given ZIP file and expands it.
131134
#
135+
# @param [String] version the version of the download
136+
# @param [String] uri the uri of the download
132137
# @param [Boolean] strip_top_level whether to strip the top-level directory when expanding. Defaults to +true+.
133138
# @param [Pathname] target_directory the directory to expand the ZIP file to. Defaults to the component's
134139
# sandbox.

lib/java_buildpack/component/versioned_dependency_component.rb

+3-2
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,13 @@ def download_jar(jar_name = self.jar_name, target_directory = @droplet.sandbox,
7171

7272
# Downloads a given TAR file and expands it.
7373
#
74+
# @param [Boolean] strip_top_level whether to strip the top-level directory when expanding. Defaults to +true+.
7475
# @param [Pathname] target_directory the directory to expand the TAR file to. Defaults to the component's
7576
# sandbox.
7677
# @param [String] name an optional name for the download and expansion. Defaults to +@component_name+.
7778
# @return [Void]
78-
def download_tar(target_directory = @droplet.sandbox, name = @component_name)
79-
super(@version, @uri, target_directory, name)
79+
def download_tar(strip_top_level = true, target_directory = @droplet.sandbox, name = @component_name)
80+
super(@version, @uri, strip_top_level, target_directory, name)
8081
end
8182

8283
# Downloads a given ZIP file and expands it.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Encoding: utf-8
2+
# Cloud Foundry Java Buildpack
3+
# Copyright 2013-2017 the original author or authors.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
require 'base64'
18+
require 'java_buildpack/component/versioned_dependency_component'
19+
require 'java_buildpack/framework'
20+
21+
module JavaBuildpack
22+
module Framework
23+
24+
# Encapsulates the functionality for enabling zero-touch Google Cloud Debugger support.
25+
class GoogleStackdriverDebugger < JavaBuildpack::Component::VersionedDependencyComponent
26+
27+
# (see JavaBuildpack::Component::BaseComponent#compile)
28+
def compile
29+
download_tar false
30+
31+
credentials = @application.services.find_service(FILTER)['credentials']
32+
write_json_file credentials[PRIVATE_KEY_DATA]
33+
end
34+
35+
# (see JavaBuildpack::Component::BaseComponent#release)
36+
def release
37+
java_opts = @droplet.java_opts
38+
39+
java_opts
40+
.add_agentpath_with_props(@droplet.sandbox + 'cdbg_java_agent.so', '--logtostderr' => 1)
41+
.add_system_property('com.google.cdbg.auth.serviceaccount.enable', true)
42+
.add_system_property('com.google.cdbg.auth.serviceaccount.jsonfile', json_file)
43+
.add_system_property('com.google.cdbg.module', @application.details['application_name'])
44+
.add_system_property('com.google.cdbg.version', @application.details['application_version'])
45+
end
46+
47+
protected
48+
49+
# (see JavaBuildpack::Component::VersionedDependencyComponent#supports?)
50+
def supports?
51+
@application.services.one_service? FILTER, PRIVATE_KEY_DATA
52+
end
53+
54+
FILTER = /google-stackdriver-debugger/
55+
56+
PRIVATE_KEY_DATA = 'PrivateKeyData'.freeze
57+
58+
private_constant :FILTER, :PRIVATE_KEY_DATA
59+
60+
private
61+
62+
def json_file
63+
@droplet.sandbox + 'svc.json'
64+
end
65+
66+
def write_json_file(json_file_data)
67+
FileUtils.mkdir_p json_file.parent
68+
json_file.open(File::CREAT | File::WRONLY) do |f|
69+
f.write "#{Base64.decode64 json_file_data}\n"
70+
f.sync
71+
f
72+
end
73+
end
74+
75+
end
76+
77+
end
78+
end

spec/application_helper.rb

+4-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,10 @@
4646

4747
let(:services) { application.services }
4848

49-
let(:vcap_application) { { 'application_name' => 'test-application-name' } }
49+
let(:vcap_application) do
50+
{ 'application_name' => 'test-application-name',
51+
'application_version' => 'test-application-version' }
52+
end
5053

5154
let(:vcap_services) do
5255
{ 'test-service-n/a' => [{ 'name' => 'test-service-name', 'label' => 'test-service-n/a',
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Encoding: utf-8
2+
# Cloud Foundry Java Buildpack
3+
# Copyright 2013-2017 the original author or authors.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
require 'spec_helper'
18+
require 'component_helper'
19+
require 'java_buildpack/framework/google_stackdriver_debugger'
20+
21+
describe JavaBuildpack::Framework::GoogleStackdriverDebugger do
22+
include_context 'component_helper'
23+
24+
it 'does not detect without google-stackdriver-debugger-n/a service' do
25+
expect(component.detect).to be_nil
26+
end
27+
28+
context do
29+
30+
before do
31+
allow(services).to receive(:one_service?)
32+
.with(/google-stackdriver-debugger/, 'PrivateKeyData').and_return(true)
33+
34+
allow(services).to receive(:find_service).and_return(
35+
'credentials' => {
36+
'PrivateKeyData' => 'dGVzdC1wcml2YXRlLWtleS1kYXRh'
37+
}
38+
)
39+
end
40+
41+
it 'detects with google-stackdriver-debugger-c-n/a service' do
42+
expect(component.detect).to eq("google-stackdriver-debugger=#{version}")
43+
end
44+
45+
it 'unpacks the google stackdriver debugger tar',
46+
cache_fixture: 'stub-google-stackdriver-debugger.tar.gz' do
47+
48+
component.compile
49+
50+
expect(sandbox + 'cdbg_java_agent.so').to exist
51+
end
52+
53+
it 'writes JSOn file',
54+
cache_fixture: 'stub-google-stackdriver-debugger.tar.gz' do
55+
56+
component.compile
57+
58+
expect(sandbox + 'svc.json').to exist
59+
expect(File.read(sandbox + 'svc.json')).to eq("test-private-key-data\n")
60+
end
61+
62+
it 'updates JAVA_OPTS' do
63+
component.release
64+
expect(java_opts).to include('-agentpath:$PWD/.java-buildpack/google_stackdriver_debugger/cdbg_java_agent.so=' \
65+
'--logtostderr=1')
66+
expect(java_opts).to include('-Dcom.google.cdbg.auth.serviceaccount.enable=true')
67+
expect(java_opts).to include('-Dcom.google.cdbg.auth.serviceaccount.jsonfile=' \
68+
'$PWD/.java-buildpack/google_stackdriver_debugger/svc.json')
69+
expect(java_opts).to include('-Dcom.google.cdbg.module=test-application-name')
70+
expect(java_opts).to include('-Dcom.google.cdbg.version=test-application-version')
71+
end
72+
73+
end
74+
75+
end

0 commit comments

Comments
 (0)