Skip to content

Commit

Permalink
Merge pull request #266 from fujitsusystemswebtechnology/add-dynamicp…
Browse files Browse the repository at this point in the history
…ulse

Add DynamicPULSE as a framework.
  • Loading branch information
jgawor committed Feb 21, 2016
2 parents 2ee5bcc + 1ba4b78 commit 325c75a
Show file tree
Hide file tree
Showing 10 changed files with 288 additions and 0 deletions.
1 change: 1 addition & 0 deletions config/components.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ frameworks:
- "LibertyBuildpack::Framework::NewRelicAgent"
- "LibertyBuildpack::Framework::JRebelAgent"
- "LibertyBuildpack::Framework::DynaTraceAgent"
- "LibertyBuildpack::Framework::DynamicPULSEAgent"
27 changes: 27 additions & 0 deletions docs/framework-dynamic_pulse_agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# `DynamicPULSE Agent` Framework
The DynamicPULSE Agent Framework enables the use of DynamicPULSE Agent with deployed applications.
Pushing any DynamicPULSE enabled application (containing `dynamicpulse-remote.xml`) will automatically download the DynamicPULSE Agent and set it up for use.

<table>
<tr>
<td><strong>Detection Criterion</strong></td>
<td>Presence of a <tt>/WEB-INF/dynamicpulse-remote.xml</tt> file inside the application archive. The detail of this file is shown in DynamicPULSE Getting Started Guide.</td>
</tr>
<tr>
<td><strong>Tags</strong></td><td><tt>DynamicPULSE-&lt;version&gt;</tt></td>
</tr>
</table>
Tags are printed to standard output by the buildpack detect script.


## User Provided Service
Users must provide DynamicPULSE Center service on the SoftLayer through purchasing DynamicPULSE on IBM Cloud marketplace.


## Configuration
This framework does not have any configuration files.
For more information about configuring the buildpack, see [Configuration and Extension][].



[Configuration and Extension]: ../README.md#Configuration-and-Extension
106 changes: 106 additions & 0 deletions lib/liberty_buildpack/framework/dynamic_pulse_agent.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Encoding: utf-8
# IBM WebSphere Application Server Liberty Buildpack
# Copyright 2014-2015 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 'liberty_buildpack/diagnostics/common'
require 'liberty_buildpack/diagnostics/logger_factory'
require 'liberty_buildpack/framework'
require 'liberty_buildpack/framework/framework_utils'
require 'liberty_buildpack/repository/configured_item'
require 'liberty_buildpack/util/download'
require 'liberty_buildpack/util/tokenized_version'
require 'liberty_buildpack/container/common_paths'
require 'liberty_buildpack/services/vcap_services'
require 'pathname'
require 'fileutils'
require 'rexml/document'

module LibertyBuildpack::Framework

# Encapsulates the detection, compile, and release functionality for DynamicPULSE Agent
class DynamicPULSEAgent

# An initializer for the instance.
#
# @param [Hash<Symbol, String>] context A shared context provided to all components
# @option context [String] :app_dir the directory that the application exists in
# @option context [Hash] :environment A hash containing all environment variables except +VCAP_APPLICATION+ and
# +VCAP_SERVICES+. Those values are available separately in parsed form.
# @option context [Array<String>] :java_opts an array that Java options can be added to
# @option context [String] :lib_directory the directory that additional libraries are placed in
def initialize(context = {})
@logger = LibertyBuildpack::Diagnostics::LoggerFactory.get_logger
@app_dir = context[:app_dir]
@java_opts = context[:java_opts]
@lib_directory = context[:lib_directory]
end

# Detects whether DynamicPULSE Agent can attach
#
# @return [String, nil] returns DynamicPULSE-2.+ if DynamicPULSE Agent can attach otherwise returns +nil+
def detect
dynamicpulse_remote_xml = File.join(@app_dir, 'WEB-INF/dynamicpulse-remote.xml')
if File.exists?(dynamicpulse_remote_xml)
doc = REXML::Document.new(open(dynamicpulse_remote_xml))
@url = doc.elements['dynamicpulse-remote/centerUrl'].text
@system_id = doc.elements['dynamicpulse-remote/systemId'].text

@logger.debug("url=#{@url}")
@logger.debug("system_id=#{@system_id}")

return 'DynamicPULSE-3.+'
else
nil
end
end

# Downloads and places the DynamicPULSE JARs
#
# @return [void]
def compile
if @url.nil? || @system_id.nil?
raise "url #{@url}, or systemId #{@system_id} is not available, detect needs to be invoked"
end

dp_home = File.join(@app_dir, '.dynamic_pulse_agent')
FileUtils.mkdir_p(dp_home)

download_and_unzip(@url, @system_id, 'dynamicpulse-agent.zip', dp_home)

FileUtils.mv(File.join(dp_home, 'dynamicpulse.jar'), @lib_directory)
FrameworkUtils.link_libs([@app_dir], @lib_directory)
end

# Append VM options to java_opts
#
# @return [void]
def release
@java_opts << '-javaagent:/home/vcap/app/.dynamic_pulse_agent/aspectjweaver.jar'
@java_opts << '-Dorg.aspectj.tracing.factory=default'
end

# Downloads ZIP file from specified url
def download_and_unzip(base_url, system_id, filename, save_to_dir)
download_url = File.join(base_url, system_id, filename)
begin
LibertyBuildpack::Util.download('3.+', download_url, 'DynamicPULSE Agent', filename, save_to_dir)
rescue
@logger.error("[DynamicPULSE] Can't download #{filename} from #{download_url}. Please check dynamicpulse-remote.xml.")
raise
end
LibertyBuildpack::Container::ContainerUtils.unzip(File.join(save_to_dir, filename), save_to_dir)
end

end
end
5 changes: 5 additions & 0 deletions spec/fixtures/dynamicpulse-remote/dynamicpulse-remote.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<dynamicpulse-remote>
<centerUrl>http://downloadsite/dynamicpulse/</centerUrl>
<systemId>SampleWebApp</systemId>
</dynamicpulse-remote>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<dynamicpulse-remote>
<centerUrl>http://hoge/dynamicpulse/</centerUrl>
<systemId>SampleWebApp</systemId>
</dynamicpulse-remote>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<centerUrl>http://downloadsite/dynamicpulse/</centerUrl>
<systemId>SampleWebApp</systemId>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<dynamicpulse-remote>
<systemId>SampleWebApp</systemId>
</dynamicpulse-remote>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<dynamicpulse-remote>
<centerUrl>http://downloadsite/dynamicpulse/</centerUrl>
</dynamicpulse-remote>
Binary file added spec/fixtures/stub-dynamic-pulse-agent.zip
Binary file not shown.
134 changes: 134 additions & 0 deletions spec/liberty_buildpack/framework/dynamic_pulse_agent_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# Encoding: utf-8
# IBM WebSphere Application Server Liberty Buildpack
# Copyright 2016 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 'liberty_buildpack/framework/dynamic_pulse_agent'
require 'liberty_buildpack/container/common_paths'

module LibertyBuildpack::Framework

describe 'DynamicPULSEAgent' do
include_context 'component_helper' # component context

let(:remote_dir) { File.expand_path('../../fixtures/dynamicpulse-remote', File.dirname(__FILE__)) }
let(:app_dir) { File.join(remote_dir, 'app') }
let(:webinf_dir) { File.join(app_dir, 'WEB-INF') }
let(:application_cache) { double('ApplicationCache') }
let(:lib_directory) { File.join(webinf_dir, 'lib') }

before do | example |
# default values for the new relic index.yml info for tests
index_uri = 'http://downloadsite/dynamicpulse/SampleWebApp/dynamicpulse-agent.zip'

# tests can set find_item=false and a raise_error_message to mock a failed return of processing the index.yml
LibertyBuildpack::Repository::ConfiguredItem.stub(:find_item).and_raise(example.metadata[:raise_error_message])

# For a download request of a new relic agent jar, return the fixture jar
LibertyBuildpack::Util::Cache::ApplicationCache.stub(:new).and_return(application_cache)
application_cache.stub(:get).with(index_uri).and_yield(File.open('spec/fixtures/stub-dynamic-pulse-agent.zip'))

FileUtils.mkdir_p(lib_directory)
end

describe 'configuration' do
it 'must have url and systemId' do
FileUtils.cp(File.join(remote_dir, 'dynamicpulse-remote.xml'), File.join(webinf_dir, 'dynamicpulse-remote.xml'))
dynamicpulse_remote_xml = File.join(webinf_dir, 'dynamicpulse-remote.xml')
doc = REXML::Document.new(open(dynamicpulse_remote_xml))
url = doc.elements['dynamicpulse-remote/centerUrl'].text

expect(url).to eq('http://downloadsite/dynamicpulse/')
end

it 'must have url and systemId' do
FileUtils.cp(File.join(remote_dir, 'dynamicpulse-remote.xml'), File.join(webinf_dir, 'dynamicpulse-remote.xml'))
dynamicpulse_remote_xml = File.join(webinf_dir, 'dynamicpulse-remote.xml')
doc = REXML::Document.new(open(dynamicpulse_remote_xml))
system_id = doc.elements['dynamicpulse-remote/systemId'].text

expect(system_id).to eq('SampleWebApp')
end
end

describe 'detect' do
subject(:detected) do
dynamicpulse = DynamicPULSEAgent.new(app_dir: app_dir, lib_directory: lib_directory)
dynamicpulse.detect
end

it 'should be detected when the dynamicpulse-remote.xml is valid' do
FileUtils.cp(File.join(remote_dir, 'dynamicpulse-remote.xml'), File.join(webinf_dir, 'dynamicpulse-remote.xml'))
expect(detected).to eq('DynamicPULSE-3.+')
end

it 'should not be detected if the dynamicpulse-remote.xml is nothing' do
expect(detected).to eq(nil)
end

it 'should raise an error with ParseException if xml file is illegal format' do
FileUtils.cp(File.join(remote_dir, 'dynamicpulse-remote_illegalFormat.xml'), File.join(webinf_dir, 'dynamicpulse-remote.xml'))
expect { detected }.to raise_error(REXML::ParseException)
end
end

describe 'compile' do
subject(:compiled) do
dynamicpulse = DynamicPULSEAgent.new(app_dir: app_dir, lib_directory: lib_directory)
dynamicpulse.detect
dynamicpulse.compile
end

it 'should create a dynamicpulse home directory in the application root' do
FileUtils.cp(File.join(remote_dir, 'dynamicpulse-remote.xml'), File.join(webinf_dir, 'dynamicpulse-remote.xml'))
compiled
expect(File.exist?(File.join(app_dir, '.dynamic_pulse_agent'))).to eq(true)
end

it 'should download the agent with a matching centerUrl and systemId' do
FileUtils.cp(File.join(remote_dir, 'dynamicpulse-remote.xml'), File.join(webinf_dir, 'dynamicpulse-remote.xml'))
expect { compiled }.to output(%r{Downloading DynamicPULSE Agent 3.+ from http://downloadsite/dynamicpulse/SampleWebApp/dynamicpulse-agent.zip}).to_stdout
expect(File.exists?(File.join(app_dir, '.dynamic_pulse_agent', 'dynamicpulse-agent.zip'))).to eq(true)
end

it 'should raise an error if the illegal centerUrl is in the dynamicpulse-remote.xml' do
FileUtils.cp(File.join(remote_dir, 'dynamicpulse-remote_illegalCenterUrl.xml'), File.join(webinf_dir, 'dynamicpulse-remote.xml'))
allow(LibertyBuildpack::Util).to receive(:download).and_raise('underlying download error')
end

it 'should raise an error if the centerUrl is not in the dynamicpulse-remote.xml' do
FileUtils.cp(File.join(remote_dir, 'dynamicpulse-remote_notCenterUrl.xml'), File.join(webinf_dir, 'dynamicpulse-remote.xml'))
dynamicpulse = DynamicPULSEAgent.new(app_dir: app_dir, lib_directory: lib_directory)
expect { dynamicpulse.compile }.to raise_error(/url , or systemId is not available, detect needs to be invoked/)
end
end

describe 'release' do
subject(:released) do
dynamicpulse = DynamicPULSEAgent.new(app_dir: app_dir, lib_directory: lib_directory, java_opts: [])
dynamicpulse.detect
dynamicpulse.compile
dynamicpulse.release
end

it 'should return command line options for a valid service in a default container' do
FileUtils.cp(File.join(remote_dir, 'dynamicpulse-remote.xml'), File.join(webinf_dir, 'dynamicpulse-remote.xml'))
expect(released).to include('-javaagent:/home/vcap/app/.dynamic_pulse_agent/aspectjweaver.jar')
expect(released).to include('-Dorg.aspectj.tracing.factory=default')
end
end
end
end # module

0 comments on commit 325c75a

Please sign in to comment.