cloudstack_spec 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +13 -0
- data/README.md +127 -0
- data/Rakefile +2 -0
- data/bin/cloudstackspec-init +7 -0
- data/cloudstack_spec.gemspec +29 -0
- data/examples/output_example.txt +56 -0
- data/lib/cloudstack_spec.rb +56 -0
- data/lib/cloudstack_spec/helper.rb +9 -0
- data/lib/cloudstack_spec/helper/api.rb +40 -0
- data/lib/cloudstack_spec/helper/resource.rb +19 -0
- data/lib/cloudstack_spec/matcher.rb +12 -0
- data/lib/cloudstack_spec/matcher/be_allocated.rb +23 -0
- data/lib/cloudstack_spec/matcher/be_created.rb +30 -0
- data/lib/cloudstack_spec/matcher/be_ready.rb +17 -0
- data/lib/cloudstack_spec/matcher/be_running.rb +17 -0
- data/lib/cloudstack_spec/matcher/be_set.rb +18 -0
- data/lib/cloudstack_spec/resource.rb +1 -0
- data/lib/cloudstack_spec/resource/account.rb +102 -0
- data/lib/cloudstack_spec/resource/base.rb +58 -0
- data/lib/cloudstack_spec/resource/domain.rb +71 -0
- data/lib/cloudstack_spec/resource/network.rb +90 -0
- data/lib/cloudstack_spec/resource/project.rb +66 -0
- data/lib/cloudstack_spec/resource/snapshot.rb +53 -0
- data/lib/cloudstack_spec/resource/system_vm.rb +55 -0
- data/lib/cloudstack_spec/resource/template.rb +41 -0
- data/lib/cloudstack_spec/resource/template_from_snapshot.rb +73 -0
- data/lib/cloudstack_spec/resource/virtual_machine.rb +245 -0
- data/lib/cloudstack_spec/resource/vpc.rb +139 -0
- data/lib/cloudstack_spec/resource/vpc_tier.rb +81 -0
- data/lib/cloudstack_spec/resource/zone.rb +51 -0
- data/lib/cloudstack_spec/setup.rb +191 -0
- data/lib/cloudstack_spec/version.rb +3 -0
- data/spec/config.yml +5 -0
- data/spec/lib/1_zone_spec.rb +18 -0
- data/spec/lib/domain_spec.rb +20 -0
- data/spec/lib/network_spec.rb +45 -0
- data/spec/lib/snapshot_spec.rb +41 -0
- data/spec/lib/template_spec.rb +11 -0
- data/spec/lib/virtual_machine_spec.rb +17 -0
- data/spec/lib/vpc_spec.rb +40 -0
- data/spec/preprod/001_zone_spec.rb +65 -0
- data/spec/preprod/010_domain_spec.rb +18 -0
- data/spec/preprod/snapshot_spec.rb +27 -0
- data/spec/spec_helper.rb +31 -0
- metadata +207 -0
@@ -0,0 +1,139 @@
|
|
1
|
+
module CloudstackSpec::Resource
|
2
|
+
class Vpc < Base
|
3
|
+
# do nothing
|
4
|
+
|
5
|
+
def initialize(name='rspec-vpc1', zonename=nil)
|
6
|
+
@name = name
|
7
|
+
@connection = CloudstackSpec::Helper::Api.new.connection
|
8
|
+
@zone = get_zone(zonename)
|
9
|
+
@runner = Specinfra::Runner
|
10
|
+
#vpc = @connection.list_vpcs(listall: true, name: @name)
|
11
|
+
if vpc.empty?
|
12
|
+
@router = nil
|
13
|
+
else
|
14
|
+
@router = @connection.list_routers(vpcid: vpc['id'])['router'].first
|
15
|
+
end
|
16
|
+
$vpc = vpc
|
17
|
+
end
|
18
|
+
|
19
|
+
def exist?
|
20
|
+
if vpc.empty?
|
21
|
+
return false
|
22
|
+
else
|
23
|
+
return true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def ready?
|
28
|
+
begin
|
29
|
+
if @router['state'] == 'Running'
|
30
|
+
if @router['version'] == CloudstackSpec::Helper::Api.new.version
|
31
|
+
return true
|
32
|
+
else
|
33
|
+
return "VR version #{@router['version']}"
|
34
|
+
end
|
35
|
+
else
|
36
|
+
return false
|
37
|
+
end
|
38
|
+
rescue
|
39
|
+
return false
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def reachable?(port, proto, timeout)
|
44
|
+
ip = @router['publicip']
|
45
|
+
@runner.check_host_is_reachable(ip, port, proto, timeout)
|
46
|
+
end
|
47
|
+
|
48
|
+
def created?(cidr='10.10.0.0/22')
|
49
|
+
if self.exist?
|
50
|
+
puts " VPC already exist"
|
51
|
+
return true
|
52
|
+
else
|
53
|
+
job = @connection.create_vpc(
|
54
|
+
:name => @name,
|
55
|
+
:displaytext => @name,
|
56
|
+
:cidr => cidr,
|
57
|
+
:vpcofferingid => vpc_offering_id,
|
58
|
+
:zoneid => @zone['id']
|
59
|
+
)
|
60
|
+
job_status = job_status?(job['jobid'])
|
61
|
+
@router = @connection.list_routers(vpcid: vpc['id'])['router'].first
|
62
|
+
$vpc = vpc
|
63
|
+
return job_status
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def destroy?
|
69
|
+
sleep(5)
|
70
|
+
if self.exist?
|
71
|
+
job = @connection.delete_vpc(id: vpc['id'])
|
72
|
+
return job_status?(job['jobid'])
|
73
|
+
else
|
74
|
+
puts " Does not exist"
|
75
|
+
return false
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def enable_remote_vpn
|
80
|
+
newvpn = @connection.create_remote_access_vpn(publicipid: publicip_snat_id)
|
81
|
+
job_status?(newvpn['jobid'])
|
82
|
+
vpn = @connection.list_remote_access_vpns(publicipid: publicip_snat_id)
|
83
|
+
vpn = vpn['remoteaccessvpn'].first
|
84
|
+
if ! vpn.empty?
|
85
|
+
return true
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def remote_vpn_enabled?
|
90
|
+
a = @connection.list_remote_access_vpns(listall: true, publicipid: publicip_snat_id)
|
91
|
+
if a.empty?
|
92
|
+
false
|
93
|
+
else
|
94
|
+
puts " Pubic IP = #{a['remoteaccessvpn'].first['publicip']}"
|
95
|
+
puts " PreShared Key = #{a['remoteaccessvpn'].first['presharedkey']}"
|
96
|
+
true
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def vpc
|
104
|
+
vpc = @connection.list_vpcs(listall: true, name: @name)
|
105
|
+
if vpc.empty?
|
106
|
+
return {}
|
107
|
+
else
|
108
|
+
return vpc['vpc'].first
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def first_vm_id
|
113
|
+
vm = @connection.list_virtual_machines(vpcid: vpc['id'])
|
114
|
+
if vm.empty?
|
115
|
+
return false
|
116
|
+
end
|
117
|
+
vm['virtualmachine'].first['id']
|
118
|
+
end
|
119
|
+
|
120
|
+
def first_tier_id
|
121
|
+
net = @connection.list_vpcs(id: vpc['id'])
|
122
|
+
net = net['vpc'].first['network'].first['id']
|
123
|
+
return net
|
124
|
+
end
|
125
|
+
|
126
|
+
def publicip_snat_id
|
127
|
+
# get the id of the sourceNAT public IP for the current VPC
|
128
|
+
public_ip = @connection.list_public_ip_addresses(vpcid: vpc['id'], issourcenat: true)
|
129
|
+
public_ip = public_ip['publicipaddress'].first
|
130
|
+
return public_ip['id']
|
131
|
+
end
|
132
|
+
|
133
|
+
def vpc_offering_id(offering_name="Default VPC offering")
|
134
|
+
offering = @connection.list_vpc_offerings(name: offering_name)['vpcoffering'].first
|
135
|
+
return offering['id']
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module CloudstackSpec::Resource
|
2
|
+
class VpcTier < Base
|
3
|
+
attr_reader :name
|
4
|
+
|
5
|
+
def initialize(name='tier11', zonename=nil)
|
6
|
+
@name = name
|
7
|
+
@connection = CloudstackSpec::Helper::Api.new.connection
|
8
|
+
@zone = get_zone(zonename)
|
9
|
+
@runner = Specinfra::Runner
|
10
|
+
end
|
11
|
+
|
12
|
+
def exist?
|
13
|
+
begin
|
14
|
+
if !get_tier.empty?
|
15
|
+
return true
|
16
|
+
else
|
17
|
+
return false
|
18
|
+
end
|
19
|
+
rescue Exception => e
|
20
|
+
return false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def created?
|
25
|
+
unless self.exist?
|
26
|
+
@connection.create_network(
|
27
|
+
:name => @name,
|
28
|
+
:displaytext => @name,
|
29
|
+
:networkofferingid => get_offering_id,
|
30
|
+
:zoneid => @zone['id'],
|
31
|
+
:vpcid => $vpc['id'],
|
32
|
+
:gateway => '10.10.0.1',
|
33
|
+
:netmask => '255.255.255.0',
|
34
|
+
:aclid => get_acl_id
|
35
|
+
)
|
36
|
+
else
|
37
|
+
print " already exist"
|
38
|
+
return true
|
39
|
+
#return false
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def destroy?
|
44
|
+
if self.exist?
|
45
|
+
sleep(5)
|
46
|
+
job = @connection.delete_network(id: get_tier['id'])
|
47
|
+
job_status?(job['jobid'])
|
48
|
+
else
|
49
|
+
puts " Does not exist"
|
50
|
+
return false
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def get_tier
|
58
|
+
# CloudStack API does not search by name for networks
|
59
|
+
networks = @connection.list_networks(:listall => true, vpcid: $vpc['id'])
|
60
|
+
networks = networks['network']
|
61
|
+
if networks.nil?
|
62
|
+
return {}
|
63
|
+
else
|
64
|
+
network = networks.select { |net| net['name'] == @name }
|
65
|
+
network = network.first
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def get_offering_id
|
70
|
+
offering = @connection.list_network_offerings(:name => "DefaultIsolatedNetworkOfferingForVpcNetworks")
|
71
|
+
offering = offering["networkoffering"].first
|
72
|
+
return offering['id']
|
73
|
+
end
|
74
|
+
|
75
|
+
def get_acl_id(name='default_allow')
|
76
|
+
acl = @connection.list_network_a_c_l_lists(name: name)
|
77
|
+
acl = acl['networkacllist'].first
|
78
|
+
return acl['id']
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module CloudstackSpec::Resource
|
2
|
+
class Zone < Base
|
3
|
+
# All about zone...
|
4
|
+
#####
|
5
|
+
def exist?
|
6
|
+
#zone = @connection.list_zone(:name => name)
|
7
|
+
if @zonename.nil?
|
8
|
+
return false
|
9
|
+
else
|
10
|
+
return true
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def allocated?
|
15
|
+
if @zonename['allocationstate'] == 'Enabled'
|
16
|
+
return true
|
17
|
+
else
|
18
|
+
return @zonename['allocationstate']
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def local_storage
|
23
|
+
return @zonename['localstorageenabled']
|
24
|
+
end
|
25
|
+
|
26
|
+
def security_group
|
27
|
+
return @zonename['securitygroupsenabled']
|
28
|
+
end
|
29
|
+
|
30
|
+
def network_type
|
31
|
+
# return "Basic" or "Advanced"
|
32
|
+
return @zonename['networktype']
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def this_zone(name)
|
38
|
+
if name.nil?
|
39
|
+
# if zone name not define, thake the first one
|
40
|
+
zone = @connection.list_zones['zone'].first
|
41
|
+
@name = zone['name']
|
42
|
+
else
|
43
|
+
@name = name
|
44
|
+
zone = @connection.list_zones(:name => name)['zone'].first
|
45
|
+
end
|
46
|
+
return zone
|
47
|
+
end
|
48
|
+
|
49
|
+
# end private
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,191 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'erb'
|
3
|
+
|
4
|
+
module CloudstackSpec
|
5
|
+
class Setup
|
6
|
+
def self.run
|
7
|
+
|
8
|
+
create_initial
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.create_initial
|
12
|
+
print "Create base for cloudstack_spec? y/n: "
|
13
|
+
auto_config = $stdin.gets.chomp
|
14
|
+
if auto_config =~ (/(true|t|yes|y|1)$/i)
|
15
|
+
[ 'spec', "spec/lib" ].each { |dir| safe_mkdir(dir) }
|
16
|
+
safe_create_config
|
17
|
+
safe_create_spec
|
18
|
+
safe_create_spec_helper
|
19
|
+
# safe_create_rakefile
|
20
|
+
puts "Make sure to Update file: spec/config.yml"
|
21
|
+
else
|
22
|
+
exit
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.safe_create_config
|
27
|
+
# create config.yml file.
|
28
|
+
content = <<-EOF
|
29
|
+
cloudstack:
|
30
|
+
url: http://127.0.0.1:8080/client/api
|
31
|
+
api_key: c0dD7KjmFF4ixekZyQZJa7xPrW6y5-egZU1FGqq2u0DITs1qSluyP3giLDJ2msg0y1gPeARq4ZyvK-j48QP8hQ
|
32
|
+
secret_key: GYfIZjsjSIHKO_227M6tvLns86QJEzqJVzc8xobqfgg03YeDUYk2QTGBgB6IeaHfSROW61uPm-koO2iDDvq5HQ
|
33
|
+
use_ssl: false
|
34
|
+
|
35
|
+
EOF
|
36
|
+
|
37
|
+
if File.exists? "spec/config.yml"
|
38
|
+
old_content = File.read("spec/config.yml")
|
39
|
+
if old_content != content
|
40
|
+
$stderr.puts "!! spec/config.yml already exists and differs from template"
|
41
|
+
end
|
42
|
+
else
|
43
|
+
File.open("spec/config.yml", 'w') do |f|
|
44
|
+
f.puts content
|
45
|
+
end
|
46
|
+
puts " + spec/config.yml"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.safe_create_spec
|
51
|
+
content = <<-EOF
|
52
|
+
require 'spec_helper'
|
53
|
+
|
54
|
+
describe zone do
|
55
|
+
it { should exist }
|
56
|
+
it { should be_allocated }
|
57
|
+
# its(:local_storage) { should_not be_set }
|
58
|
+
# its(:security_group) { should_not be_set }
|
59
|
+
# its(:network_type) { should match("Advanced") }
|
60
|
+
end
|
61
|
+
|
62
|
+
%w(consoleproxy secondarystoragevm).each do |svm|
|
63
|
+
describe system_vm(svm) do
|
64
|
+
it { should exist }
|
65
|
+
it { should be_running }
|
66
|
+
it { should be_reachable }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
EOF
|
71
|
+
|
72
|
+
if File.exists? "spec/lib/001_zone_spec.rb"
|
73
|
+
old_content = File.read("spec/lib/001_zone_spec.rb")
|
74
|
+
if old_content != content
|
75
|
+
$stderr.puts "!! spec/lib/zone_spec.rb already exists and differs from template"
|
76
|
+
end
|
77
|
+
else
|
78
|
+
File.open("spec/lib/001_zone_spec.rb", 'w') do |f|
|
79
|
+
f.puts content
|
80
|
+
end
|
81
|
+
puts " + spec/lib/001_zone_spec.rb"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.safe_mkdir(dir)
|
86
|
+
if File.exists? dir
|
87
|
+
unless File.directory? dir
|
88
|
+
$stderr.puts "!! #{dir} already exists and is not a directory"
|
89
|
+
end
|
90
|
+
else
|
91
|
+
FileUtils.mkdir dir
|
92
|
+
puts " + #{dir}/"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.safe_create_spec_helper
|
97
|
+
requirements = []
|
98
|
+
content = ERB.new(spec_helper_template, nil, '-').result(binding)
|
99
|
+
if File.exists? 'spec/spec_helper.rb'
|
100
|
+
old_content = File.read('spec/spec_helper.rb')
|
101
|
+
if old_content != content
|
102
|
+
$stderr.puts "!! spec/spec_helper.rb already exists and differs from template"
|
103
|
+
end
|
104
|
+
else
|
105
|
+
File.open('spec/spec_helper.rb', 'w') do |f|
|
106
|
+
f.puts content
|
107
|
+
end
|
108
|
+
puts ' + spec/spec_helper.rb'
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.safe_create_rakefile
|
113
|
+
content = <<-EOF
|
114
|
+
require 'rake'
|
115
|
+
require 'rspec/core/rake_task'
|
116
|
+
|
117
|
+
task :spec => 'spec:all'
|
118
|
+
task :default => :spec
|
119
|
+
|
120
|
+
namespace :spec do
|
121
|
+
targets = []
|
122
|
+
Dir.glob('./spec/*').each do |dir|
|
123
|
+
next unless File.directory?(dir)
|
124
|
+
targets << File.basename(dir)
|
125
|
+
end
|
126
|
+
|
127
|
+
task :all => targets
|
128
|
+
task :default => :all
|
129
|
+
|
130
|
+
targets.each do |target|
|
131
|
+
desc "Run serverspec tests to #{target}"
|
132
|
+
RSpec::Core::RakeTask.new(target.to_sym) do |t|
|
133
|
+
ENV['TARGET_HOST'] = target
|
134
|
+
t.pattern = "spec/#{target}/*_spec.rb"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
EOF
|
140
|
+
if File.exists? 'Rakefile'
|
141
|
+
old_content = File.read('Rakefile')
|
142
|
+
if old_content != content
|
143
|
+
$stderr.puts "!! Rakefile already exists and differs from template"
|
144
|
+
end
|
145
|
+
else
|
146
|
+
File.open('Rakefile', 'w') do |f|
|
147
|
+
f.puts content
|
148
|
+
end
|
149
|
+
puts ' + Rakefile'
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def self.spec_helper_template
|
154
|
+
template = <<-EOF
|
155
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
156
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
157
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
158
|
+
# loaded once.
|
159
|
+
#
|
160
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
161
|
+
require 'yaml'
|
162
|
+
require 'cloudstack_ruby_client'
|
163
|
+
require 'uuid'
|
164
|
+
require 'cloudstack_spec'
|
165
|
+
require 'rspec/expectations'
|
166
|
+
|
167
|
+
require 'serverspec'
|
168
|
+
#require 'specinfra'
|
169
|
+
set :backend, :exec
|
170
|
+
|
171
|
+
|
172
|
+
|
173
|
+
RSpec.configure do |config|
|
174
|
+
config.run_all_when_everything_filtered = true
|
175
|
+
# config.filter_run :focus
|
176
|
+
|
177
|
+
# Run specs in random order to surface order dependencies. If you find an
|
178
|
+
# order dependency and want to debug it, you can fix the order by providing
|
179
|
+
# the seed, which is printed after each run.
|
180
|
+
# --seed 1234
|
181
|
+
config.order = 'defined'
|
182
|
+
config.formatter = 'documentation'
|
183
|
+
config.color = true
|
184
|
+
end
|
185
|
+
|
186
|
+
EOF
|
187
|
+
template
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|
191
|
+
end
|