From 441fdaf52beca831c9eb156eba45187bc8f5db7d Mon Sep 17 00:00:00 2001 From: sue445 Date: Fri, 1 Apr 2016 22:03:31 +0900 Subject: [PATCH 1/4] Support multiple network ids --- README.md | 3 ++- lib/vagrant-cloudstack/action/run_instance.rb | 13 ++++++++++--- lib/vagrant-cloudstack/config.rb | 4 ++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 0e1b14fc..b9ea3ba5 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,8 @@ to update UUIDs in your Vagrantfile. If both are specified, the id parameter tak * `instance_ready_timeout` - The number of seconds to wait for the instance to become "ready" in Cloudstack. Defaults to 120 seconds. * `domain_id` - Domain id to launch the instance into -* `network_id` - Network uuid that the instance should use +* `network_id` - Network uuid(s) that the instance should use + - `network_id` is single value (e.g. `"AAAA"`) or multiple values (e.g. `["AAAA", "BBBB"]`) * `network_name` - Network name that the instance should use * `project_id` - Project uuid that the instance should belong to * `service_offering_id`- Service offering uuid to use for the instance diff --git a/lib/vagrant-cloudstack/action/run_instance.rb b/lib/vagrant-cloudstack/action/run_instance.rb index d52bde7d..51531b30 100644 --- a/lib/vagrant-cloudstack/action/run_instance.rb +++ b/lib/vagrant-cloudstack/action/run_instance.rb @@ -34,8 +34,15 @@ def call(env) sanitize_domain_config + @network_ids = + if @domain_config.network_id.nil? + [] + else + Array(@domain_config.network_id) + end + @zone = CloudstackResource.new(@domain_config.zone_id, @domain_config.zone_name, 'zone') - @network = CloudstackResource.new(@domain_config.network_id, @domain_config.network_name, 'network') + @network = CloudstackResource.new(@network_ids.first, @domain_config.network_name, 'network') @service_offering = CloudstackResource.new(@domain_config.service_offering_id, @domain_config.service_offering_name, 'service_offering') @disk_offering = CloudstackResource.new(@domain_config.disk_offering_id, @domain_config.disk_offering_name, 'disk_offering') @template = CloudstackResource.new(@domain_config.template_id, @domain_config.template_name || @env[:machine].config.vm.box, 'template') @@ -91,7 +98,7 @@ def call(env) @env[:ui].info(" -- Template: #{@template.name} (#{@template.id})") @env[:ui].info(" -- Project UUID: #{@domain_config.project_id}") unless @domain_config.project_id.nil? @env[:ui].info(" -- Zone: #{@zone.name} (#{@zone.id})") - @env[:ui].info(" -- Network: #{@network.name} (#{@network.id})") unless @network.id.nil? + @env[:ui].info(" -- Network: #{@network.name} (#{@network_ids.join(",")})") unless @network.id.nil? @env[:ui].info(" -- Keypair: #{@domain_config.keypair}") if @domain_config.keypair @env[:ui].info(' -- User Data: Yes') if @domain_config.user_data @security_groups.each do |security_group| @@ -205,7 +212,7 @@ def create_vm :image_id => @template.id } - options['network_ids'] = @network.id unless @network.id.nil? + options['network_ids'] = @network_ids.join(",") unless @network_ids.empty? options['security_group_ids'] = @security_groups.map{|security_group| security_group.id}.join(',') unless @security_groups.empty? options['project_id'] = @domain_config.project_id unless @domain_config.project_id.nil? options['key_name'] = @domain_config.keypair unless @domain_config.keypair.nil? diff --git a/lib/vagrant-cloudstack/config.rb b/lib/vagrant-cloudstack/config.rb index 513d32ec..4a15e261 100644 --- a/lib/vagrant-cloudstack/config.rb +++ b/lib/vagrant-cloudstack/config.rb @@ -49,9 +49,9 @@ class Config < Vagrant.plugin("2", :config) # @return [String] attr_accessor :domain_id - # Network uuid that the instance should use + # Network uuid(s) that the instance should use # - # @return [String] + # @return [String,Array] attr_accessor :network_id # Network name that the instance should use From 8b17e6c01a202a58a7df0727d32b3b794bfccfe2 Mon Sep 17 00:00:00 2001 From: sue445 Date: Wed, 6 Apr 2016 19:08:14 +0900 Subject: [PATCH 2/4] Add CloudstackResource.create_list --- .../model/cloudstack_resource.rb | 22 ++++++++++++ spec/spec_helper.rb | 2 ++ .../model/cloudstack_resource_spec.rb | 35 +++++++++++++++++++ .../support/be_a_resource.rb | 6 ++++ 4 files changed, 65 insertions(+) create mode 100644 spec/vagrant-cloudstack/support/be_a_resource.rb diff --git a/lib/vagrant-cloudstack/model/cloudstack_resource.rb b/lib/vagrant-cloudstack/model/cloudstack_resource.rb index 8820dafd..c9f42d24 100644 --- a/lib/vagrant-cloudstack/model/cloudstack_resource.rb +++ b/lib/vagrant-cloudstack/model/cloudstack_resource.rb @@ -27,6 +27,28 @@ def is_name_undefined? def to_s "#{kind} - #{id || ''}:#{name || ''}" end + + def self.create_list(ids, names, kind) + # padding with nil elements + if ids.length < names.length + ids += [nil] * (names.length - ids.length) + elsif ids.length > names.length + names += [nil] * (ids.length - names.length) + end + + ids_enum = ids.to_enum + names_enum = names.to_enum + + resources = [] + + loop do + id = ids_enum.next + name = names_enum.next + resources << CloudstackResource.new(id, name, kind) + end + + resources + end end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index da412223..44340fa7 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -2,5 +2,7 @@ require 'coveralls' require 'rspec/its' +Dir["#{__dir__}/vagrant-cloudstack/support/**/*.rb"].each { |f| require f } + SimpleCov.start Coveralls.wear! diff --git a/spec/vagrant-cloudstack/model/cloudstack_resource_spec.rb b/spec/vagrant-cloudstack/model/cloudstack_resource_spec.rb index 4f37e0c1..9bff706c 100644 --- a/spec/vagrant-cloudstack/model/cloudstack_resource_spec.rb +++ b/spec/vagrant-cloudstack/model/cloudstack_resource_spec.rb @@ -70,4 +70,39 @@ it { expect(CloudstackResource.new(nil, 'name', 'kind').is_name_undefined?).to be_eql false } it { expect(CloudstackResource.new('', 'name', 'kind').is_name_undefined?).to be_eql false } end + + describe '#create_list' do + subject { CloudstackResource.create_list(ids, names, kind) } + + let(:kind) { 'network' } + + context 'When ids count == names count' do + let(:ids) { %w(id1 id2) } + let(:names) { %w(name1 name2) } + + its(:count) { should eq 2 } + its([0]) { should be_a_resource('id1', 'name1', kind) } + its([1]) { should be_a_resource('id2', 'name2', kind) } + end + + context 'When ids count >= names count' do + let(:ids) { %w(id1 id2 id3) } + let(:names) { %w(name1 name2) } + + its(:count) { should eq 3 } + its([0]) { should be_a_resource('id1', 'name1', kind) } + its([1]) { should be_a_resource('id2', 'name2', kind) } + its([2]) { should be_a_resource('id3', nil, kind) } + end + + context 'When ids count <= names count' do + let(:ids) { %w(id1 id2) } + let(:names) { %w(name1 name2 name3) } + + its(:count) { should eq 3 } + its([0]) { should be_a_resource('id1', 'name1', kind) } + its([1]) { should be_a_resource('id2', 'name2', kind) } + its([2]) { should be_a_resource(nil, 'name3', kind) } + end + end end diff --git a/spec/vagrant-cloudstack/support/be_a_resource.rb b/spec/vagrant-cloudstack/support/be_a_resource.rb new file mode 100644 index 00000000..76cb79c7 --- /dev/null +++ b/spec/vagrant-cloudstack/support/be_a_resource.rb @@ -0,0 +1,6 @@ +RSpec::Matchers.define :be_a_resource do |id, name, kind| + match do |actual| + actual.is_a?(VagrantPlugins::Cloudstack::Model::CloudstackResource) && + actual.id == id && actual.name == name && actual.kind == kind + end +end From 45962953647ef469607aa646b11f2eb25d9b2f8d Mon Sep 17 00:00:00 2001 From: sue445 Date: Wed, 6 Apr 2016 19:58:00 +0900 Subject: [PATCH 3/4] Support multiple network names --- README.md | 3 ++- lib/vagrant-cloudstack/action/run_instance.rb | 27 +++++++++++++------ lib/vagrant-cloudstack/config.rb | 4 +-- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index b9ea3ba5..7bd84c61 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,8 @@ to update UUIDs in your Vagrantfile. If both are specified, the id parameter tak * `domain_id` - Domain id to launch the instance into * `network_id` - Network uuid(s) that the instance should use - `network_id` is single value (e.g. `"AAAA"`) or multiple values (e.g. `["AAAA", "BBBB"]`) -* `network_name` - Network name that the instance should use +* `network_name` - Network name(s) that the instance should use + - `network_name` is single value (e.g. `"AAAA"`) or multiple values (e.g. `["AAAA", "BBBB"]`) * `project_id` - Project uuid that the instance should belong to * `service_offering_id`- Service offering uuid to use for the instance * `service_offering_name`- Service offering name to use for the instance diff --git a/lib/vagrant-cloudstack/action/run_instance.rb b/lib/vagrant-cloudstack/action/run_instance.rb index 51531b30..8ec8ee1a 100644 --- a/lib/vagrant-cloudstack/action/run_instance.rb +++ b/lib/vagrant-cloudstack/action/run_instance.rb @@ -34,15 +34,22 @@ def call(env) sanitize_domain_config - @network_ids = + network_ids = if @domain_config.network_id.nil? [] else Array(@domain_config.network_id) end + network_names = + if @domain_config.network_name.nil? + [] + else + Array(@domain_config.network_name) + end + @zone = CloudstackResource.new(@domain_config.zone_id, @domain_config.zone_name, 'zone') - @network = CloudstackResource.new(@network_ids.first, @domain_config.network_name, 'network') + @networks = CloudstackResource.create_list(network_ids, network_names, 'network') @service_offering = CloudstackResource.new(@domain_config.service_offering_id, @domain_config.service_offering_name, 'service_offering') @disk_offering = CloudstackResource.new(@domain_config.disk_offering_id, @domain_config.disk_offering_name, 'disk_offering') @template = CloudstackResource.new(@domain_config.template_id, @domain_config.template_name || @env[:machine].config.vm.box, 'template') @@ -55,8 +62,8 @@ def call(env) if cs_zone.network_type.downcase == 'basic' # No network specification in basic zone - @env[:ui].warn(I18n.t('vagrant_cloudstack.basic_network', :zone_name => @zone.name)) if @network.id || @network.name - @network = CloudstackResource.new(nil, nil, 'network') + @env[:ui].warn(I18n.t('vagrant_cloudstack.basic_network', :zone_name => @zone.name)) if !@networks.empty? && (@networks[0].id || @networks[0].name) + @networks = [CloudstackResource.new(nil, nil, 'network')] # No portforwarding in basic zone, so none of the below @domain_config.pf_ip_address = nil @@ -65,7 +72,9 @@ def call(env) @domain_config.pf_public_rdp_port = nil @domain_config.pf_public_port_randomrange = nil else - @resource_service.sync_resource(@network) + @networks.each do |network| + @resource_service.sync_resource(network) + end end if cs_zone.security_groups_enabled @@ -98,7 +107,9 @@ def call(env) @env[:ui].info(" -- Template: #{@template.name} (#{@template.id})") @env[:ui].info(" -- Project UUID: #{@domain_config.project_id}") unless @domain_config.project_id.nil? @env[:ui].info(" -- Zone: #{@zone.name} (#{@zone.id})") - @env[:ui].info(" -- Network: #{@network.name} (#{@network_ids.join(",")})") unless @network.id.nil? + @networks.each do |network| + @env[:ui].info(" -- Network: #{network.name} (#{network.id})") + end @env[:ui].info(" -- Keypair: #{@domain_config.keypair}") if @domain_config.keypair @env[:ui].info(' -- User Data: Yes') if @domain_config.user_data @security_groups.each do |security_group| @@ -212,7 +223,7 @@ def create_vm :image_id => @template.id } - options['network_ids'] = @network_ids.join(",") unless @network_ids.empty? + options['network_ids'] = @networks.map(&:id).compact.join(",") unless @networks.empty? options['security_group_ids'] = @security_groups.map{|security_group| security_group.id}.join(',') unless @security_groups.empty? options['project_id'] = @domain_config.project_id unless @domain_config.project_id.nil? options['key_name'] = @domain_config.keypair unless @domain_config.keypair.nil? @@ -235,7 +246,7 @@ def create_vm # XXX FIXME vpc? if e.message =~ /subnet ID/ raise Errors::FogError, - :message => "Subnet ID not found: #{@network.id}" + :message => "Subnet ID not found: #{@networks.map(&:id).compact.join(",")}" end raise diff --git a/lib/vagrant-cloudstack/config.rb b/lib/vagrant-cloudstack/config.rb index 4a15e261..efe4c39b 100644 --- a/lib/vagrant-cloudstack/config.rb +++ b/lib/vagrant-cloudstack/config.rb @@ -54,9 +54,9 @@ class Config < Vagrant.plugin("2", :config) # @return [String,Array] attr_accessor :network_id - # Network name that the instance should use + # Network name(s) that the instance should use # - # @return [String] + # @return [String,Array] attr_accessor :network_name # Network Type From 840e8537fb6e289ce4b83684c45113d7ac3034f5 Mon Sep 17 00:00:00 2001 From: sue445 Date: Fri, 8 Apr 2016 18:18:25 +0900 Subject: [PATCH 4/4] Support either ids or names --- lib/vagrant-cloudstack/action/run_instance.rb | 31 +++++++------- .../model/cloudstack_resource.rb | 28 ++++++------- .../model/cloudstack_resource_spec.rb | 41 +++++++------------ 3 files changed, 42 insertions(+), 58 deletions(-) diff --git a/lib/vagrant-cloudstack/action/run_instance.rb b/lib/vagrant-cloudstack/action/run_instance.rb index 8ec8ee1a..493bdc1f 100644 --- a/lib/vagrant-cloudstack/action/run_instance.rb +++ b/lib/vagrant-cloudstack/action/run_instance.rb @@ -34,22 +34,8 @@ def call(env) sanitize_domain_config - network_ids = - if @domain_config.network_id.nil? - [] - else - Array(@domain_config.network_id) - end - - network_names = - if @domain_config.network_name.nil? - [] - else - Array(@domain_config.network_name) - end - @zone = CloudstackResource.new(@domain_config.zone_id, @domain_config.zone_name, 'zone') - @networks = CloudstackResource.create_list(network_ids, network_names, 'network') + @networks = CloudstackResource.create_list(@domain_config.network_id, @domain_config.network_name, 'network') @service_offering = CloudstackResource.new(@domain_config.service_offering_id, @domain_config.service_offering_name, 'service_offering') @disk_offering = CloudstackResource.new(@domain_config.disk_offering_id, @domain_config.disk_offering_name, 'disk_offering') @template = CloudstackResource.new(@domain_config.template_id, @domain_config.template_name || @env[:machine].config.vm.box, 'template') @@ -139,6 +125,21 @@ def call(env) def sanitize_domain_config # Accept a single entry as input, convert it to array @domain_config.pf_trusted_networks = [@domain_config.pf_trusted_networks] if @domain_config.pf_trusted_networks + + if @domain_config.network_id.nil? + # Use names if ids are not present + @domain_config.network_id = [] + + if @domain_config.network_name.nil? + @domain_config.network_name = [] + else + @domain_config.network_name = Array(@domain_config.network_name) + end + else + # Use ids if present + @domain_config.network_id = Array(@domain_config.network_id) + @domain_config.network_name = [] + end end def configure_networking diff --git a/lib/vagrant-cloudstack/model/cloudstack_resource.rb b/lib/vagrant-cloudstack/model/cloudstack_resource.rb index c9f42d24..1d1bdf2c 100644 --- a/lib/vagrant-cloudstack/model/cloudstack_resource.rb +++ b/lib/vagrant-cloudstack/model/cloudstack_resource.rb @@ -29,25 +29,21 @@ def to_s end def self.create_list(ids, names, kind) - # padding with nil elements - if ids.length < names.length - ids += [nil] * (names.length - ids.length) - elsif ids.length > names.length - names += [nil] * (ids.length - names.length) - end - - ids_enum = ids.to_enum - names_enum = names.to_enum - - resources = [] + return create_id_list(ids, kind) unless ids.empty? + return create_name_list(names, kind) unless names.empty? + [] + end - loop do - id = ids_enum.next - name = names_enum.next - resources << CloudstackResource.new(id, name, kind) + def self.create_id_list(ids, kind) + ids.each_with_object([]) do |id, resources| + resources << CloudstackResource.new(id, nil, kind) end + end - resources + def self.create_name_list(names, kind) + names.each_with_object([]) do |name, resources| + resources << CloudstackResource.new(nil, name, kind) + end end end end diff --git a/spec/vagrant-cloudstack/model/cloudstack_resource_spec.rb b/spec/vagrant-cloudstack/model/cloudstack_resource_spec.rb index 9bff706c..e144a666 100644 --- a/spec/vagrant-cloudstack/model/cloudstack_resource_spec.rb +++ b/spec/vagrant-cloudstack/model/cloudstack_resource_spec.rb @@ -71,38 +71,25 @@ it { expect(CloudstackResource.new('', 'name', 'kind').is_name_undefined?).to be_eql false } end - describe '#create_list' do - subject { CloudstackResource.create_list(ids, names, kind) } + describe '#create_id_list' do + subject { CloudstackResource.create_id_list(ids, kind) } let(:kind) { 'network' } + let(:ids) { %w(id1 id2) } - context 'When ids count == names count' do - let(:ids) { %w(id1 id2) } - let(:names) { %w(name1 name2) } - - its(:count) { should eq 2 } - its([0]) { should be_a_resource('id1', 'name1', kind) } - its([1]) { should be_a_resource('id2', 'name2', kind) } - end - - context 'When ids count >= names count' do - let(:ids) { %w(id1 id2 id3) } - let(:names) { %w(name1 name2) } + its(:count) { should eq 2 } + its([0]) { should be_a_resource('id1', nil, kind) } + its([1]) { should be_a_resource('id2', nil, kind) } + end - its(:count) { should eq 3 } - its([0]) { should be_a_resource('id1', 'name1', kind) } - its([1]) { should be_a_resource('id2', 'name2', kind) } - its([2]) { should be_a_resource('id3', nil, kind) } - end + describe '#create_name_list' do + subject { CloudstackResource.create_name_list(names, kind) } - context 'When ids count <= names count' do - let(:ids) { %w(id1 id2) } - let(:names) { %w(name1 name2 name3) } + let(:kind) { 'network' } + let(:names) { %w(name1 name2) } - its(:count) { should eq 3 } - its([0]) { should be_a_resource('id1', 'name1', kind) } - its([1]) { should be_a_resource('id2', 'name2', kind) } - its([2]) { should be_a_resource(nil, 'name3', kind) } - end + its(:count) { should eq 2 } + its([0]) { should be_a_resource(nil, 'name1', kind) } + its([1]) { should be_a_resource(nil, 'name2', kind) } end end