Skip to content

Commit

Permalink
Merge pull request #271 from dljvette/v1.2.1
Browse files Browse the repository at this point in the history
Release v1.2.1
  • Loading branch information
brndnblck authored Sep 25, 2020
2 parents a0e45b6 + 886e895 commit 030bc3a
Show file tree
Hide file tree
Showing 25 changed files with 2,684 additions and 83 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ codedeploy-local.*.log
deployment/
.idea/
.DS_STORE
*.iml
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ group :test do
gem 'fakefs', :require => 'fakefs/safe'
gem 'mocha'
gem 'rspec'
gem 'webmock', :require => 'webmock/rspec'
gem 'shoulda'
gem 'shoulda-matchers'
gem 'shoulda-context'
Expand Down
55 changes: 49 additions & 6 deletions bin/install
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,52 @@ end

@log.level = Logger::INFO

require 'net/http'
require 'json'

TOKEN_PATH = '/latest/api/token'
DOCUMENT_PATH = '/latest/dynamic/instance-identity/document'

class IMDSV2
def self.region
doc['region'].strip
end

private
def self.http_request(request)
Net::HTTP.start('169.254.169.254', 80, :read_timeout => 120, :open_timeout => 120) do |http|
response = http.request(request)
if response.code.to_i != 200
raise "HTTP error from metadata service: #{response.message}, code #{response.code}"
end
return response.body
end
end

def self.put_request(path)
request = Net::HTTP::Put.new(path)
request['X-aws-ec2-metadata-token-ttl-seconds'] = '21600'
http_request(request)
end

def self.get_request(path, token = nil)
request = Net::HTTP::Get.new(path)
unless token.nil?
request['X-aws-ec2-metadata-token'] = token
end
http_request(request)
end

def self.doc
begin
token = put_request(TOKEN_PATH)
JSON.parse(get_request(DOCUMENT_PATH, token).strip)
rescue
JSON.parse(get_request(DOCUMENT_PATH).strip)
end
end
end

begin
require 'fileutils'
require 'openssl'
Expand Down Expand Up @@ -208,12 +254,9 @@ EOF

def get_ec2_metadata_region
begin
uri = URI.parse('http://169.254.169.254/latest/dynamic/instance-identity/document')
document_string = uri.read(:read_timeout => 120)
doc = JSON.parse(document_string.strip)
return doc['region'].strip
rescue
@log.warn("Could not get region from EC2 metadata service at '#{uri.to_s}'")
return IMDSV2.region
rescue => error
@log.warn("Could not get region from EC2 metadata service at '#{error.message}'")
return nil
end
end
Expand Down
55 changes: 49 additions & 6 deletions bin/update
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,52 @@ end

@log.level = Logger::INFO

require 'net/http'
require 'json'

TOKEN_PATH = '/latest/api/token'
DOCUMENT_PATH = '/latest/dynamic/instance-identity/document'

class IMDSV2
def self.region
doc['region'].strip
end

private
def self.http_request(request)
Net::HTTP.start('169.254.169.254', 80, :read_timeout => 120, :open_timeout => 120) do |http|
response = http.request(request)
if response.code.to_i != 200
raise "HTTP error from metadata service: #{response.message}, code #{response.code}"
end
return response.body
end
end

def self.put_request(path)
request = Net::HTTP::Put.new(path)
request['X-aws-ec2-metadata-token-ttl-seconds'] = '21600'
http_request(request)
end

def self.get_request(path, token = nil)
request = Net::HTTP::Get.new(path)
unless token.nil?
request['X-aws-ec2-metadata-token'] = token
end
http_request(request)
end

def self.doc
begin
token = put_request(TOKEN_PATH)
JSON.parse(get_request(DOCUMENT_PATH, token).strip)
rescue
JSON.parse(get_request(DOCUMENT_PATH).strip)
end
end
end

require 'set'
VALID_TYPES = Set.new ['rpm','zypper','deb','msi']

Expand Down Expand Up @@ -275,12 +321,9 @@ EOF

def get_ec2_metadata_region
begin
uri = URI.parse('http://169.254.169.254/latest/dynamic/instance-identity/document')
document_string = uri.read(:read_timeout => 120)
doc = JSON.parse(document_string.strip)
return doc['region'].strip
rescue
@log.warn("Could not get region from EC2 metadata service at '#{uri.to_s}'")
return IMDSV2.region
rescue => error
@log.warn("Could not get region from EC2 metadata service at '#{error.message}'")
return nil
end
end
Expand Down
10 changes: 6 additions & 4 deletions codedeploy_agent.gemspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Gem::Specification.new do |spec|
spec.name = 'aws_codedeploy_agent'
spec.version = '1.1.2'
spec.version = '1.2.1'
spec.summary = 'Packages AWS CodeDeploy agent libraries'
spec.description = 'AWS CodeDeploy agent is responsible for doing the actual work of deploying software on an individual EC2 instance'
spec.author = 'Amazon Web Services'
Expand All @@ -14,13 +14,15 @@ Gem::Specification.new do |spec|
spec.add_dependency('gli', '~> 2.5')
spec.add_dependency('json_pure', '~> 1.6')
spec.add_dependency('archive-tar-minitar', '~> 0.5.2')
spec.add_dependency('rubyzip', '~> 1.1.0')
spec.add_dependency('rubyzip', '~> 1.3.0')
spec.add_dependency('logging', '~> 1.8')
spec.add_dependency('aws-sdk-core', '~> 2.9')
spec.add_dependency('aws-sdk-core', '~> 3')
spec.add_dependency('aws-sdk-code-generator', '~> 0.2.2.pre')
spec.add_dependency('aws-sdk-s3', '~> 1')
spec.add_dependency('simple_pid', '~> 0.2.1')
spec.add_dependency('docopt', '~> 0.5.0')
spec.add_dependency('concurrent-ruby', '~> 1.0.5')

spec.add_development_dependency('rake', '~> 10.0')
spec.add_development_dependency('rake', '~> 12.3.3')
spec.add_development_dependency('rspec', '~> 3.2.0')
end
1 change: 1 addition & 0 deletions features/step_definitions/common_steps.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'aws-sdk-core'
require 'aws-sdk-s3'

$:.unshift File.join(File.dirname(File.expand_path('../..', __FILE__)), 'features')
require 'step_definitions/step_constants'
Expand Down
3 changes: 2 additions & 1 deletion lib/instance_agent/file_credentials.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ def initialize(path)
private

def refresh
@credentials = Aws::SharedCredentials.new(path: @path)
@credentials = Aws::SharedCredentials.new(path: @path).credentials
raise "Failed to load credentials from path #{@path}" if @credentials.nil?
@expiration = Time.new + 1800
end
end
Expand Down
6 changes: 4 additions & 2 deletions lib/instance_agent/plugins/codedeploy/command_executor.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require 'openssl'
require 'fileutils'
require 'aws-sdk-core'
require 'aws-sdk-s3'
require 'zlib'
require 'zip'
require 'instance_metadata'
Expand All @@ -12,6 +13,7 @@
require 'instance_agent/plugins/codedeploy/deployment_specification'
require 'instance_agent/plugins/codedeploy/hook_executor'
require 'instance_agent/plugins/codedeploy/installer'
require 'instance_agent/string_utils'

module InstanceAgent
module Plugins
Expand Down Expand Up @@ -47,8 +49,8 @@ def initialize(options = {})

def self.command(name, &blk)
@command_methods ||= Hash.new

method = Seahorse::Util.underscore(name).to_sym
raise "Received command is not in PascalCase form: #{name.to_s}" unless StringUtils.is_pascal_case(name.to_s)
method = StringUtils.underscore(name.to_s)
@command_methods[name] = method

define_method(method, &blk)
Expand Down
16 changes: 16 additions & 0 deletions lib/instance_agent/string_utils.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module InstanceAgent
class StringUtils

def self.underscore(string)
string.
gsub(/([A-Z0-9]+)([A-Z][a-z])/, '\1_\2').
scan(/[a-z0-9]+|\d+|[A-Z0-9]+[a-z]*/).
join('_').downcase
end

def self.is_pascal_case(string)
!!(string =~ /^([A-Z][a-z0-9]+)+/)
end

end
end
60 changes: 44 additions & 16 deletions lib/instance_metadata.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,26 @@ class InstanceMetadata
PORT = 80
HTTP_TIMEOUT = 30

PARTITION_PATH = '/latest/meta-data/services/partition'
INSTANCE_ID_PATH = '/latest/meta-data/instance-id'
TOKEN_PATH = '/latest/api/token'
DOCUMENT_PATH = '/latest/dynamic/instance-identity/document'

def self.host_identifier
"arn:#{partition}:ec2:#{doc['region']}:#{doc['accountId']}:instance/#{doc['instanceId']}"
end

def self.partition
http_get('/latest/meta-data/services/partition').strip
get_metadata_wrapper(PARTITION_PATH).strip
end

def self.region
doc['region']
doc['region'].strip
end

def self.instance_id
begin
Net::HTTP.start(IP_ADDRESS, PORT) do |http|
response = http.get('/latest/meta-data/instance-id')
if response.code.to_i != 200
return nil
end
return response.body
end
get_metadata_wrapper(INSTANCE_ID_PATH)
rescue
return nil
end
Expand All @@ -39,19 +38,48 @@ class InstanceMetadataError < StandardError
end

private
def self.http_get(path)
Net::HTTP.start(IP_ADDRESS, PORT, :read_timeout => HTTP_TIMEOUT/2, :open_timeout => HTTP_TIMEOUT/2) do |http|
response = http.get(path)
def self.get_metadata_wrapper(path)
begin
token = put_request(TOKEN_PATH)
get_request(path, token)
rescue
InstanceAgent::Log.send(:info, "IMDSv2 http request failed, falling back to IMDSv1.")
get_request(path)
end

end

def self.http_request(request)
Net::HTTP.start(IP_ADDRESS, PORT, :read_timeout => 120, :open_timeout => 120) do |http|
response = http.request(request)
if response.code.to_i != 200
InstanceAgent::Log.send(:debug, "HTTP error from metadata service, code #{response.code}")
raise "HTTP error from metadata service, code #{response.code}"
raise "HTTP error from metadata service: #{response.message}, code #{response.code}"
end
return response.body
end
end

private
def self.put_request(path)
request = Net::HTTP::Put.new(path)
request['X-aws-ec2-metadata-token-ttl-seconds'] = '21600'
http_request(request)
end

def self.get_request(path, token = nil)
request = Net::HTTP::Get.new(path)
unless token.nil?
request['X-aws-ec2-metadata-token'] = token
end
http_request(request)
end

def self.doc
JSON.parse(http_get('/latest/dynamic/instance-identity/document').strip)
begin
token = put_request(TOKEN_PATH)
JSON.parse(get_request(DOCUMENT_PATH, token).strip)
rescue
InstanceAgent::Log.send(:info, "IMDSv2 http request failed, falling back to IMDSv1.")
JSON.parse(get_request(DOCUMENT_PATH).strip)
end
end
end
63 changes: 63 additions & 0 deletions spec/add_service_wrapper_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# frozen_string_literal: true
package_root = File.dirname(File.dirname(__FILE__))

require "#{package_root}/vendor/gems/codedeploy-commands-1.0.0/lib/aws/add_service_wrapper"

RSpec.describe 'add_service_wrapper' do

# This test is taken from the AwsSdkRubyCodeGenWrapper
# https://code.amazon.com/packages/AwsSdkRubyCodeGenWrapper/blobs/mainline/--/spec/add_service_wrapper_spec.rb
describe '#add_service' do
before(:all) do
@service_file = File.expand_path('../fixtures/sample_service.json', __FILE__)
@api = JSON.parse(File.read(@service_file))
@svc_class = Aws.add_service('GeneratedService', api: @api)
end

let(:client) {Aws::GeneratedService::Client.new(stub_responses: true) }

it 'can create a valid client' do
expect(client).to be_instance_of(Aws::GeneratedService::Client)
end

it 'can create a client from the returned namespace' do
expect(@svc_class::Client.new(stub_responses: true))
.to be_instance_of(Aws::GeneratedService::Client)
end

it 'can set constants on the returned namespace' do
@svc_class.const_set(:VERSION, '1.1.42')
expect(Aws::GeneratedService::VERSION).to eq('1.1.42')
end

it 'can add plugins to the generated client' do
class MyPlugin; end
Aws::GeneratedService::Client.add_plugin(MyPlugin)
expect(Aws::GeneratedService::Client.plugins).to include(MyPlugin)
end

it 'can generate a whitelabel (non-Aws) service' do
Aws.add_service('MyService', api: @api, whitelabel: true)
expect(MyService::Client.new(stub_responses: true))
.to be_instance_of(MyService::Client)
end

it 'loads the model from a string path' do
Aws.add_service('StringPathService', api: @service_file)
expect(Aws::StringPathService::Client.new(stub_responses: true))
.to be_instance_of(Aws::StringPathService::Client)
end

it 'loads the model from a PathName' do
Aws.add_service('PathService', api: Pathname.new(@service_file))
expect(Aws::PathService::Client.new(stub_responses: true))
.to be_instance_of(Aws::PathService::Client)
end

it 'raises an ArgumentError if api is not provided' do
expect do
Aws.add_service('NoApiService')
end.to raise_exception(ArgumentError)
end
end
end
Loading

0 comments on commit 030bc3a

Please sign in to comment.