Skip to content

Commit e0e9041

Browse files
author
Christopher Frost
committed
Zero-touch support for Spring Insight
Spring Insight is a monitoring solution provided Pivotal[1]. It monitors Spring web applications for performance and faults. This support is implemented as a framework that looks for a service called 'insight' and acts when it is found. The framework downloads the appropriate Insight agent from the Insight dashboard and configures it so that it connects to the bound service properly. Configuration of Insight is not accomplished through the buildpack, but rather through the Insight dashboard. This service only works for applications deploying into the Tomcat container and modifies the Tomcat container with *TEMPORARY* support for behaviors needed by the Spring Insight agent. These changes to the Tomcat container are not likely to last long and other components should not depend on or emulate them. [1]: http://gopivotal.com/pivotal-products/apps/pivotal-tc-server [52064679] [52065001] [52065073]
1 parent 47d091e commit e0e9041

8 files changed

Lines changed: 369 additions & 1 deletion

File tree

config/components.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ jres:
2626
frameworks:
2727
- "JavaBuildpack::Framework::JavaOpts"
2828
- "JavaBuildpack::Framework::NewRelic"
29+
- "JavaBuildpack::Framework::SpringInsight"
2930
- "JavaBuildpack::Framework::PlayAutoReconfiguration"
3031
- "JavaBuildpack::Framework::PlayJpaPlugin"
3132
- "JavaBuildpack::Framework::SpringAutoReconfiguration"

config/springinsight.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Cloud Foundry Java Buildpack
2+
# Copyright (c) 2013 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 Spring Insight framework
17+
---

lib/java_buildpack/container/tomcat.rb

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ def compile
4949
download_tomcat
5050
download_support
5151
link_application
52+
link_container_libs
53+
link_extra_applications
5254
link_libs
5355
end
5456

@@ -95,6 +97,10 @@ def supports?
9597

9698
WEB_INF_DIRECTORY = 'WEB-INF'.freeze
9799

100+
def container_libs_directory
101+
@application.component_directory 'container-libs'
102+
end
103+
98104
def download_tomcat
99105
download(@tomcat_version, @tomcat_uri) { |file| expand file }
100106
end
@@ -115,18 +121,46 @@ def expand(file)
115121
puts "(#{(Time.now - expand_start_time).duration})"
116122
end
117123

124+
def extra_applications_directory
125+
@application.component_directory 'extra-applications'
126+
end
127+
118128
def link_application
119129
FileUtils.rm_rf root
120130
FileUtils.mkdir_p root
121131
@application.children.each { |child| FileUtils.ln_sf child.relative_path_from(root), root }
122132
end
123133

134+
# Support for container libs in addition to the users application in temporay and will go away in the future.
135+
def link_container_libs
136+
if container_libs_directory.exist?
137+
container_libs = ContainerUtils.libs(@app_dir, container_libs_directory)
138+
139+
if container_libs
140+
FileUtils.mkdir_p(tomcat_lib) unless tomcat_lib.exist?
141+
container_libs.each { |lib| FileUtils.ln_sf(File.join('..', '..', lib), tomcat_lib) }
142+
end
143+
end
144+
end
145+
146+
# Support for extra applications in addition to the users application in temporay and will go away in the future.
147+
def link_extra_applications
148+
if extra_applications_directory.exist?
149+
extra_applications = ContainerUtils.relative_paths(@app_dir, extra_applications_directory.children) { |file| file.directory? }
150+
151+
if extra_applications
152+
FileUtils.mkdir_p webapps
153+
extra_applications.each { |extra_application| FileUtils.ln_sf(File.join('..', '..', extra_application), webapps) }
154+
end
155+
end
156+
end
157+
124158
def link_libs
125159
libs = ContainerUtils.libs(@app_dir, @lib_directory)
126160

127161
if libs
128162
FileUtils.mkdir_p(web_inf_lib) unless web_inf_lib.exist?
129-
libs.each { |lib| shell "ln -sfn #{File.join '..', '..', lib} #{web_inf_lib}" }
163+
libs.each { |lib| FileUtils.ln_sf(File.join('..', '..', lib), web_inf_lib) }
130164
end
131165
end
132166

@@ -142,6 +176,10 @@ def tomcat_home
142176
@application.component_directory 'tomcat'
143177
end
144178

179+
def tomcat_lib
180+
tomcat_home + 'lib'
181+
end
182+
145183
def webapps
146184
tomcat_home + 'webapps'
147185
end
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
# Encoding: utf-8
2+
# Cloud Foundry Java Buildpack
3+
# Copyright 2013 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 'java_buildpack/base_component'
18+
require 'java_buildpack/framework'
19+
require 'java_buildpack/util/service_utils'
20+
require 'tmpdir'
21+
require 'fileutils'
22+
require 'uri'
23+
24+
module JavaBuildpack::Framework
25+
26+
# Encapsulates the detect, compile, and release functionality for enabling Insight auto configuration.
27+
class SpringInsight < JavaBuildpack::BaseComponent
28+
29+
def initialize(context)
30+
super('Spring Insight', context)
31+
@version, @uri = supports? ? find_insight_agent : [nil, nil]
32+
end
33+
34+
def detect
35+
@version ? id(@version) : nil
36+
end
37+
38+
def compile
39+
download(@version, @uri + AGENT_DOWNLOAD_URI_SUFFIX) { |file| expand file } # TODO: AGENT_DOWNLOAD_URI_SUFFIX To be removed once the full path is included in VCAP_SERVICES see issue 58873498
40+
end
41+
42+
def release
43+
weaver_jar = @application.relative_path_to(Pathname.new Dir[File.join(insight_home, 'weaver', 'insight-weaver-*.jar')][0])
44+
45+
@java_opts << "-javaagent:#{weaver_jar}"
46+
@java_opts << "-Dinsight.base=#{File.join insight_home, 'insight'}"
47+
@java_opts << "-Dinsight.logs=#{File.join insight_home, 'insight' , 'logs'}"
48+
@java_opts << '-Daspectj.overweaving=true'
49+
@java_opts << '-Dorg.aspectj.tracing.factory=default'
50+
@java_opts << '-Dagent.http.protocol=http'
51+
@java_opts << "-Dagent.http.host=#{URI(@uri).host}"
52+
@java_opts << '-Dagent.http.port=80'
53+
@java_opts << '-Dagent.http.context.path=insight'
54+
@java_opts << '-Dagent.http.username=spring'
55+
@java_opts << '-Dagent.http.password=insight'
56+
@java_opts << '-Dagent.http.send.json=false'
57+
@java_opts << '-Dagent.http.use.proxy=false'
58+
@java_opts << '-Dinsight.transport.type=HTTP'
59+
@java_opts << "-Dagent.name.override=#{@vcap_application[NAME_KEY]}"
60+
end
61+
62+
protected
63+
64+
# The unique identifier of the component, incorporating the version of the dependency (e.g. +spring-insight=1.9.3+)
65+
#
66+
# @param [String] version the version of the dependency
67+
# @return [String] the unique identifier of the component
68+
def id(version)
69+
"spring-insight=#{version}"
70+
end
71+
72+
def supports?
73+
JavaBuildpack::Util::ServiceUtils.find_service(@vcap_services, SERVICE_NAME)
74+
end
75+
76+
private
77+
78+
AGENT_DOWNLOAD_URI_SUFFIX = 'services/config/agent-download'.freeze # TODO: To be removed once the full path is included in VCAP_SERVICES see issue 58873498
79+
80+
EXTRA_APPLICATIONS_DIRECTORY = '.extra-applications'.freeze
81+
82+
CONTAINER_LIBS_DIRECTORY = '.container-libs'.freeze
83+
84+
INSIGHT_HOME = '.insight'.freeze
85+
86+
NAME_KEY = 'application_name'.freeze
87+
88+
SERVICE_NAME = /insight/.freeze
89+
90+
def expand(file)
91+
expand_start_time = Time.now
92+
print " Expanding Spring Insight to #{INSIGHT_HOME} "
93+
94+
Dir.mktmpdir do |root|
95+
agent_dir = unpack_agent_installer(root, file)
96+
install_insight(agent_dir)
97+
end
98+
99+
puts "(#{(Time.now - expand_start_time).duration})"
100+
end
101+
102+
def unpack_agent_installer(root, file)
103+
installer_dir = File.join root, 'installer'
104+
agent_dir = File.join root, 'agent'
105+
106+
FileUtils.mkdir_p(installer_dir)
107+
FileUtils.mkdir_p(agent_dir)
108+
shell "unzip -qq #{file.path} -d #{installer_dir} 2>&1"
109+
shell "unzip -qq #{uber_agent_zip(installer_dir)} -d #{agent_dir} 2>&1"
110+
111+
agent_dir
112+
end
113+
114+
def install_insight(agent_dir)
115+
weaver_directory = File.join insight_home, 'weaver'
116+
insight_directory = File.join insight_home, 'insight'
117+
insight_analyser_directory = File.join extra_applications_directory, 'insight-agent'
118+
uber_agent_directory = File.join agent_dir, 'springsource-insight-uber-agent-*'
119+
120+
shell "rm -rf #{insight_home}"
121+
shell "rm -rf #{insight_analyser_directory}"
122+
FileUtils.mkdir_p(container_libs_directory)
123+
FileUtils.mkdir_p(extra_applications_directory)
124+
FileUtils.mkdir_p(weaver_directory)
125+
FileUtils.mkdir_p(insight_directory)
126+
127+
shell "mv #{File.join uber_agent_directory, 'agents', 'common', 'insight-weaver-*.jar'} #{weaver_directory}"
128+
shell "mv #{File.join uber_agent_directory, 'agents', 'common', 'insight-bootstrap-generic-*.jar'} #{container_libs_directory}"
129+
shell "mv #{File.join uber_agent_directory, 'agents', 'tomcat', '7', 'lib', 'insight-bootstrap-tomcat-common-*.jar'} #{container_libs_directory}"
130+
shell "mv #{File.join uber_agent_directory, 'insight', 'collection-plugins'} #{insight_directory}"
131+
shell "mv #{File.join uber_agent_directory, 'insight', 'conf'} #{insight_directory}"
132+
shell "mv #{File.join uber_agent_directory, 'insight-agent'} #{insight_analyser_directory}"
133+
shell "mv #{File.join uber_agent_directory, 'transport', 'http', 'insight-agent-http-*.jar'} #{File.join insight_analyser_directory, 'WEB-INF', 'lib'} "
134+
end
135+
136+
def container_libs_directory
137+
File.join @app_dir, CONTAINER_LIBS_DIRECTORY
138+
end
139+
140+
def extra_applications_directory
141+
File.join @app_dir, EXTRA_APPLICATIONS_DIRECTORY
142+
end
143+
144+
def uber_agent_zip(location)
145+
candidates = Dir[File.join location, 'springsource-insight-uber-agent-*.zip']
146+
fail 'There was not exactly one Uber Agent zip' if candidates.size != 1
147+
candidates[0]
148+
end
149+
150+
def find_insight_agent
151+
service = JavaBuildpack::Util::ServiceUtils.find_service(@vcap_services, SERVICE_NAME)
152+
version = service['label'].match(/(.*)-(.*)/)[2]
153+
uri = service['credentials']['dashboard_url']
154+
155+
return version, uri # rubocop:disable RedundantReturn
156+
end
157+
158+
def insight_home
159+
File.join @app_dir, INSIGHT_HOME
160+
end
161+
162+
end
163+
164+
end

spec/fixtures/framework_spring_insight/.insight/weaver/insight-weaver-1.2.4-CI-SNAPSHOT.jar

Whitespace-only changes.
1.51 KB
Binary file not shown.

spec/java_buildpack/container/tomcat_spec.rb

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,58 @@ module JavaBuildpack::Container
195195
end
196196
end
197197

198+
it 'should link extra applications to the applications directory' do
199+
Dir.mktmpdir do |root|
200+
extra_applications_dir = File.join(root, '.extra-applications')
201+
Dir.mkdir extra_applications_dir
202+
Dir.mkdir File.join root, 'WEB-INF'
203+
system "cp -r spec/fixtures/framework_spring_insight #{extra_applications_dir}"
204+
205+
JavaBuildpack::Repository::ConfiguredItem.stub(:find_item) { |&block| block.call(TOMCAT_VERSION) if block }
206+
.and_return(TOMCAT_DETAILS, SUPPORT_DETAILS)
207+
208+
JavaBuildpack::Util::ApplicationCache.stub(:new).and_return(application_cache)
209+
application_cache.stub(:get).with('test-tomcat-uri').and_yield(File.open('spec/fixtures/stub-tomcat.tar.gz'))
210+
application_cache.stub(:get).with('test-support-uri').and_yield(File.open('spec/fixtures/stub-support.jar'))
211+
212+
Tomcat.new(
213+
app_dir: root,
214+
application: JavaBuildpack::Application.new(root),
215+
configuration: {}
216+
).compile
217+
218+
insight_test_dir = File.join root, '.tomcat', 'webapps', 'framework_spring_insight'
219+
expect(File.exists?(insight_test_dir)).to be_true
220+
expect(File.symlink?(insight_test_dir)).to be_true
221+
end
222+
end
223+
224+
it 'should link container libs to the tomcat lib directory' do
225+
Dir.mktmpdir do |root|
226+
container_libs_directory = File.join(root, '.container-libs')
227+
Dir.mkdir container_libs_directory
228+
Dir.mkdir File.join root, 'WEB-INF'
229+
system "cp -r spec/fixtures/framework_spring_insight/.insight/weaver/insight-weaver-1.2.4-CI-SNAPSHOT.jar #{container_libs_directory}"
230+
231+
JavaBuildpack::Repository::ConfiguredItem.stub(:find_item) { |&block| block.call(TOMCAT_VERSION) if block }
232+
.and_return(TOMCAT_DETAILS, SUPPORT_DETAILS)
233+
234+
JavaBuildpack::Util::ApplicationCache.stub(:new).and_return(application_cache)
235+
application_cache.stub(:get).with('test-tomcat-uri').and_yield(File.open('spec/fixtures/stub-tomcat.tar.gz'))
236+
application_cache.stub(:get).with('test-support-uri').and_yield(File.open('spec/fixtures/stub-support.jar'))
237+
238+
Tomcat.new(
239+
app_dir: root,
240+
application: JavaBuildpack::Application.new(root),
241+
configuration: {}
242+
).compile
243+
244+
insight_test_lib = File.join root, '.tomcat', 'lib', 'insight-weaver-1.2.4-CI-SNAPSHOT.jar'
245+
expect(File.exists?(insight_test_lib)).to be_true
246+
expect(File.symlink?(insight_test_lib)).to be_true
247+
end
248+
end
249+
198250
it 'should return command' do
199251
JavaBuildpack::Repository::ConfiguredItem.stub(:find_item) { |&block| block.call(TOMCAT_VERSION) if block }
200252
.and_return(TOMCAT_DETAILS, SUPPORT_DETAILS)

0 commit comments

Comments
 (0)