Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unit testing covering a (most) basic VM deployment #174

Merged
merged 4 commits into from
May 19, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Vagrant Cloudstack Provider

[![Build Status](https://travis-ci.org/MissionCriticalCloud/vagrant-cloudstack.png?branch=master)](https://travis-ci.org/missioncriticalcloud/vagrant-cloudstack)
[![Build Status](https://travis-ci.org/MissionCriticalCloud/vagrant-cloudstack.png?branch=master)](https://travis-ci.org/MissionCriticalCloud/vagrant-cloudstack)
[![Gem Version](https://badge.fury.io/rb/vagrant-cloudstack.png)](http://badge.fury.io/rb/vagrant-cloudstack)
[![Code climate](https://codeclimate.com/github/MissionCriticalCloud/vagrant-cloudstack.png)](https://codeclimate.com/github/missioncriticalcloud/vagrant-cloudstack)
[![Code climate](https://codeclimate.com/github/MissionCriticalCloud/vagrant-cloudstack.png)](https://codeclimate.com/github/MissionCriticalCloud/vagrant-cloudstack)
[![Coverage Status](https://coveralls.io/repos/github/MissionCriticalCloud/vagrant-cloudstack/badge.svg?branch=master)](https://coveralls.io/github/MissionCriticalCloud/vagrant-cloudstack?branch=master)
[![Gem Version](https://badge.fury.io/rb/vagrant-cloudstack.svg)](http://badge.fury.io/rb/vagrant-cloudstack)
[![BCH compliance](https://bettercodehub.com/edge/badge/MissionCriticalCloud/vagrant-cloudstack?branch=master)](https://bettercodehub.com/)

This is a fork of [mitchellh AWS Provider](https://github.com/mitchellh/vagrant-aws/).

Expand Down
66 changes: 36 additions & 30 deletions lib/vagrant-cloudstack/action/read_transport_info.rb
Original file line number Diff line number Diff line change
@@ -1,38 +1,44 @@
class ReadTransportInfo
def initialize
@public_port_fieldname = 'pf_public_port'
end
module VagrantPlugins
module Cloudstack
module Action
class ReadTransportInfo
def initialize
@public_port_fieldname = 'pf_public_port'
end

def retrieve_public_ip_port(cloudstack, domain_config, machine)
pf_ip_address_id = domain_config.pf_ip_address_id
pf_ip_address = domain_config.pf_ip_address
pf_public_port = domain_config.send(@public_port_fieldname)
def retrieve_public_ip_port(cloudstack, domain_config, machine)
pf_ip_address_id = domain_config.pf_ip_address_id
pf_ip_address = domain_config.pf_ip_address
pf_public_port = domain_config.send(@public_port_fieldname)

if pf_public_port.nil?
pf_public_port_file = machine.data_dir.join(@public_port_fieldname)
if pf_public_port_file.file?
File.read(pf_public_port_file).each_line do |line|
pf_public_port = line.strip
end
domain_config.send("#{@public_port_fieldname}=", pf_public_port)
end
end
if pf_public_port.nil?
pf_public_port_file = machine.data_dir.join(@public_port_fieldname)
if pf_public_port_file.file?
File.read(pf_public_port_file).each_line do |line|
pf_public_port = line.strip
end
domain_config.send("#{@public_port_fieldname}=", pf_public_port)
end
end

if not pf_ip_address and pf_ip_address_id and pf_public_port
begin
response = cloudstack.list_public_ip_addresses({:id => pf_ip_address_id})
rescue Fog::Compute::Cloudstack::Error => e
raise Errors::FogError, :message => e.message
end
if not pf_ip_address and pf_ip_address_id and pf_public_port
begin
response = cloudstack.list_public_ip_addresses({:id => pf_ip_address_id})
rescue Fog::Compute::Cloudstack::Error => e
raise Errors::FogError, :message => e.message
end

if (response['listpublicipaddressesresponse']['count']).zero?
@logger.info("IP address #{pf_ip_address_id} not exists.")
env[:ui].info(I18n.t("IP address #{pf_ip_address_id} not exists."))
pf_ip_address = nil
else
pf_ip_address = response['listpublicipaddressesresponse']['publicipaddress'][0]['ipaddress']
if (response['listpublicipaddressesresponse']['count']).zero?
@logger.info("IP address #{pf_ip_address_id} not exists.")
env[:ui].info(I18n.t("IP address #{pf_ip_address_id} not exists."))
pf_ip_address = nil
else
pf_ip_address = response['listpublicipaddressesresponse']['publicipaddress'][0]['ipaddress']
end
end
return pf_ip_address, pf_public_port
end
end
end
return pf_ip_address, pf_public_port
end
end
10 changes: 5 additions & 5 deletions lib/vagrant-cloudstack/action/run_instance.rb
Original file line number Diff line number Diff line change
Expand Up @@ -178,11 +178,11 @@ def sanitize_domain_config
def configure_networking
enable_static_nat_rules

evaluate_pf_private_port
evaluate_pf_private_rdp_port


create_port_forwardings
unless @pf_ip_address.is_undefined?
evaluate_pf_private_port
evaluate_pf_private_rdp_port
create_port_forwardings
end
# First create_port_forwardings,
# as it may generate 'pf_public_port' or 'pf_public_rdp_port',
# which after this may need a firewall rule
Expand Down
94 changes: 94 additions & 0 deletions spec/vagrant-cloudstack/action/retrieve_public_ip_port_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
require 'spec_helper'
require 'vagrant-cloudstack/action/read_transport_info'
require 'vagrant-cloudstack/config'
require 'fog'

describe VagrantPlugins::Cloudstack::Action::ReadTransportInfo do
let(:action) {VagrantPlugins::Cloudstack::Action::ReadTransportInfo.new }

describe '#retrieve_public_ip_port' do
subject { action.retrieve_public_ip_port(cloudstack_compute, domain_config, machine) }

let(:cloudstack_compute) { double('Fog::Compute::Cloudstack') }
let(:machine) { double('Vagrant::Machine')}

let(:data_dir) { double('Pathname') }
let(:pf_public_port_file) { double('Pathname') }

let(:pf_ip_address) { 'ip_address_in_config' }
let(:pf_ip_address_from_server) { 'ip_address_from_server' }
let(:pf_ip_address_id) { 'ID of ip_address_in_config' }
let(:pf_public_port) { 'public_port_in_config' }
let(:pf_public_port_from_file) { 'public_port_from_file' }

let(:domain_config) do
config = VagrantPlugins::Cloudstack::Config.new
config.domain_config :cloudstack do |cfg|
cfg.pf_ip_address = pf_ip_address
cfg.pf_public_port = pf_public_port
cfg.pf_ip_address_id = pf_ip_address_id
end
config.finalize!
config.get_domain_config(:cloudstack)
end

context 'without both ip address and port in config' do
it 'retrieves those configured values' do
should eq [pf_ip_address, pf_public_port]
end
end

context 'port not configured' do
let(:pf_public_port) { nil }

it 'retrieves the active port stored on filesystem' do
expect(machine).to receive(:data_dir).and_return(data_dir)
expect(data_dir).to receive(:join).and_return(pf_public_port_file)
expect(pf_public_port_file).to receive(:file?).and_return(true)
expect(File).to receive(:read).and_return(pf_public_port_from_file)

expect(subject).to eq [pf_ip_address, pf_public_port_from_file]
end
end

context 'only ID of ip address specified (and public port)' do
let(:pf_ip_address) { nil }

it 'resolves, and returns, the ip address from the ID' do
response = {
'listpublicipaddressesresponse' => {
'count' =>1,
'publicipaddress' =>[{
'id' => pf_ip_address_id,
'ipaddress' => pf_ip_address_from_server,
'allocated' => '2016-05-06T13:58:04+0200',
'zoneid' => 'UUID',
'zonename' => 'Name',
'issourcenat' =>false,
'account' => 'Name',
'domainid' => 'UUID',
'domain' => 'Name',
'forvirtualnetwork' =>true,
'isstaticnat' =>false,
'issystem' =>false,
'associatednetworkid' => 'UUID',
'associatednetworkname' => 'Name',
'networkid' => 'UUID',
'aclid' => 'UUID',
'state' => 'Allocated',
'physicalnetworkid' => 'UUID',
'vpcid' => 'UUID',
'tags' =>[],
'isportable' =>false
}]
}
}
expect(cloudstack_compute).to receive(:list_public_ip_addresses)
.with(:id => pf_ip_address_id)
.and_return(response)

expect(subject).to eq [pf_ip_address_from_server, pf_public_port]
end
end
end
end
170 changes: 170 additions & 0 deletions spec/vagrant-cloudstack/action/run_instance_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
require 'spec_helper'
require 'vagrant-cloudstack/action/run_instance'
require 'vagrant-cloudstack/config'
require 'vagrant-cloudstack/provider'

require 'vagrant'
require 'fog'


ZONE_NAME = 'Zone Name'
ZONE_ID = 'Zone UUID'
SERVICE_OFFERING_NAME = 'Service Offering Name'
SERVICE_OFFERING_ID = 'Service Offering UUID'
TEMPLATE_NAME = 'Template Name'
TEMPLATE_ID = 'Template UUID'
NETWORK_NAME = 'Network Name'
NETWORK_ID = 'Network UUID'
DISPLAY_NAME = 'Display Name'

SERVER_ID = 'Server UUID'
NETWORK_TYPE = 'Advanced'
SECURITY_GROUPS_ENABLED = false


describe VagrantPlugins::Cloudstack::Action::RunInstance do
let(:action) { VagrantPlugins::Cloudstack::Action::RunInstance.new(app, env) }


describe '#run_instance in advanced zone' do
subject { action.call(env) }
let(:app) { double('Vagrant::Action::Warden')}

let(:provider_config) do
config = VagrantPlugins::Cloudstack::Config.new
config.domain_config :cloudstack do |cfg|
cfg.zone_name = ZONE_NAME
cfg.network_name = NETWORK_NAME
cfg.service_offering_name = SERVICE_OFFERING_NAME
cfg.template_name = TEMPLATE_NAME
cfg.ssh_key = '/path/to/ssh/key/file'
cfg.display_name = DISPLAY_NAME
end
config.finalize!
config.get_domain_config(:cloudstack)
end

let(:machine) { double('Vagrant::Machine') }

let(:cloudstack_zone) {
instance_double('Fog::Compute::Cloudstack::Zone',
id: ZONE_ID,
name: ZONE_NAME,
network_type: NETWORK_TYPE,
security_groups_enabled: SECURITY_GROUPS_ENABLED)
}
let(:cloudstack_compute) { double('Fog::Compute::Cloudstack') }
let(:servers) { double('Fog::Compute::Cloudstack::Servers') }
let(:server) { double('Fog::Compute::Cloudstack::Server') }
let(:ui) { double('Vagrant::UI::Prefixed') }
let(:root_path) { double('Pathname') }
let(:env) do
{
root_path: root_path,
ui: ui,
machine: machine,
cloudstack_compute: cloudstack_compute
}
end

before(:each) do
allow(app).to receive(:call).and_return(true)

allow(ui).to receive(:info)
allow(ui).to receive(:warn)
allow(ui).to receive(:detail)

allow(machine).to receive(:provider_config).and_return(provider_config)
allow(machine).to receive(:id=).with(SERVER_ID)
allow(machine).to receive(:communicate).and_return('')
allow(machine).to receive_message_chain(:communicate, :ready?).and_return(true)
allow(machine).to receive_message_chain(:config, :vm, :box).and_return(TEMPLATE_NAME)

allow(cloudstack_compute).to receive(:servers).and_return(servers)
allow(cloudstack_compute).to receive(:volumes).and_return([])

allow(server).to receive(:id).and_return(SERVER_ID)
allow(server).to receive(:wait_for).and_return(ready = true)
allow(server).to receive(:password_enabled).and_return(false)

list_zones_response = {
"listzonesresponse"=>{
"count"=>1,
"zone"=>[
{
"tags"=>[],
"id"=>ZONE_ID,
"name"=>ZONE_NAME,
"networktype"=>NETWORK_TYPE,
"securitygroupsenabled"=>SECURITY_GROUPS_ENABLED
}
]
}
}
allow(cloudstack_compute).to receive(:send).with(:list_zones, :available => true ).and_return(list_zones_response)

list_service_offerings_response = {
"listserviceofferingsresponse"=>{
"count"=>1,
"serviceoffering"=>[
{
"id"=>SERVICE_OFFERING_ID,
"name"=>SERVICE_OFFERING_NAME,
"displaytext"=>"Display version of #{SERVICE_OFFERING_NAME}",
}
]
}
}
allow(cloudstack_compute).to receive(:send).with(:list_service_offerings, listall: true)
.and_return(list_service_offerings_response)

list_templates_response = {
"listtemplatesresponse"=>{
"count"=>1,
"template"=>[
{
"id"=>TEMPLATE_ID,
"name"=>TEMPLATE_NAME
}
]
}
}
allow(cloudstack_compute).to receive(:send)
.with(:list_templates, zoneid: ZONE_ID, templatefilter: 'executable', listall: true)
.and_return(list_templates_response)

allow(cloudstack_compute).to receive(:zones).and_return([cloudstack_zone])

list_networks = {
"listnetworksresponse"=>{
"count"=>1,
"network"=>[
{
"id"=>NETWORK_ID,
"name"=>NETWORK_NAME,
}
]
}
}
allow(cloudstack_compute).to receive(:send)
.with(:list_networks, {})
.and_return(list_networks)

create_servers_parameters = {
:display_name=>DISPLAY_NAME,
:group=>nil,
:zone_id=>ZONE_ID,
:flavor_id=>SERVICE_OFFERING_ID,
:image_id=>TEMPLATE_ID,
"network_ids"=>NETWORK_ID
}
allow(servers).to receive(:create).with(create_servers_parameters).and_return(server)
end

context 'start a simple VM' do
it 'starts a vm' do
should eq true
end
end
end
end