Return-Path: X-Original-To: apmail-deltacloud-dev-archive@www.apache.org Delivered-To: apmail-deltacloud-dev-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id B349990AC for ; Thu, 2 Aug 2012 07:57:35 +0000 (UTC) Received: (qmail 34211 invoked by uid 500); 2 Aug 2012 07:57:35 -0000 Delivered-To: apmail-deltacloud-dev-archive@deltacloud.apache.org Received: (qmail 34190 invoked by uid 500); 2 Aug 2012 07:57:35 -0000 Mailing-List: contact dev-help@deltacloud.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@deltacloud.apache.org Delivered-To: mailing list dev@deltacloud.apache.org Received: (qmail 34178 invoked by uid 99); 2 Aug 2012 07:57:35 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 02 Aug 2012 07:57:35 +0000 X-ASF-Spam-Status: No, hits=-1.4 required=5.0 tests=NAME_EMAIL_DIFF,RCVD_IN_DNSWL_HI,SPF_HELO_PASS,SPF_PASS,T_FILL_THIS_FORM_SHORT X-Spam-Check-By: apache.org Received-SPF: pass (athena.apache.org: domain of mandreou@redhat.com designates 209.132.183.28 as permitted sender) Received: from [209.132.183.28] (HELO mx1.redhat.com) (209.132.183.28) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 02 Aug 2012 07:57:28 +0000 Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q727v8N6009604 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Thu, 2 Aug 2012 03:57:08 -0400 Received: from [10.36.112.19] (ovpn-112-19.ams2.redhat.com [10.36.112.19]) by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id q727v57o030588 for ; Thu, 2 Aug 2012 03:57:06 -0400 Message-ID: <501A32D0.9010605@redhat.com> Date: Thu, 02 Aug 2012 10:57:04 +0300 From: "marios@redhat.com" User-Agent: Mozilla/5.0 (X11; Linux i686; rv:13.0) Gecko/20120605 Thunderbird/13.0 MIME-Version: 1.0 To: dev@deltacloud.apache.org Subject: Re: [PATCH 2/2] API TESTS: adds images and instances tests References: <818896177.6973794.1343859815301.JavaMail.root@redhat.com> In-Reply-To: <818896177.6973794.1343859815301.JavaMail.root@redhat.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25 X-Virus-Checked: Checked by ClamAV on apache.org On 02/08/12 01:23, Ronelle Landy wrote: > Two comments (so far): > > 1. running >> rake test:deltacloud produces a bunch of warnings like: > /home/dcloud/workspace/deltacloud/tests/deltacloud/instances_test.rb:28: > warning: class variable access from toplevel > > 2: tests take a really long time to complete (tests are still running ...). Maybe there is just a lot of testing going on but it looks like some of the tests sit and query the provider over and over again? (open to more explanation here) > yes, the tests are obviously running against a 'real' provider... if this is ec2 then the images tests are the likely culprit for the delay you are seeing. Lets talk about this some more when you are online, marios >> >> From: marios >> >> >> Signed-off-by: marios >> --- >> tests/config.yaml | 19 ++- >> tests/deltacloud/base_api_test.rb | 8 +- >> tests/deltacloud/images_test.rb | 75 ++++++++ >> tests/deltacloud/instances_test.rb | 353 >> ++++++++++++++++++++++++++++++++++++ >> 4 files changed, 448 insertions(+), 7 deletions(-) >> >> diff --git a/tests/config.yaml b/tests/config.yaml >> index 3070b56..5f905a6 100644 >> --- a/tests/config.yaml >> +++ b/tests/config.yaml >> @@ -4,15 +4,28 @@ api_url: "http://localhost:3001/api" >> mock: >> user: "mockuser" >> password: "mockpassword" >> +#OPENSTACK DRIVER CONFIG >> +openstack: >> + user: >> + password: >> + #used for instances tests: >> + instances: >> + preferred_image: "14075" >> #EC2 DRIVER CONFIG: >> ec2: >> - user: #EC2 KEY >> - password: #EC2 SECRET KEY >> + user: >> + password: >> bucket_locations: >> - #location constraint : provider >> + #location constraint >> - "EU" >> - "sa-east-1" >> - "us-west-1" >> - "us-west-2" >> - "ap-southeast-1" >> - "ap-northeast-1" >> + preferred_provider: "us-east-1" >> + #used for instances tests: >> + instances: >> + preferred_image: "ami-2b5fba42" >> + preferred_hwp: "m1.small" >> + preferred_realm: "us-east-1b" >> diff --git a/tests/deltacloud/base_api_test.rb >> b/tests/deltacloud/base_api_test.rb >> index bd37b46..12e1e4d 100644 >> --- a/tests/deltacloud/base_api_test.rb >> +++ b/tests/deltacloud/base_api_test.rb >> @@ -120,17 +120,17 @@ describe "Deltacloud API Entry Point" do >> end >> >> it 'must change the API PROVIDER using the /api;provider matrix >> parameter in URI' do >> - res = get(';provider=test1', :public => true) >> + res = get("\;provider=test1", {:accept=>:xml, :noauth=>true}) >> res.xml.root[:provider].wont_be_nil >> res.xml.root[:provider].must_equal 'test1' >> - res = get(';provider=test2', :public => true) >> + res = get("\;provider=test2", {:accept=>:xml, :noauth=>true}) >> res.xml.root[:provider].must_equal 'test2' >> end >> >> it 'must change the API DRIVER using the /api;driver matrix >> parameter in URI' do >> - res = get(';driver=ec2', :public => true) >> + res = get("\;driver=ec2", {:accept=>:xml, :noauth=>true}) >> res.xml.root[:driver].must_equal 'ec2' >> - res = get(';driver=mock', :public => true) >> + res = get("\;driver=mock", {:accept=>:xml, :noauth=>true}) >> res.xml.root[:driver].must_equal 'mock' >> end >> >> diff --git a/tests/deltacloud/images_test.rb >> b/tests/deltacloud/images_test.rb >> index e69de29..a6bd840 100644 >> --- a/tests/deltacloud/images_test.rb >> +++ b/tests/deltacloud/images_test.rb >> @@ -0,0 +1,75 @@ >> +# >> +# Licensed to the Apache Software Foundation (ASF) under one or more >> +# contributor license agreements. See the NOTICE file distributed >> with >> +# this work for additional information regarding copyright >> ownership. The >> +# ASF licenses this file to you 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. >> + >> +$:.unshift File.join(File.dirname(__FILE__), '..') >> +require "deltacloud/test_setup.rb" >> + >> +IMAGES = "/images" >> + >> +describe 'Deltacloud API Images collection' do >> + include Deltacloud::Test::Methods >> + >> + need_collection :images >> + >> + def each_image_xml(&block) >> + res = get(IMAGES, :accept=> :xml) >> + (res.xml/'images/image').each do |r| >> + image_res = get(IMAGES + '/' + r[:id], :accept => :xml) >> + yield image_res.xml >> + end >> + end >> + >> + #Run the 'common' tests for all collections defined in >> common_tests_collections.rb >> + test_collection = "images" >> + $:.unshift File.join(File.dirname(__FILE__), '..') >> + eval File.read('deltacloud/common_tests_collections.rb') >> + >> + #Now run the images-specific tests: >> + it 'should have the "owner_id", "description", "architecure" and >> "state" element for each image' do >> + each_image_xml do |image_xml| >> + (image_xml/'state').wont_be_empty >> + (image_xml/'owner_id').wont_be_empty >> + (image_xml/'architecture').wont_be_empty >> + (image_xml/'description').wont_be_empty >> + end >> + end >> + >> + it 'should include the list of compatible hardware_profiles for >> each image' do >> + each_image_xml do |image_xml| >> + (image_xml/'hardware_profiles/hardware_profile').wont_be_empty >> + (image_xml/'hardware_profiles/hardware_profile').each do |hwp| >> + hwp[:href].wont_be_nil >> + hwp[:href].must_match /^http/ >> + hwp[:id].wont_be_nil >> + hwp[:href].must_match /\/#{hwp[:id]}$/ >> + hwp[:rel].must_equal 'hardware_profile' >> + end >> + end >> + end >> + >> + it 'should advertise the list of actions that can be executed for >> each image' do >> + each_image_xml do |image_xml| >> + (image_xml/'actions/link').wont_be_empty >> + (image_xml/'actions/link').each do |l| >> + l[:href].wont_be_nil >> + l[:href].must_match /^http/ >> + l[:method].wont_be_nil >> + l[:rel].wont_be_nil >> + end >> + end >> + end >> + >> +end >> diff --git a/tests/deltacloud/instances_test.rb >> b/tests/deltacloud/instances_test.rb >> index e69de29..852b00b 100644 >> --- a/tests/deltacloud/instances_test.rb >> +++ b/tests/deltacloud/instances_test.rb >> @@ -0,0 +1,353 @@ >> +# >> +# Licensed to the Apache Software Foundation (ASF) under one or more >> +# contributor license agreements. See the NOTICE file distributed >> with >> +# this work for additional information regarding copyright >> ownership. The >> +# ASF licenses this file to you 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. >> + >> +$:.unshift File.join(File.dirname(__FILE__), '..') >> +require "deltacloud/test_setup.rb" >> + >> +INSTANCES = "/instances" >> + >> +describe 'Deltacloud API instances collection' do >> + include Deltacloud::Test::Methods >> + need_collection :instances >> + #make sure we have at least one instance to test >> + begin >> + #keep track of what we create for deletion after tests: >> + @@created_resources = {:instances=>[], :keys=>[], :images=>[], >> :firewalls=>[]} >> + if api.instances_config["preferred_image"] >> + image_id = api.instances_config["preferred_image"] >> + else >> + image_list = get("/images", {:accept => :xml}) >> + image_id = (image_list.xml/'images/image').to_a.choice[:id] >> + end >> + res = post(INSTANCES, :image_id=>image_id) >> + unless res.code == 201 >> + raise Exception.new("Failed to create instance from image_id >> #{image_id}") >> + end >> + @@my_instance_id = (res.xml/'instance')[0][:id] >> + @@created_resources[:instances] << @@my_instance_id >> + end >> + >> + #stop/destroy the resources we created for the tests >> + MiniTest::Unit.after_tests { >> +puts "CLEANING UP... resources for deletion: >> #{@@created_resources.inspect}" >> + #instances: >> + @@created_resources[:instances].each_index do |i| >> + attempts = 0 >> + begin >> + stop_res = >> post(INSTANCES+"/"+@@created_resources[:instances][i]+"/stop", "") >> + @@created_resources[:instances][i] = nil if stop_res.code == >> 202 >> + rescue Exception => e >> + sleep(10) >> + attempts += 1 >> + retry if (attempts <= 5) >> + end >> + end >> + @@created_resources[:instances].compact! >> + @@created_resources.delete(:instances) if >> @@created_resources[:instances].empty? >> + #keys >> + [:keys, :images, :firewalls].each do |col| >> + @@created_resources[col].each do |k| >> + res = delete("/#{col}/#{k}") >> + @@created_resources[col].delete(k) if res.code == 204 >> + end >> + @@created_resources.delete(col) if >> @@created_resources[col].empty? >> + end >> +puts "CLEANUP attempt finished... resources looks like: >> #{@@created_resources.inspect}" >> + raise Exception.new("Unable to delete all created resources - >> please check: #{@@created_resources.inspect}") unless >> @@created_resources.empty? >> + } >> + >> + def each_instance_xml(&block) >> + res = get(INSTANCES, :accept=> :xml) >> + (res.xml/'instances/instance').each do |r| >> + instance_res = get(INSTANCES + '/' + r[:id], :accept => :xml) >> + yield instance_res.xml >> + end >> + end >> + >> + def get_image >> + if api.instances_config["preferred_image"] >> + image_id = api.instances_config["preferred_image"] >> + else >> + image_list = get("/images", {:accept => :xml}) >> + image_id = (image_list.xml/'images/image').to_a.choice[:id] >> + end >> + end >> + >> + def get_realm >> + if api.instances_config["preferred_realm"] >> + realm_id = api.instances_config["preferred_realm"] >> + else >> + realms_list = get("/realms", {:accept => :xml}) >> + realm_id = (realms_list.xml/'realms/realm').to_a.choice[:id] >> + end >> + end >> + >> + def get_hwp >> + if api.instances_config["preferred_hwp"] >> + hwp_id = api.instances_config["preferred_hwp"] >> + else >> + hw_profile_list = get("/hardware_profiles", {:accept => :xml}) >> + hwp_id = >> (hw_profile_list.xml/'hardware_profiles/hardware_profile').to_a.choice[:id] >> + end >> + end >> + >> + #Run the 'common' tests for all collections defined in >> common_tests_collections.rb >> + test_collection = "instances" >> + $:.unshift File.join(File.dirname(__FILE__), '..') >> + eval File.read('deltacloud/common_tests_collections.rb') >> + >> + #Now run the instances-specific tests: >> + >> + it 'must have the "state" element defined for each instance in >> collection' do >> + res = get(INSTANCES, :accept=> :xml) >> + (res.xml/'instances/instance').each do |r| >> + (r/'state').wont_be_empty >> + (r/'state').first.must_match /(RUNNING|STOPPED|PENDING)/ >> + end >> + end >> + >> + it 'must have the "owner_id" element for each instance and it >> should match with the one in collection' do >> + res = get(INSTANCES, :accept=> :xml) >> + (res.xml/'instances/instance').each do |r| >> + instance_res = get(INSTANCES + '/' + r[:id], :accept => :xml) >> + (instance_res.xml/'owner_id').wont_be_empty >> + >> (instance_res.xml/'owner_id').first.text.must_equal((r/'owner_id').first.text) >> + end >> + end >> + >> + it 'each instance must link to the realm that was used during >> instance creation' do >> + each_instance_xml do |instance_xml| >> + (instance_xml/'realm').wont_be_empty >> + (instance_xml/'realm').size.must_equal 1 >> + (instance_xml/'realm').first[:id].wont_be_nil >> + (instance_xml/'realm').first[:href].wont_be_nil >> + (instance_xml/'realm').first[:href].must_match >> /\/#{(instance_xml/'realm').first[:id]}$/ >> + end >> + end >> + >> + it 'each instance must link to the image that was used to during >> instance creation' do >> + each_instance_xml do |instance_xml| >> + (instance_xml/'image').wont_be_empty >> + (instance_xml/'image').size.must_equal 1 >> + (instance_xml/'image').first[:id].wont_be_nil >> + (instance_xml/'image').first[:href].wont_be_nil >> + (instance_xml/'image').first[:href].must_match >> /\/#{(instance_xml/'image').first[:id]}$/ >> + end >> + end >> + >> + it 'each instance must link to the hardware_profile that was used >> to during instance creation' do >> + each_instance_xml do |instance_xml| >> + (instance_xml/'hardware_profile').wont_be_empty >> + (instance_xml/'hardware_profile').size.must_equal 1 >> + (instance_xml/'hardware_profile').first[:id].wont_be_nil >> + (instance_xml/'hardware_profile').first[:href].wont_be_nil >> + (instance_xml/'hardware_profile').first[:href].must_match >> /\/#{(instance_xml/'hardware_profile').first[:id]}$/ >> + end >> + end >> + >> + it 'each (NON-STOPPED) instance should advertise the public and >> private addresses of the instance' do >> + each_instance_xml do |instance_xml| >> + #skip this instance if it is in STOPPED state >> + next if (instance_xml/'instance/state').text == "STOPPED" >> + (instance_xml/'public_addresses').wont_be_empty >> + (instance_xml/'public_addresses').size.must_equal 1 >> + (instance_xml/'public_addresses/address').each do |a| >> + a[:type].wont_be_nil >> + a.text.strip.wont_be_empty >> + end >> + (instance_xml/'private_addresses').wont_be_empty >> + (instance_xml/'private_addresses').size.must_equal 1 >> + (instance_xml/'private_addresses/address').each do |a| >> + a[:type].wont_be_nil >> + a.text.strip.wont_be_empty >> + end >> + end >> + end >> + >> + it 'each instance should advertise the storage volumes used by the >> instance' do >> + each_instance_xml do |i| >> + (i/'storage_volumes').wont_be_empty >> + end >> + end >> + >> + it 'each instance should advertise the list of actions that can be >> executed for each instance' do >> + each_instance_xml do |instance_xml| >> + (instance_xml/'actions/link').each do |l| >> + l[:href].wont_be_nil >> + l[:href].must_match /^http/ >> + l[:method].wont_be_nil >> + l[:rel].wont_be_nil >> + end >> + end >> + end >> + >> + it 'should allow to create new instance using image without realm' >> do >> + #random image and create instance >> + image_id = get_image >> + image_id.wont_be_nil >> + res = post(INSTANCES, :image_id=>image_id) >> + res.code.must_equal 201 >> + res.headers[:location].wont_be_nil >> + created_instance_id = (res.xml/'instance')[0][:id] >> + #GET the instance >> + res = get(INSTANCES+"/"+created_instance_id, {:accept=>:xml}) >> + res.code.must_equal 200 >> + (res.xml/'instance').first[:id].must_equal created_instance_id >> + (res.xml/'instance/image').first[:id].must_equal image_id >> + #mark it for stopping after tests run: >> + @@created_resources[:instances] << created_instance_id >> + end >> + >> + it 'should allow to create new instance using image and realm' do >> + #random image, realm and create instance >> + image_id = get_image >> + image_id.wont_be_nil >> + realm_id = get_realm >> + realm_id.wont_be_nil >> + res = post(INSTANCES, :image_id=>image_id, :realm_id=>realm_id) >> + res.code.must_equal 201 >> + res.headers[:location].wont_be_nil >> + created_instance_id = (res.xml/'instance')[0][:id] >> + #GET the instance >> + res = get(INSTANCES+"/"+created_instance_id, {:accept=>:xml}) >> + res.code.must_equal 200 >> + (res.xml/'instance').first[:id].must_equal created_instance_id >> + (res.xml/'instance/image').first[:id].must_equal image_id >> + (res.xml/'instance/realm').first[:id].must_equal realm_id >> + #mark it for stopping after tests run: >> + @@created_resources[:instances] << created_instance_id >> + end >> + >> + it 'should allow to create new instance using image, realm and >> hardware_profile' do >> + #random image, realm, hardware_profile and create instance >> + image_id = get_image >> + image_id.wont_be_nil >> + #check if this image defines compatible hw_profiles: >> + res = get("/images/"+image_id, {:accept =>:xml}) >> + if (res.xml/'image/hardware_profiles').empty? >> + hwp_id = get_hwp >> + else >> + hwp_id = >> (res.xml/'image/hardware_profiles/hardware_profile').to_a.choice[:id] >> + end >> + hwp_id.wont_be_nil >> + #random realm: >> + realm_id = get_realm >> + realm_id.wont_be_nil >> + res = post(INSTANCES, :image_id=>image_id, :realm_id=>realm_id, >> :hwp_id => hwp_id) >> + res.code.must_equal 201 >> + res.headers[:location].wont_be_nil >> + created_instance_id = (res.xml/'instance')[0][:id] >> + #GET the instance >> + res = get(INSTANCES+"/"+created_instance_id, {:accept=>:xml}) >> + res.code.must_equal 200 >> + (res.xml/'instance').first[:id].must_equal created_instance_id >> + (res.xml/'instance/image').first[:id].must_equal image_id >> + (res.xml/'instance/realm').first[:id].must_equal realm_id >> + (res.xml/'instance/hardware_profile').first[:id].must_equal >> hwp_id >> + #mark it for stopping after tests run: >> + @@created_resources[:instances] << created_instance_id >> + end >> + >> +#snapshot (make image) >> + >> + it 'should allow to snapshot running instance if supported by >> provider' do >> + #check if created instance allows creating image >> + res = get(INSTANCES+"/"+@@my_instance_id, {:accept=>:xml}) >> + instance_actions = >> (res.xml/'actions/link').to_a.inject([]){|actions, current| actions >> << current[:rel]; actions} >> + skip "no create image support for instance #{@@my_instance_id}" >> unless instance_actions.include?("create_image") >> + #create image >> + res = post("/images", :instance_id => @@my_instance_id, >> :name=>random_name) >> + res.code.must_equal 201 >> + my_image_id = (res.xml/'image')[0][:id] >> + #mark for deletion later: >> + @@created_resources[:images] << my_image_id >> + end >> +# >> +#create with key >> + >> + describe "create instance with auth key" do >> + >> + need_collection :keys >> + need_feature :instances, :authentication_key >> + >> + it 'should allow specification of auth key for created >> instance when supported' do >> + #create a key to use >> + key_name = random_name >> + key_res = post("/keys", :name=>key_name) >> + key_res.code.must_equal 201 >> + key_id = (key_res.xml/'key')[0][:id] >> + #create instance with this key: >> + image_id = get_image >> + res = post(INSTANCES, :image_id => image_id, :keyname => >> key_id) >> + res.code.must_equal 201 >> + instance_id = (res.xml/'instance')[0][:id] >> + #check the key: >> + key_used = >> (res.xml/'instance/authentication/login/keyname')[0].text >> + key_used.must_equal key_id >> + #mark them for deletion after tests run: >> + @@created_resources[:instances] << instance_id >> + @@created_resources[:keys] << key_id >> + end >> + >> + end >> + >> +#specify user name (feature) >> + describe "create instance with user defined name" do >> + >> + need_feature :instances, :user_name >> + >> + it 'should allow specification of name for created instance when >> supported' do >> + instance_name = random_name >> + image_id = get_image >> + res = post(INSTANCES, :image_id => image_id, :name => >> instance_name) >> + res.code.must_equal 201 >> + instance_id = (res.xml/'instance')[0][:id] >> + #check the name: >> + created_name = (res.xml/'instance/name')[0].text >> + created_name.must_equal instance_name >> + #mark for deletion: >> + @@created_resources[:instances] << instance_id >> + end >> + end >> + >> +#create with firewall (feature) >> + describe "create instance with firewall" do >> + >> + need_collection :firewalls >> + need_feature :instances, :firewalls >> + >> + it 'should be able to create instance using specified firewall' >> do >> + #create a firewall to use >> + fw_name = random_name >> + fw_res = post("/firewalls", :name=>fw_name, >> :description=>"firewall created for instances API test on >> #{Time.now}") >> + fw_res.code.must_equal 201 >> + fw_id = (fw_res.xml/'firewall')[0][:id] >> + ((fw_res.xml/'firewall/name')[0].text).must_equal fw_name >> + #create instance with this firewall: >> + image_id = get_image >> + res = post(INSTANCES, :image_id => image_id, :firewalls1 => >> fw_id) >> + res.code.must_equal 201 >> + instance_id = (res.xml/'instance')[0][:id] >> + #check the firewall: >> + fw_used = (res.xml/'instance/firewalls/firewall')[0][:id] >> + fw_used.must_equal fw_id >> + #mark for deletion: >> + @@created_resources[:instances] << instance_id >> + @@created_resources[:firewalls] << fw_id >> + end >> + >> + end >> +end >> -- >> 1.7.6.5 >> >>