Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Download sealights agent from 'customAgentUrl' #1050

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions config/sealights_agent.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Cloud Foundry Java Buildpack
# Copyright 2013-2020 the original author or authors.
# Copyright 2013-2024 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.
Expand All @@ -20,4 +20,5 @@ repository_root: https://agents.sealights.co/pcf
build_session_id:
lab_id:
proxy:
auto_upgrade: false
enable_upgrade: false
customAgentUrl:
14 changes: 8 additions & 6 deletions docs/framework-sealights_agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ Tags are printed to standard output by the buildpack detect script
When binding Sealights using a user-provided service, it must have name or tag with `sealights` in it.
The credential payload can contain the following entries.

| Name | Description
| ---- | -----------
| `token` | A Sealights Agent token
| `proxy` | Specify a HTTP proxy used to communicate with the Sealights backend. Required when a corporate network prohibits communication to cloud services. The default is to have no proxy configured. This does not inherit from `http_proxy`/`https_proxy` or `http.proxyHost/https.proxyHost`, you must set this specifically if a proxy is needed.
| `lab_id` | Specify a Sealights [Lab ID][]
| Name | Description
|------------------| -----------
| `token` | A Sealights Agent token
| `proxy` | Specify a HTTP proxy used to communicate with the Sealights backend. Required when a corporate network prohibits communication to cloud services. The default is to have no proxy configured. This does not inherit from `http_proxy`/`https_proxy` or `http.proxyHost/https.proxyHost`, you must set this specifically if a proxy is needed.
| `lab_id` | Specify a Sealights [Lab ID][]
| `customAgentUrl` | Specify an url to download zip containing custom Sealights agent jar. If the custom agent is downloaded then the 'enable_upgrade' is forced to 'false'

All fields above except the agent token may be also specified in the [Configuration Section](#configuration) below.

Expand All @@ -34,8 +35,9 @@ The framework can be configured by modifying the [`config/sealights_agent.yml`][
| `build_session_id` | Sealights [Build Session ID][] for the application. Leave blank to use the value embedded in the jar/war artifacts
| `proxy` | Specify a HTTP proxy used to communicate with the Sealights backend. Required when a corporate network prohibits communication to cloud services. The default is to have no proxy configured. This does not inherit from `http_proxy`/`https_proxy` or `http.proxyHost/https.proxyHost`, you must set this specifically if a proxy is needed.
| `lab_id` | Specify a Sealights [Lab ID][]
| `auto_upgrade` | Enable/disable agent auto-upgrade. Off by default
| `enable_upgrade` | Enable/disable agent auto-upgrade. Off by default
| `version` | The version of Auto-reconfiguration to use. Candidate versions can be found in [this listing][]. If auto_upgrade is turned on, a different version may be downloaded and used at runtime
| `customAgentUrl` | Specify an url to download zip containing custom Sealights agent jar. If the custom agent is downloaded then the 'enable_upgrade' is forced to 'false'

Configuration settings will take precedence over the ones specified in the [User-Provided Service](#user-provided-service), if those are defined.

Expand Down
68 changes: 63 additions & 5 deletions lib/java_buildpack/framework/sealights_agent.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

# Cloud Foundry Java Buildpack
# Copyright 2013-2020 the original author or authors.
# Copyright 2013-2024 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.
Expand All @@ -16,6 +16,7 @@
# limitations under the License.

require 'java_buildpack/framework'
require 'java_buildpack/buildpack_version'
require 'java_buildpack/component/versioned_dependency_component'
require 'shellwords'
require 'fileutils'
Expand All @@ -34,18 +35,33 @@ def initialize(context)

# (see JavaBuildpack::Component::BaseComponent#compile)
def compile
download_zip(false)
custom_download_uri = get_value(CUSTOM_AGENT_URL)
if custom_download_uri.nil?
download_zip(false)
else
target_directory = @droplet.sandbox
name = @component_name
download('custom-agent', custom_download_uri, name) do |file|
expand(file, name, target_directory)
end
end
end

# (see JavaBuildpack::Component::BaseComponent#release)
def release
@droplet.java_opts.add_javaagent(agent)
credentials = @application.services.find_service(FILTER, TOKEN)['credentials']
@droplet.java_opts.add_system_property('sl.token', Shellwords.escape(credentials[TOKEN]))
@droplet.java_opts.add_system_property('sl.tags', 'pivotal_cloud_foundry')
@droplet.java_opts.add_system_property('sl.tags', Shellwords.escape("sl-pcf-#{buildpack_version}"))

# add sl.enableUpgrade system property
@droplet.java_opts.add_system_property('sl.enableUpgrade', @configuration[ENABLE_UPGRADE] ? 'true' : 'false')
enable_upgrade_value = @configuration[ENABLE_UPGRADE] ? 'true' : 'false'
custom_download_uri = get_from_cfg_or_svc(credentials, CUSTOM_AGENT_URL)
unless custom_download_uri.nil? || enable_upgrade_value != 'true'
@logger.info { 'Switching sl.enableUpgrade to false because agent downloaded from customAgentUrl' }
enable_upgrade_value = 'false'
end
@droplet.java_opts.add_system_property('sl.enableUpgrade', enable_upgrade_value)

# add sl.proxy system property if defined (either in config or user provisioned service)
add_system_property_from_cfg_or_svc credentials, 'sl.proxy', PROXY
Expand Down Expand Up @@ -80,8 +96,48 @@ def supports?

private

def buildpack_version
version_hash = BuildpackVersion.new.to_hash
if version_hash.key?('version') && version_hash.key?('offline') && version_hash['offline']
version_hash['version'] + '(offline)'
elsif version_hash.key?('version')
version_hash['version']
else
'v-unknown'
end
end

def expand(file, name, target_directory)
with_timing "Expanding #{name} to #{target_directory.relative_path_from(@droplet.root)}" do
FileUtils.mkdir_p target_directory
shell "unzip -qq #{file.path} -d #{target_directory} 2>&1"
end
end

def agent
@droplet.sandbox + "sl-test-listener-#{@version}.jar"
custom_download_uri = get_value(CUSTOM_AGENT_URL)
if custom_download_uri.nil?
agent_jar_name = "sl-test-listener-#{@version}.jar"
else
jars = Dir["#{@droplet.sandbox}/sl-test-listener*.jar"]
raise 'Failed to find jar which name starts with \'sl-test-listener\' in downloaded zip' if jars.empty?

agent_jar_name = File.basename(jars[0])
end
@droplet.sandbox + agent_jar_name
end

def get_from_cfg_or_svc(svc, config_key)
if @configuration.key?(config_key)
@configuration[config_key]
elsif svc.key?(config_key)
svc[config_key]
end
end

def get_value(config_key)
svc = @application.services.find_service(FILTER, TOKEN)['credentials']
get_from_cfg_or_svc(svc, config_key)
end

# Configuration property names
Expand All @@ -95,6 +151,8 @@ def agent

PROXY = 'proxy'

CUSTOM_AGENT_URL = 'customAgentUrl'

FILTER = /sealights/.freeze

private_constant :TOKEN, :ENABLE_UPGRADE, :BUILD_SESSION_ID, :LAB_ID, :PROXY, :FILTER
Expand Down
Binary file not shown.
Binary file added spec/fixtures/stub-sealights-custom-agent.zip
Binary file not shown.
160 changes: 157 additions & 3 deletions spec/java_buildpack/framework/sealights_agent_spec.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

# Cloud Foundry Java Buildpack
# Copyright 2013-2020 the original author or authors.
# Copyright 2013-2024 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.
Expand Down Expand Up @@ -41,17 +41,53 @@
before do
allow(services).to receive(:one_service?).with(/sealights/, 'token').and_return(true)
allow(services).to receive(:find_service).and_return('credentials' => credentials)
uri = 'https://test-apiurl/getcustomagent/agent.zip'
p = Pathname.new('spec/fixtures/stub-sealights-custom-agent.zip')
allow(application_cache).to receive(:get).with(uri).and_yield(p.open, false)
end

it 'detects with sealights service' do
expect(component.detect).to eq("sealights-agent=#{version}")
end

context do
it 'updates JAVA_OPTS sl.tags' do
it 'updates JAVA_OPTS sl.tags with buildpack version number' do
allow_any_instance_of(JavaBuildpack::BuildpackVersion)
.to receive(:to_hash).and_return({ 'version' => '1234',
'offline' => false,
'remote' => 'test-remote',
'hash' => 'test-hash' })
component.release

expect(java_opts).to include('-Dsl.tags=pivotal_cloud_foundry')
expect(java_opts).to include('-Dsl.tags=sl-pcf-1234')
end

it 'updates JAVA_OPTS sl.tags with buildpack version number and offline info' do
allow_any_instance_of(JavaBuildpack::BuildpackVersion)
.to receive(:to_hash).and_return({ 'version' => '1234',
'offline' => true,
'remote' => 'test-remote',
'hash' => 'test-hash' })
component.release

expect(java_opts).to include('-Dsl.tags=sl-pcf-1234\(offline\)')
end

it 'updates JAVA_OPTS sl.tags with version number' do
allow_any_instance_of(JavaBuildpack::BuildpackVersion)
.to receive(:to_hash).and_return({ 'version' => '1234',
'remote' => 'test-remote',
'hash' => 'test-hash' })
component.release

expect(java_opts).to include('-Dsl.tags=sl-pcf-1234')
end

it 'updates JAVA_OPTS sl.tags with information about unknown version number' do
allow_any_instance_of(JavaBuildpack::BuildpackVersion).to receive(:to_hash).and_return({})
component.release

expect(java_opts).to include('-Dsl.tags=sl-pcf-v-unknown')
end

it 'updates JAVA_OPTS sl.buildSessionId' do
Expand Down Expand Up @@ -151,6 +187,124 @@
end
end

context do
let(:credentials) { { 'token' => 'my_token' } }

let(:configuration) do
{ 'build_session_id' => '1234',
'lab_id' => 'lab1',
'enable_upgrade' => true,
'customAgentUrl' => 'https://foo.com/getcustomagent/sealights-custom-agent.zip' }
end

before do
allow(services).to receive(:one_service?).with(/sealights/, 'token').and_return(true)
allow(services).to receive(:find_service).and_return('credentials' => credentials)
uri = 'https://foo.com/getcustomagent/sealights-custom-agent.zip'
p = Pathname.new('spec/fixtures/stub-sealights-custom-agent.zip')
allow(application_cache).to receive(:get).with(uri).and_yield(p.open, false)
allow(Net::HTTP).to receive(:start).with('foo.com', 443, use_ssl: true).and_call_original
stub_request(:get, uri)
.with(
headers: {
'Accept' => '*/*',
'User-Agent' => 'Ruby'
}
).to_return(status: 200, body: '', headers: {})

end

it 'downloads custom agent jar',
cache_fixture: 'stub-sealights-custom-agent.zip' do
component.compile
expect(sandbox + 'sl-test-listener-4.0.1.jar').to exist
end

it 'customAgentUrl from app configuration overwrites enableUpgrade to false',
cache_fixture: 'stub-sealights-custom-agent.zip' do
component.compile
component.release
expect(java_opts).to include('-Dsl.enableUpgrade=false')
end
end

context do
let(:credentials) do
{ 'token' => 'my_token',
'customAgentUrl' => 'https://foo.com/getcustomagent/sealights-custom-agent.zip' }
end

let(:configuration) do
{ 'build_session_id' => '1234',
'lab_id' => 'lab1',
'enable_upgrade' => true }
end

before do
allow(services).to receive(:one_service?).with(/sealights/, 'token').and_return(true)
allow(services).to receive(:find_service).and_return('credentials' => credentials)
uri = 'https://foo.com/getcustomagent/sealights-custom-agent.zip'
p = Pathname.new('spec/fixtures/stub-sealights-custom-agent.zip')
allow(application_cache).to receive(:get).with(uri).and_yield(p.open, false)
allow(Net::HTTP).to receive(:start).with('foo.com', 443, use_ssl: true).and_call_original
stub_request(:get, uri)
.with(
headers: {
'Accept' => '*/*',
'User-Agent' => 'Ruby'
}
).to_return(status: 200, body: '', headers: {})

end

it 'downloads custom agent jar based on service settings',
cache_fixture: 'stub-sealights-custom-agent.zip' do
component.compile
expect(sandbox + 'sl-test-listener-4.0.1.jar').to exist
end

it 'customAgentUrl from service settings forces overwrites enableUpgrade to false',
cache_fixture: 'stub-sealights-custom-agent.zip' do
component.compile
component.release
expect(java_opts).to include('-Dsl.enableUpgrade=false')
end
end

context do
let(:credentials) { { 'token' => 'my_token' } }

let(:configuration) do
{ 'build_session_id' => '1234',
'lab_id' => 'lab1',
'customAgentUrl' => 'https://foo.com/getcustomagent/sealights-custom-agent-invalid.zip' }
end

before do
allow(services).to receive(:one_service?).with(/sealights/, 'token').and_return(true)
allow(services).to receive(:find_service).and_return('credentials' => credentials)
uri = 'https://foo.com/getcustomagent/sealights-custom-agent-invalid.zip'
p = Pathname.new('spec/fixtures/stub-sealights-custom-agent-invalid.zip')
allow(application_cache).to receive(:get).with(uri).and_yield(p.open, false)
stub_request(:get, 'https://foo.com/getcustomagent/sealights-custom-agent-invalid.zip')
.with(
headers: {
'Accept' => '*/*',
'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
'User-Agent' => 'Ruby'
}
).to_return(status: 200, body: '', headers: {})
end

it 'test listener agent jar not found in downloaded zip',
cache_fixture: 'stub-sealights-custom-agent-invalid.zip' do
component.compile
expect { component.release }
.to raise_error(RuntimeError,
/Failed to find jar which name starts with 'sl-test-listener' in downloaded zip/)
end
end

end

end