This repository has been archived by the owner on Dec 31, 2022. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(source): Added support for HTTP
- Loading branch information
Showing
13 changed files
with
370 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
# frozen_string_literal: true | ||
|
||
module Drivers | ||
module Source | ||
class Http < Drivers::Source::Base | ||
adapter :http | ||
allowed_engines :archive, :http | ||
packages debian: %w[bzip2 git gzip p7zip tar unzip xz-utils], | ||
rhel: %w[bzip2 git gzip tar unzip xz] | ||
output filter: %i[user password url] | ||
|
||
def initialize(context, app, options = {}) | ||
super | ||
@file_name = File.basename(URI.parse(out[:url]).path) | ||
end | ||
|
||
def before_deploy | ||
prepare_archive_directories | ||
fetch_archive_from_http | ||
prepare_dummy_git_repository | ||
end | ||
|
||
def deploy_before_restart | ||
remove_dot_git | ||
end | ||
|
||
def fetch(deploy_context) | ||
deploy_context.repository(dummy_repository_dir) | ||
end | ||
|
||
private | ||
|
||
def prepare_archive_directories | ||
context.directory(archive_file_dir) do | ||
mode '0700' | ||
end | ||
|
||
context.directory(dummy_repository_dir) do | ||
mode '0700' | ||
end | ||
end | ||
|
||
def fetch_archive_from_http | ||
uri = URI.parse(out[:url]) | ||
uri.userinfo = "#{out[:user]}:#{out[:password]}" | ||
|
||
context.remote_file File.join(archive_file_dir, @file_name) do | ||
source uri.to_s | ||
owner node['deployer']['user'] || 'root' | ||
group www_group | ||
mode '0600' | ||
action :create | ||
end | ||
end | ||
|
||
def prepare_dummy_git_repository | ||
chef_archive_file_dir = archive_file_dir | ||
chef_dummy_repository_dir = dummy_repository_dir | ||
file_name = @file_name | ||
|
||
context.ruby_block 'extract' do | ||
block do | ||
OpsworksRuby::Archive.new(File.join(chef_archive_file_dir, file_name)).uncompress(chef_dummy_repository_dir) | ||
end | ||
end | ||
|
||
context.execute dummy_git_command | ||
end | ||
|
||
def remove_dot_git | ||
context.directory File.join(deploy_dir(app), 'current', '.git') do | ||
recursive true | ||
action :delete | ||
end | ||
end | ||
|
||
def dummy_git_command | ||
"cd #{dummy_repository_dir} && git init && git config user.name 'Chef' && " \ | ||
'git config user.email \'chef@localhost\' && git add -A && ' \ | ||
'git commit --author=\'Chef <>\' -m \'dummy repo\' -an' | ||
end | ||
|
||
def archive_file_dir | ||
@archive_file_dir ||= File.join(tmpdir, 'archive') | ||
end | ||
|
||
def dummy_repository_dir | ||
@dummy_repository_dir ||= File.join(tmpdir, 'archive.d') | ||
end | ||
|
||
def tmpdir | ||
return @tmpdir if @tmpdir.present? | ||
|
||
@tmpdir = Dir.mktmpdir('opsworks_ruby') | ||
|
||
context.directory(@tmpdir) do | ||
mode '0755' | ||
end | ||
|
||
@tmpdir | ||
end | ||
|
||
# taken from https://github.com/aws/opsworks-cookbooks/blob/release-chef-11.10/scm_helper/libraries/s3.rb#L6 | ||
def parse_uri(uri) # rubocop:disable Metrics/MethodLength | ||
# base_uri | remote_path | ||
#----------------------------------------+------------------------------ | ||
# scheme, userinfo, host, port, registry | path, opaque, query, fragment | ||
|
||
components = URI.split(uri) | ||
base_uri = URI::HTTP.new(*(components.take(5) + [nil] * 4)) | ||
remote_path = URI::HTTP.new(*([nil] * 5 + components.drop(5))) | ||
|
||
virtual_host_match = | ||
base_uri.host.match(/\A(.+)\.s3(?:[-.](?:ap|eu|sa|us)-(?:.+-)\d|-external-1)?\.amazonaws\.com/i) | ||
|
||
if virtual_host_match | ||
# virtual-hosted-style: http://bucket.s3.amazonaws.com or http://bucket.s3-aws-region.amazonaws.com | ||
bucket = virtual_host_match[1] | ||
else | ||
# path-style: http://s3.amazonaws.com/bucket or http://s3-aws-region.amazonaws.com/bucket | ||
uri_path_components = remote_path.path.split('/').reject(&:empty?) | ||
bucket = uri_path_components.shift # cut first element | ||
base_uri.path = "/#{bucket}" # append bucket to base_uri | ||
remote_path.path = uri_path_components.join('/') # delete bucket from remote_path | ||
end | ||
|
||
# remote_path don't allow a "/" at the beginning | ||
# base_url don't allow a "/" at the end | ||
[bucket, remote_path.to_s.to_s.sub(%r{^/}, ''), base_uri.to_s.chomp('/')] | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'spec_helper' | ||
|
||
describe Drivers::Source::Http do | ||
let(:http_aws_opsworks_app) do | ||
aws_opsworks_app( | ||
app_source: { | ||
password: 'password', | ||
type: 'archive', | ||
url: 'https://example.com/path/file.tar.gz', | ||
user: 'user' | ||
} | ||
) | ||
end | ||
let(:driver) { described_class.new(dummy_context(node), http_aws_opsworks_app) } | ||
|
||
it 'receives and exposes app and node' do | ||
expect(driver.app).to eq http_aws_opsworks_app | ||
expect(driver.send(:node)).to eq node | ||
expect(driver.options).to eq({}) | ||
end | ||
|
||
it 'has the correct driver_type' do | ||
expect(driver.driver_type).to eq('source') | ||
end | ||
|
||
context 'validate adapter and engine' do | ||
it 'adapter = missing, engine = missing' do | ||
expect do | ||
described_class.new(dummy_context(node(deploy: { dummy_project: {} })), aws_opsworks_app(app_source: nil)).out | ||
end.to raise_error ArgumentError, | ||
"Missing :app or :node engine, expected #{described_class.allowed_engines.inspect}." | ||
end | ||
|
||
it 'adapter = missing, engine = wrong' do | ||
expect do | ||
described_class.new( | ||
dummy_context(node(deploy: { dummy_project: {} })), | ||
aws_opsworks_app(app_source: { type: 'svn' }) | ||
).out | ||
end.to raise_error ArgumentError, | ||
"Incorrect :app engine, expected #{described_class.allowed_engines.inspect}, got 'svn'." | ||
end | ||
|
||
it 'adapter = missing, engine = correct' do | ||
expect do | ||
described_class.new(dummy_context(node(deploy: { dummy_project: {} })), http_aws_opsworks_app).out | ||
end.not_to raise_error | ||
end | ||
|
||
it 'adapter = wrong, engine = missing' do | ||
expect do | ||
described_class.new( | ||
dummy_context( | ||
node(deploy: { dummy_project: { source: { adapter: 'svn' } } }) | ||
), | ||
aws_opsworks_app(app_source: nil) | ||
).out | ||
end.to raise_error ArgumentError, | ||
"Incorrect :node engine, expected #{described_class.allowed_engines.inspect}, got 'svn'." | ||
end | ||
|
||
it 'adapter = wrong, engine = wrong' do | ||
expect do | ||
described_class.new( | ||
dummy_context(node(deploy: { dummy_project: { source: { adapter: 'svn' } } })), | ||
aws_opsworks_app(app_source: { type: 'svn' }) | ||
).out | ||
end.to raise_error ArgumentError, | ||
"Incorrect :app engine, expected #{described_class.allowed_engines.inspect}, got 'svn'." | ||
end | ||
|
||
it 'adapter = wrong, engine = correct' do | ||
expect do | ||
described_class.new( | ||
dummy_context(node(deploy: { dummy_project: { source: { adapter: 'svn' } } })), http_aws_opsworks_app | ||
).out | ||
end.not_to raise_error | ||
end | ||
|
||
it 'adapter = correct, engine = missing' do | ||
expect do | ||
described_class.new( | ||
dummy_context( | ||
node(deploy: { dummy_project: { source: { adapter: 'http', url: 'http://example.com' } } }) | ||
), | ||
aws_opsworks_app(app_source: nil) | ||
).out | ||
end.not_to raise_error | ||
end | ||
|
||
it 'adapter = correct, engine = wrong' do | ||
expect do | ||
described_class.new( | ||
dummy_context(node(deploy: { dummy_project: { source: { adapter: 'http' } } })), | ||
aws_opsworks_app(app_source: { type: 'svn' }) | ||
).out | ||
end.to raise_error ArgumentError, | ||
"Incorrect :app engine, expected #{described_class.allowed_engines.inspect}, got 'svn'." | ||
end | ||
|
||
it 'adapter = correct, engine = correct' do | ||
expect do | ||
described_class.new( | ||
dummy_context(node(deploy: { dummy_project: { source: { adapter: 'http' } } })), http_aws_opsworks_app | ||
).out | ||
end.not_to raise_error | ||
end | ||
end | ||
|
||
context 'connection data' do | ||
after(:each) do | ||
expect(@item.out).to eq( | ||
password: 'password', | ||
url: 'https://example.com/path/file.tar.gz', | ||
user: 'user' | ||
) | ||
end | ||
|
||
it 'taken from engine' do | ||
@item = described_class.new(dummy_context(node), http_aws_opsworks_app) | ||
end | ||
|
||
it 'taken from adapter' do | ||
node_data = node | ||
node_data['deploy']['dummy_project']['source'] = { | ||
'adapter' => 'http', | ||
'password' => 'password', | ||
'url' => 'https://example.com/path/file.tar.gz', | ||
'user' => 'user' | ||
} | ||
@item = described_class.new(dummy_context(node_data), aws_opsworks_app(app_source: nil)) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.