mirror of
https://github.com/fog/fog.git
synced 2022-11-09 13:51:43 -05:00
[aws|compute] Allow mock tagging to work across accounts.
This moves tag_sets out of individual resources and up to a top-level item in each mock account's hash. Starting with images, this allows other mock accounts to create and use their own tags on images they have launchPermission on.
This commit is contained in:
parent
661667eff8
commit
890929ca6b
12 changed files with 96 additions and 42 deletions
|
@ -152,7 +152,10 @@ module Fog
|
|||
},
|
||||
:snapshots => {},
|
||||
:volumes => {},
|
||||
:tags => {}
|
||||
:tags => {},
|
||||
:tag_sets => Hash.new do |tag_set_hash, resource_id|
|
||||
tag_set_hash[resource_id] = {}
|
||||
end
|
||||
}
|
||||
end
|
||||
end
|
||||
|
@ -172,34 +175,56 @@ module Fog
|
|||
end
|
||||
end
|
||||
|
||||
def region_data
|
||||
self.class.data[@region]
|
||||
end
|
||||
|
||||
def data
|
||||
self.class.data[@region][@aws_access_key_id]
|
||||
self.region_data[@aws_access_key_id]
|
||||
end
|
||||
|
||||
def reset_data
|
||||
self.class.data[@region].delete(@aws_access_key_id)
|
||||
self.region_data.delete(@aws_access_key_id)
|
||||
end
|
||||
|
||||
def apply_tag_filters(resources, filters)
|
||||
def visible_images
|
||||
images = self.data[:images].values.inject({}) do |h, image|
|
||||
h.update(image['imageId'] => image)
|
||||
end
|
||||
|
||||
self.region_data.each do |aws_access_key_id, data|
|
||||
data[:image_launch_permissions].each do |image_id, list|
|
||||
if list[:users].include?(self.data[:owner_id])
|
||||
images.update(image_id => data[:images][image_id])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
images
|
||||
end
|
||||
|
||||
def apply_tag_filters(resources, filters, resource_id_key)
|
||||
tag_set_fetcher = lambda {|resource| self.data[:tag_sets][resource[resource_id_key]] }
|
||||
|
||||
# tag-key: match resources tagged with this key (any value)
|
||||
if filters.has_key?('tag-key')
|
||||
value = filters.delete('tag-key')
|
||||
resources = resources.select{|r| r['tagSet'].has_key?(value)}
|
||||
resources = resources.select{|r| tag_set_fetcher[r].has_key?(value)}
|
||||
end
|
||||
|
||||
# tag-value: match resources tagged with this value (any key)
|
||||
if filters.has_key?('tag-value')
|
||||
value = filters.delete('tag-value')
|
||||
resources = resources.select{|r| r['tagSet'].values.include?(value)}
|
||||
resources = resources.select{|r| tag_set_fetcher[r].values.include?(value)}
|
||||
end
|
||||
|
||||
# tag:key: match resources taged with a key-value pair. Value may be an array, which is OR'd.
|
||||
# tag:key: match resources tagged with a key-value pair. Value may be an array, which is OR'd.
|
||||
tag_filters = {}
|
||||
filters.keys.each do |key|
|
||||
tag_filters[key.gsub('tag:', '')] = filters.delete(key) if /^tag:/ =~ key
|
||||
end
|
||||
for tag_key, tag_value in tag_filters
|
||||
resources = resources.select{|r| tag_value.include?(r['tagSet'][tag_key])}
|
||||
resources = resources.select{|r| tag_value.include?(tag_set_fetcher[r][tag_key])}
|
||||
end
|
||||
|
||||
resources
|
||||
|
|
|
@ -59,7 +59,6 @@ module Fog
|
|||
response.body = {
|
||||
'requestId' => Fog::AWS::Mock.request_id
|
||||
}.merge!(data)
|
||||
self.data[:snapshots][snapshot_id]['tagSet'] = {}
|
||||
else
|
||||
response.status = 400
|
||||
raise(Excon::Errors.status_error({:expects => 200}, response))
|
||||
|
|
|
@ -53,7 +53,7 @@ module Fog
|
|||
when /^vol\-[a-z0-9]{8}$/i
|
||||
'volume'
|
||||
end
|
||||
if type && self.data[:"#{type}s"][resource_id]
|
||||
if type && ((type == 'image' && visible_images[resource_id]) || self.data[:"#{type}s"][resource_id])
|
||||
{ 'resourceId' => resource_id, 'resourceType' => type }
|
||||
else
|
||||
raise(Fog::Service::NotFound.new("The #{type} ID '#{resource_id}' does not exist"))
|
||||
|
@ -65,7 +65,9 @@ module Fog
|
|||
self.data[:tags][key][value] ||= []
|
||||
self.data[:tags][key][value] |= tagged
|
||||
|
||||
tagged.each {|resource| self.data[:"#{resource['resourceType']}s"][resource['resourceId']]['tagSet'][key] = value}
|
||||
tagged.each do |resource|
|
||||
self.data[:tag_sets][resource['resourceId']][key] = value
|
||||
end
|
||||
end
|
||||
|
||||
response = Excon::Response.new
|
||||
|
|
|
@ -60,7 +60,6 @@ module Fog
|
|||
'size' => size,
|
||||
'snapshotId' => snapshot_id,
|
||||
'status' => 'creating',
|
||||
'tagSet' => {},
|
||||
'volumeId' => volume_id
|
||||
}
|
||||
self.data[:volumes][volume_id] = data
|
||||
|
|
|
@ -53,7 +53,7 @@ module Fog
|
|||
when /^vol\-[a-z0-9]{8}$/i
|
||||
'volume'
|
||||
end
|
||||
if type && self.data[:"#{type}s"][resource_id]
|
||||
if type && ((type == 'image' && visible_images[resource_id]) || self.data[:"#{type}s"][resource_id])
|
||||
{ 'resourceId' => resource_id, 'resourceType' => type }
|
||||
else
|
||||
raise(Fog::Service::NotFound.new("The #{type} ID '#{resource_id}' does not exist"))
|
||||
|
@ -65,9 +65,8 @@ module Fog
|
|||
end
|
||||
|
||||
tagged.each do |resource|
|
||||
object = self.data[:"#{resource['resourceType']}s"][resource['resourceId']]
|
||||
tags.each do |key, value|
|
||||
tagset = object['tagSet']
|
||||
tagset = self.data[:tag_sets][resource['resourceId']]
|
||||
tagset.delete(key) if tagset.has_key?(key) && (value.nil? || tagset[key] == value)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -98,24 +98,13 @@ module Fog
|
|||
'virtualization-type' => 'virtualizationType'
|
||||
}
|
||||
|
||||
image_set = self.data[:images].values
|
||||
|
||||
self.class.data[@region].each do |aws_access_key_id, data|
|
||||
data[:image_launch_permissions].each do |image_id, list|
|
||||
if list[:users].include?(self.data[:owner_id])
|
||||
image_set << data[:images][image_id]
|
||||
end
|
||||
end
|
||||
end
|
||||
image_set = visible_images.values
|
||||
image_set = apply_tag_filters(image_set, filters, 'imageId')
|
||||
|
||||
for filter_key, filter_value in filters
|
||||
if tag_key = filter_key.split('tag:')[1]
|
||||
image_set = image_set.reject{|image| ![*filter_value].include?(image['tagSet'][tag_key])}
|
||||
else
|
||||
aliased_key = aliases[filter_key]
|
||||
image_set = image_set.reject{|image| ![*filter_value].include?(image[aliased_key])}
|
||||
end
|
||||
end
|
||||
|
||||
image_set = image_set.map do |image|
|
||||
case image['imageState']
|
||||
|
@ -124,7 +113,7 @@ module Fog
|
|||
image['imageState'] = 'available'
|
||||
end
|
||||
end
|
||||
image.reject { |key, value| ['registered'].include?(key) }
|
||||
image.reject { |key, value| ['registered'].include?(key) }.merge('tagSet' => self.data[:tag_sets][image['imageId']])
|
||||
end
|
||||
|
||||
response.status = 200
|
||||
|
|
|
@ -88,7 +88,7 @@ module Fog
|
|||
response = Excon::Response.new
|
||||
|
||||
instance_set = self.data[:instances].values
|
||||
instance_set = apply_tag_filters(instance_set, filters)
|
||||
instance_set = apply_tag_filters(instance_set, filters, 'instanceId')
|
||||
|
||||
aliases = {
|
||||
'architecture' => 'architecture',
|
||||
|
@ -196,7 +196,7 @@ module Fog
|
|||
'ownerId' => instance['ownerId'],
|
||||
'reservationId' => instance['reservationId']
|
||||
}
|
||||
reservation_set[instance['reservationId']]['instancesSet'] << instance.reject{|key,value| !['amiLaunchIndex', 'architecture', 'blockDeviceMapping', 'clientToken', 'dnsName', 'imageId', 'instanceId', 'instanceState', 'instanceType', 'ipAddress', 'kernelId', 'keyName', 'launchTime', 'monitoring', 'placement', 'platform', 'privateDnsName', 'privateIpAddress', 'productCodes', 'ramdiskId', 'reason', 'rootDeviceType', 'stateReason', 'tagSet'].include?(key)}
|
||||
reservation_set[instance['reservationId']]['instancesSet'] << instance.reject{|key,value| !['amiLaunchIndex', 'architecture', 'blockDeviceMapping', 'clientToken', 'dnsName', 'imageId', 'instanceId', 'instanceState', 'instanceType', 'ipAddress', 'kernelId', 'keyName', 'launchTime', 'monitoring', 'placement', 'platform', 'privateDnsName', 'privateIpAddress', 'productCodes', 'ramdiskId', 'reason', 'rootDeviceType', 'stateReason'].include?(key)}.merge('tagSet' => self.data[:tag_sets][instance['instanceId']])
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ module Fog
|
|||
Fog::Logger.warning("describe_snapshots with RestorableBy other than 'self' (wanted #{restorable_by.inspect}) is not mocked [light_black](#{caller.first})[/]")
|
||||
end
|
||||
|
||||
snapshot_set = apply_tag_filters(snapshot_set, filters)
|
||||
snapshot_set = apply_tag_filters(snapshot_set, filters, 'snapshotId')
|
||||
|
||||
aliases = {
|
||||
'description' => 'description',
|
||||
|
@ -106,6 +106,8 @@ module Fog
|
|||
end
|
||||
end
|
||||
|
||||
snapshot_set = snapshot_set.map {|snapshot| snapshot.merge('tagSet' => self.data[:tag_sets][snapshot['snapshotId']]) }
|
||||
|
||||
response.status = 200
|
||||
response.body = {
|
||||
'requestId' => Fog::AWS::Mock.request_id,
|
||||
|
|
|
@ -55,7 +55,7 @@ module Fog
|
|||
response = Excon::Response.new
|
||||
|
||||
volume_set = self.data[:volumes].values
|
||||
volume_set = apply_tag_filters(volume_set, filters)
|
||||
volume_set = apply_tag_filters(volume_set, filters, 'volumeId')
|
||||
|
||||
aliases = {
|
||||
'availability-zone' => 'availabilityZone',
|
||||
|
@ -102,6 +102,7 @@ module Fog
|
|||
end
|
||||
end
|
||||
volume_set = volume_set.reject {|volume| !self.data[:volumes][volume['volumeId']]}
|
||||
volume_set = volume_set.map {|volume| volume.merge('tagSet' => self.data[:tag_sets][volume['volumeId']]) }
|
||||
|
||||
response.status = 200
|
||||
response.body = {
|
||||
|
|
|
@ -86,7 +86,6 @@ module Fog
|
|||
'rootDeviceName' => '',
|
||||
'blockDeviceMapping' => [],
|
||||
'virtualizationType' => 'paravirtual',
|
||||
'tagSet' => {},
|
||||
'hypervisor' => 'xen',
|
||||
'registered' => Time.now
|
||||
}
|
||||
|
|
|
@ -157,8 +157,7 @@ module Fog
|
|||
'ownerId' => self.data[:owner_id],
|
||||
'privateIpAddress' => nil,
|
||||
'reservationId' => reservation_id,
|
||||
'stateReason' => {},
|
||||
'tagSet' => {}
|
||||
'stateReason' => {}
|
||||
})
|
||||
end
|
||||
response.body = {
|
||||
|
|
|
@ -13,14 +13,54 @@ Shindo.tests('Fog::Compute[:aws] | tag requests', ['aws']) do
|
|||
@volume.wait_for { ready? }
|
||||
|
||||
tests('success') do
|
||||
if Fog.mocking?
|
||||
@other_account = Fog::Compute::AWS.new(:aws_access_key_id => 'other', :aws_secret_access_key => 'account')
|
||||
@image_id = Fog::Compute[:aws].register_image('image', 'image', '/dev/sda1').body['imageId']
|
||||
end
|
||||
|
||||
tests("#create_tags('#{@volume.identity}', 'foo' => 'bar')").formats(AWS::Compute::Formats::BASIC) do
|
||||
Fog::Compute[:aws].create_tags(@volume.identity, 'foo' => 'bar').body
|
||||
end
|
||||
|
||||
if Fog.mocking?
|
||||
tests("#create_tags('#{@image_id}', 'foo' => 'baz')").formats(AWS::Compute::Formats::BASIC) do
|
||||
Fog::Compute[:aws].create_tags(@image_id, 'foo' => 'baz').body
|
||||
end
|
||||
end
|
||||
|
||||
tests('#describe_tags').formats(@tags_format) do
|
||||
Fog::Compute[:aws].describe_tags.body
|
||||
end
|
||||
|
||||
expected_identities = Fog.mocking? ? [@volume.identity, @image_id] : [@volume.identity]
|
||||
tests('#describe_tags').succeeds do
|
||||
(expected_identities - Fog::Compute[:aws].describe_tags.body['tagSet'].map {|t| t['resourceId'] }).empty?
|
||||
end
|
||||
|
||||
tests("#describe_tags('key' => 'foo', 'value' => 'bar')").returns([@volume.identity]) do
|
||||
Fog::Compute[:aws].describe_tags('key' => 'foo', 'value' => 'bar').body['tagSet'].map {|t| t['resourceId'] }
|
||||
end
|
||||
|
||||
if Fog.mocking?
|
||||
tests("#describe_tags('key' => 'foo', 'value' => 'baz')").returns([@image_id]) do
|
||||
Fog::Compute[:aws].describe_tags('key' => 'foo', 'value' => 'baz').body['tagSet'].map {|t| t['resourceId'] }
|
||||
end
|
||||
|
||||
Fog::Compute[:aws].modify_image_attribute(@image_id, 'Add.UserId' => [@other_account.data[:owner_id]])
|
||||
|
||||
tests("other_account#describe_tags('key' => 'foo', 'value' => 'baz')").returns([]) do
|
||||
@other_account.describe_tags('key' => 'foo', 'value' => 'baz').body['tagSet'].map {|t| t['resourceId'] }
|
||||
end
|
||||
|
||||
tests("other_account#create_tags('#{@image_id}', 'foo' => 'quux')").formats(AWS::Compute::Formats::BASIC) do
|
||||
@other_account.create_tags(@image_id, 'foo' => 'quux').body
|
||||
end
|
||||
|
||||
tests("other_account#describe_tags('key' => 'foo', 'value' => 'quux')").returns([@image_id]) do
|
||||
@other_account.describe_tags('key' => 'foo', 'value' => 'quux').body['tagSet'].map {|t| t['resourceId'] }
|
||||
end
|
||||
end
|
||||
|
||||
tests("#delete_tags('#{@volume.identity}', 'foo' => 'bar')").formats(AWS::Compute::Formats::BASIC) do
|
||||
Fog::Compute[:aws].delete_tags(@volume.identity, 'foo' => 'bar').body
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue