deltacloud-core 1.0.4 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. data/Rakefile +2 -2
  2. data/config/drivers/aruba.yaml +3 -3
  3. data/deltacloud-core.gemspec +2 -2
  4. data/lib/cimi/collections/address_templates.rb +1 -2
  5. data/lib/cimi/collections/addresses.rb +1 -2
  6. data/lib/cimi/collections/base.rb +1 -1
  7. data/lib/cimi/collections/credentials.rb +2 -3
  8. data/lib/cimi/collections/forwarding_group_templates.rb +1 -2
  9. data/lib/cimi/collections/forwarding_groups.rb +1 -2
  10. data/lib/cimi/collections/machine_configurations.rb +1 -2
  11. data/lib/cimi/collections/machine_images.rb +1 -2
  12. data/lib/cimi/collections/machines.rb +9 -9
  13. data/lib/cimi/collections/network_configurations.rb +1 -2
  14. data/lib/cimi/collections/network_port_configurations.rb +1 -2
  15. data/lib/cimi/collections/network_port_templates.rb +1 -2
  16. data/lib/cimi/collections/network_ports.rb +1 -2
  17. data/lib/cimi/collections/network_templates.rb +1 -2
  18. data/lib/cimi/collections/networks.rb +2 -3
  19. data/lib/cimi/collections/volume_configurations.rb +1 -2
  20. data/lib/cimi/collections/volume_images.rb +1 -2
  21. data/lib/cimi/collections/volumes.rb +3 -4
  22. data/lib/cimi/helpers/cimi_helper.rb +7 -2
  23. data/lib/cimi/models.rb +6 -10
  24. data/lib/cimi/models/base.rb +48 -35
  25. data/lib/cimi/models/cloud_entry_point.rb +22 -1
  26. data/lib/cimi/models/collection.rb +42 -5
  27. data/lib/cimi/models/credential.rb +1 -1
  28. data/lib/cimi/models/disk.rb +39 -10
  29. data/lib/cimi/models/machine.rb +39 -22
  30. data/lib/cimi/models/machine_configuration.rb +4 -5
  31. data/lib/cimi/models/machine_image.rb +1 -1
  32. data/lib/cimi/models/machine_volume.rb +1 -1
  33. data/lib/cimi/models/network.rb +6 -3
  34. data/lib/cimi/models/network_port.rb +13 -2
  35. data/lib/cimi/models/schema.rb +66 -5
  36. data/lib/cimi/models/volume.rb +17 -16
  37. data/lib/cimi/models/volume_configuration.rb +7 -10
  38. data/lib/cimi/models/volume_image.rb +1 -1
  39. data/lib/deltacloud/collections/base.rb +1 -1
  40. data/lib/deltacloud/collections/firewalls.rb +2 -2
  41. data/lib/deltacloud/collections/load_balancers.rb +8 -2
  42. data/lib/deltacloud/core_ext.rb +1 -0
  43. data/lib/deltacloud/core_ext/base.rb +30 -0
  44. data/lib/deltacloud/drivers.rb +1 -1
  45. data/lib/deltacloud/drivers/base_driver.rb +1 -1
  46. data/lib/deltacloud/drivers/condor/condor_driver.rb +1 -1
  47. data/lib/deltacloud/drivers/exceptions.rb +24 -14
  48. data/lib/deltacloud/drivers/features.rb +3 -3
  49. data/lib/deltacloud/drivers/fgcp/fgcp_driver.rb +163 -92
  50. data/lib/deltacloud/drivers/mock/data/images/img1.yml +1 -0
  51. data/lib/deltacloud/drivers/mock/data/images/img2.yml +1 -0
  52. data/lib/deltacloud/drivers/mock/data/images/img3.yml +1 -0
  53. data/lib/deltacloud/drivers/mock/mock_client.rb +4 -4
  54. data/lib/deltacloud/drivers/mock/mock_driver.rb +16 -16
  55. data/lib/deltacloud/drivers/openstack/openstack_driver.rb +25 -9
  56. data/lib/deltacloud/drivers/rhevm/rhevm_driver.rb +2 -1
  57. data/lib/deltacloud/drivers/terremark/terremark_driver.rb +1 -1
  58. data/lib/deltacloud/drivers/vsphere/vsphere_driver.rb +2 -0
  59. data/lib/deltacloud/helpers/deltacloud_helper.rb +29 -8
  60. data/lib/deltacloud/models/image.rb +1 -0
  61. data/lib/deltacloud/models/instance_profile.rb +4 -0
  62. data/lib/deltacloud/version.rb +1 -1
  63. data/lib/ec2/query_parser.rb +1 -1
  64. data/lib/sinatra/rack_accept.rb +5 -1
  65. data/lib/sinatra/rack_logger.rb +9 -2
  66. data/tests/cimi/collections/machine_images_test.rb +23 -6
  67. data/tests/cimi/collections/machines_test.rb +39 -0
  68. data/tests/cimi/model/collection_spec.rb +109 -0
  69. data/tests/cimi/{spec/cimi/model → model}/credential_spec.rb +1 -1
  70. data/tests/cimi/{spec/cimi/model → model}/machine_configuration_spec.rb +1 -1
  71. data/tests/cimi/{spec/cimi/model → model}/machine_image_spec.rb +1 -1
  72. data/tests/cimi/{spec/cimi/model → model}/machine_spec.rb +1 -1
  73. data/tests/cimi/{spec/cimi/model → model}/machine_template_spec.rb +1 -1
  74. data/tests/cimi/{spec/cimi/model → model}/schema_spec.rb +1 -1
  75. data/tests/cimi/{spec/cimi/model → model}/volume_configuration_spec.rb +1 -1
  76. data/tests/cimi/{spec/cimi/model → model}/volume_image_spec.rb +1 -1
  77. data/tests/cimi/{spec/cimi/model → model}/volume_spec.rb +1 -1
  78. data/tests/cimi/{spec/cimi/model → model}/volume_template_spec.rb +1 -1
  79. data/tests/cimi/{spec/spec_helper.rb → spec_helper.rb} +7 -4
  80. data/tests/drivers/base/exceptions_test.rb +8 -8
  81. data/tests/drivers/ec2/buckets_test.rb +1 -1
  82. data/tests/drivers/ec2/images_test.rb +1 -1
  83. data/tests/drivers/ec2/instance_test.rb +1 -1
  84. data/tests/drivers/ec2/keys_test.rb +2 -2
  85. data/tests/drivers/ec2/realms_test.rb +1 -1
  86. data/tests/drivers/ec2/storage_snapshots_test.rb +1 -1
  87. data/tests/drivers/gogrid/hardware_profiles_test.rb +1 -1
  88. data/tests/drivers/gogrid/images_test.rb +1 -1
  89. data/tests/drivers/gogrid/instances_test.rb +1 -1
  90. data/tests/drivers/gogrid/realms_test.rb +1 -1
  91. data/tests/drivers/mock/images_test.rb +7 -2
  92. data/tests/drivers/mock/instances_test.rb +1 -1
  93. data/tests/drivers/mock/keys_test.rb +2 -2
  94. data/tests/drivers/mock/realms_test.rb +1 -1
  95. data/tests/drivers/mock/storage_snapshots_test.rb +1 -1
  96. data/tests/drivers/mock/storage_volumes_test.rb +1 -1
  97. data/tests/drivers/openstack/hardware_profiles_test.rb +3 -3
  98. data/tests/drivers/openstack/images_test.rb +1 -1
  99. data/tests/drivers/openstack/instances_test.rb +1 -1
  100. data/tests/drivers/openstack/keys_test.rb +2 -2
  101. data/tests/drivers/openstack/realms_test.rb +1 -1
  102. data/tests/drivers/rhevm/common.rb +3 -3
  103. data/tests/drivers/rhevm/images_test.rb +13 -13
  104. data/tests/drivers/rhevm/instance_test.rb +22 -22
  105. data/tests/drivers/rhevm/provider_test.rb +3 -3
  106. data/tests/drivers/rhevm/realms_test.rb +7 -7
  107. data/tests/test_helper.rb +0 -5
  108. data/views/api/show.xml.haml +6 -3
  109. data/views/errors/401.html.haml +0 -16
  110. data/views/errors/404.html.haml +2 -3
  111. data/views/errors/500.html.haml +6 -5
  112. data/views/images/show.html.haml +5 -1
  113. data/views/images/show.xml.haml +8 -3
  114. data/views/instances/new.html.haml +1 -1
  115. data/views/instances/show.xml.haml +1 -1
  116. data/views/load_balancers/show.html.haml +1 -1
  117. metadata +761 -778
  118. data/lib/cimi/models/disk_collection.rb +0 -37
  119. data/lib/cimi/models/machine_volume_collection.rb +0 -34
  120. data/lib/cimi/models/network_port_collection.rb +0 -51
  121. data/lib/cimi/models/network_port_configuration_collection.rb +0 -35
  122. data/lib/cimi/models/network_port_template_collection.rb +0 -37
@@ -17,20 +17,22 @@ class CIMI::Model::Volume < CIMI::Model::Base
17
17
 
18
18
  acts_as_root_entity
19
19
 
20
- struct :capacity do
21
- scalar :quantity
22
- scalar :units
23
- end
20
+ text :state
21
+
22
+ text :type
23
+
24
+ text :capacity
25
+
24
26
  text :bootable
25
- text :supports_snapshots
27
+
26
28
  array :snapshots do
27
29
  scalar :ref
28
30
  end
29
- text :guest_interface
31
+
30
32
  array :meters do
31
33
  scalar :ref
32
34
  end
33
- href :eventlog
35
+
34
36
  array :operations do
35
37
  scalar :rel, :href
36
38
  end
@@ -40,7 +42,7 @@ class CIMI::Model::Volume < CIMI::Model::Base
40
42
  opts = ( id == :all ) ? {} : { :id => id }
41
43
  volumes = context.driver.storage_volumes(context.credentials, opts)
42
44
  volumes.collect!{ |volume| from_storage_volume(volume, context) }
43
- return volumes.first unless volumes.length > 1
45
+ return volumes.first unless volumes.length > 1 || volumes.length == 0
44
46
  return volumes
45
47
  end
46
48
 
@@ -68,14 +70,14 @@ class CIMI::Model::Volume < CIMI::Model::Base
68
70
 
69
71
  def self.find_to_attach_from_json(json_in, context)
70
72
  json = JSON.parse(json_in)
71
- volumes = json["volumes"].map{|v| {:volume=>self.find(v["volume"]["href"].split("/volumes/").last, context),
72
- :attachment_point=>v["attachmentPoint"] }}
73
+ json["volumes"].map{|v| {:volume=>self.find(v["volume"]["href"].split("/volumes/").last, context),
74
+ :attachment_point=>v["attachmentPoint"] }}
73
75
  end
74
76
 
75
77
  def self.find_to_attach_from_xml(xml_in, context)
76
78
  xml = XmlSimple.xml_in(xml_in)
77
- volumes = xml["volume"].map{|v| {:volume => self.find(v["href"].split("/volumes/").last, context),
78
- :attachment_point=>v["attachmentPoint"] }}
79
+ xml["volume"].map{|v| {:volume => self.find(v["href"].split("/volumes/").last, context),
80
+ :attachment_point=>v["attachmentPoint"] }}
79
81
  end
80
82
 
81
83
  private
@@ -90,14 +92,13 @@ class CIMI::Model::Volume < CIMI::Model::Base
90
92
  def self.from_storage_volume(volume, context)
91
93
  self.new( { :name => volume.id,
92
94
  :description => volume.id,
93
- :created => volume.created,
95
+ :created => Time.parse(volume.created).xmlschema,
94
96
  :id => context.volume_url(volume.id),
95
97
  :capacity => { :quantity=>volume.capacity, :units=>"gibibyte" }, #FIXME... units will vary
96
98
  :bootable => "false", #fixme ... will vary... ec2 doesn't expose this
97
- :supports_snapshots => "true", #fixme, will vary (true for ec2)
98
99
  :snapshots => [], #fixme...
99
- :guest_interface => "",
100
- :eventlog => {:href=> "http://eventlogs"},#FIXME
100
+ :type => 'http://schemas.dmtf.org/cimi/1/mapped',
101
+ :state => volume.state,
101
102
  :meters => []
102
103
  } )
103
104
  end
@@ -18,12 +18,9 @@ class CIMI::Model::VolumeConfiguration < CIMI::Model::Base
18
18
  acts_as_root_entity :as => "volumeConfigs"
19
19
 
20
20
  text :format
21
- struct :capacity do
22
- scalar :quantity
23
- scalar :units
24
- end
25
- text :supports_snapshots
26
- text :guest_interface
21
+
22
+ text :capacity
23
+
27
24
  array :operations do
28
25
  scalar :rel, :href
29
26
  end
@@ -50,10 +47,10 @@ class CIMI::Model::VolumeConfiguration < CIMI::Model::Base
50
47
  def self.create(size, context)
51
48
  self.new( {
52
49
  :id => context.volume_configuration_url(size),
53
- :name => size,
54
- :description => "volume configuration with #{size} GiB",
55
- :created => Time.now.to_s,
56
- :capacity => {:quantity=>size, :units=>"gibibytes"},
50
+ :name => "volume-#{size}",
51
+ :description => "Volume configuration with #{size} kilobytes",
52
+ :created => Time.now.xmlschema,
53
+ :capacity => context.to_kibibyte(size, "MB"),
57
54
  :supports_snapshots => "true"
58
55
  # FIXME :guest_interface => "NFS"
59
56
  } )
@@ -41,7 +41,7 @@ class CIMI::Model::VolumeImage < CIMI::Model::Base
41
41
  self.new( {
42
42
  :name => snapshot.id,
43
43
  :description => snapshot.id,
44
- :created => snapshot.created,
44
+ :created => Time.parse(snapshot.created).xmlschema,
45
45
  :id => context.volume_image_url(snapshot.id),
46
46
  :image_location => {:href=>context.volume_url(snapshot.storage_volume_id)},
47
47
  :bootable => "false" #FIXME
@@ -43,7 +43,7 @@ module Deltacloud::Collections
43
43
  report_error
44
44
  end
45
45
 
46
- error Deltacloud::ExceptionHandler::ValidationFailure do
46
+ error Deltacloud::Exceptions::ValidationFailure do
47
47
  report_error
48
48
  end
49
49
 
@@ -99,8 +99,8 @@ module Deltacloud::Collections
99
99
  params['addresses'] = addresses
100
100
  params['groups'] = groups
101
101
  if addresses.empty? && groups.empty?
102
- raise Deltacloud::ExceptionHandler::ValidationFailure.new(
103
- StandardError.new("No sources. Specify at least one source ip_address or group")
102
+ raise Deltacloud::Exceptions.exception_from_status(
103
+ 400, 'No sources. Specify at least one source ip address or group.'
104
104
  )
105
105
  end
106
106
  driver.create_firewall_rule(credentials, params)
@@ -23,7 +23,7 @@ module Deltacloud::Collections
23
23
  end
24
24
 
25
25
  collection :load_balancers do
26
- description "Load balancers are used distribute workload across multiple instances"
26
+ description "Load balancers are used to distribute workload across multiple instances"
27
27
 
28
28
  standard_index_operation
29
29
 
@@ -32,7 +32,13 @@ module Deltacloud::Collections
32
32
  control do
33
33
  @load_balancer = driver.load_balancer(credentials, params)
34
34
  @registered_instances = @load_balancer.instances.collect{|i| {:id => i.id, :name=> i.name}}
35
- @unregistered_instances = driver.instances(credentials).collect{|i| {:id => i.id, :name => i.name}} - @registered_instances
35
+ # if provider supports realm_filter and load balancer has only one realm (which is mostly the case), use optimization:
36
+ if @load_balancer.realms.size == 1 and driver.class.has_feature?(:instances, :realm_filter)
37
+ all_instances = driver.instances(credentials, :realm_id => @load_balancer.realms.first.id).collect{|i| {:id => i.id, :name => i.name}}
38
+ elsif
39
+ all_instances = driver.instances(credentials).collect{|i| {:id => i.id, :name => i.name} }
40
+ end
41
+ @unregistered_instances = all_instances - @registered_instances
36
42
  respond_to do |format|
37
43
  format.xml { haml :'load_balancers/show' }
38
44
  format.json { xml_to_json('load_balancers/show') }
@@ -22,3 +22,4 @@ require_relative './core_ext/integer'
22
22
  require_relative './core_ext/ordered_hash'
23
23
  require_relative './core_ext/proc'
24
24
  require_relative './core_ext/string'
25
+ require_relative './core_ext/base'
@@ -0,0 +1,30 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one or more
2
+ # contributor license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright ownership. The
4
+ # ASF licenses this file to you under the Apache License, Version 2.0 (the
5
+ # "License"); you may not use this file except in compliance with the
6
+ # License. You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+ # License for the specific language governing permissions and limitations
14
+ # under the License.
15
+
16
+ def get_current_memory_usage
17
+ `ps -o rss= -p #{Process.pid}`.to_i
18
+ end
19
+
20
+ def profile_memory(&block)
21
+ before = get_current_memory_usage
22
+ file, line, _ = caller[0].split(':')
23
+ if block_given?
24
+ instance_eval(&block)
25
+ puts "[#{file}:#{line}: #{(get_current_memory_usage - before) / 1024} MB (consumed)]"
26
+ else
27
+ before = 0
28
+ puts "[#{file}:#{line}: #{(get_current_memory_usage - before) / 1024} MB (all)]"
29
+ end
30
+ end
@@ -26,7 +26,7 @@ module Deltacloud
26
26
  Thread::current[:drivers] = {}
27
27
  top_srcdir = File.join(File.dirname(__FILE__), '..', '..')
28
28
  Dir[File.join(top_srcdir, 'config', 'drivers', '*.yaml')].each do |driver_file|
29
- Thread::current[:drivers].merge!(YAML::load(File::read(driver_file)))
29
+ Thread::current[:drivers].merge!(YAML::load_file(driver_file))
30
30
  end
31
31
  end
32
32
  Thread::current[:drivers]
@@ -23,7 +23,7 @@ module Deltacloud
23
23
 
24
24
  class BaseDriver
25
25
 
26
- include ExceptionHandler
26
+ include Exceptions
27
27
 
28
28
  STATE_MACHINE_OPTS = {
29
29
  :all_states => [:start, :pending, :running, :stopping, :stopped, :finish],
@@ -192,7 +192,7 @@ module Deltacloud
192
192
 
193
193
  def new_client(credentials)
194
194
  if ( credentials.user != 'condor' ) or ( credentials.password != 'deltacloud' )
195
- raise Deltacloud::ExceptionHandler::AuthenticationFailure.new
195
+ raise Deltacloud::Exceptions::AuthenticationFailure.new
196
196
  end
197
197
  safely do
198
198
  yield CondorCloud::DefaultExecutor.new
@@ -15,7 +15,7 @@
15
15
  #
16
16
 
17
17
  module Deltacloud
18
- module ExceptionHandler
18
+ module Exceptions
19
19
 
20
20
  class DeltacloudException < StandardError
21
21
 
@@ -30,6 +30,13 @@ module Deltacloud
30
30
 
31
31
  end
32
32
 
33
+ class AcceptedButNotCompletedError < DeltacloudException
34
+ def initialize(e, message=nil)
35
+ message ||= e.message
36
+ super(202, e.class.name, message, e.backtrace)
37
+ end
38
+ end
39
+
33
40
  class AuthenticationFailure < DeltacloudException
34
41
  def initialize(e, message=nil)
35
42
  message ||= e.message
@@ -115,6 +122,7 @@ module Deltacloud
115
122
  def initialize(conditions, &block)
116
123
  @conditions = conditions
117
124
  instance_eval(&block) if block_given?
125
+ self
118
126
  end
119
127
 
120
128
  def status(code)
@@ -142,21 +150,26 @@ module Deltacloud
142
150
  def handler(e)
143
151
  return @handler if @handler
144
152
  case @status
145
- when 401 then Deltacloud::ExceptionHandler::AuthenticationFailure.new(e, @message)
146
- when 403 then Deltacloud::ExceptionHandler::ForbiddenError.new(e, @message)
147
- when 404 then Deltacloud::ExceptionHandler::ObjectNotFound.new(e, @message)
148
- when 406 then Deltacloud::ExceptionHandler::UnknownMediaTypeError.new(e, @message)
149
- when 405 then Deltacloud::ExceptionHandler::MethodNotAllowed.new(e, @message)
150
- when 400 then Deltacloud::ExceptionHandler::ValidationFailure.new(e, @message)
151
- when 500 then Deltacloud::ExceptionHandler::BackendError.new(e, @message)
152
- when 501 then Deltacloud::ExceptionHandler::NotImplemented.new(e, @message)
153
- when 502 then Deltacloud::ExceptionHandler::ProviderError.new(e, @message)
154
- when 504 then Deltacloud::ExceptionHandler::ProviderTimeout.new(e, @message)
153
+ when 202 then AcceptedButNotCompletedError.new(e, @message)
154
+ when 401 then AuthenticationFailure.new(e, @message)
155
+ when 403 then ForbiddenError.new(e, @message)
156
+ when 404 then ObjectNotFound.new(e, @message)
157
+ when 406 then UnknownMediaTypeError.new(e, @message)
158
+ when 405 then MethodNotAllowed.new(e, @message)
159
+ when 400 then ValidationFailure.new(e, @message)
160
+ when 500 then BackendError.new(e, @message)
161
+ when 501 then NotImplemented.new(e, @message)
162
+ when 502 then ProviderError.new(e, @message)
163
+ when 504 then ProviderTimeout.new(e, @message)
155
164
  end
156
165
  end
157
166
 
158
167
  end
159
168
 
169
+ def self.exception_from_status(code, message)
170
+ ExceptionDef.new(nil) { status code}.handler(StandardError.new(message))
171
+ end
172
+
160
173
  class Exceptions
161
174
  attr_reader :exception_definitions
162
175
 
@@ -198,17 +211,14 @@ module Deltacloud
198
211
  begin
199
212
  block.call
200
213
  rescue => e
201
- log = ExceptionHandler.logger
202
214
  self.class.exceptions.each do |definitions|
203
215
  next unless definitions.any? e
204
216
  if (new_exception = definitions.handler(e)) and new_exception.message
205
217
  message = new_exception.message
206
218
  end
207
219
  message ||= e.message
208
- log.error "#{[e.class.to_s, message].join(':')}\n#{e.backtrace[0..10].join("\n")}" unless ENV['RACK_ENV'] == 'test'
209
220
  raise definitions.handler(e) unless new_exception.nil?
210
221
  end
211
- log.error "[NO HANDLED] #{[e.class.to_s, e.message].join(': ')}\n#{e.backtrace.join("\n")}" unless ENV['RACK_ENV'] == 'test'
212
222
  raise BackendError.new(e, "Unhandled exception or status code (#{e.message})")
213
223
  end
214
224
  end
@@ -135,14 +135,14 @@ module Deltacloud
135
135
  end
136
136
 
137
137
  feature :instance_count, :for => :instances do
138
- description "Number of instances to be launch with at once"
138
+ description "Number of instances to launch at once"
139
139
  operation :create do
140
140
  param :instance_count, :string, :optional
141
141
  end
142
142
  end
143
143
 
144
144
  feature :attach_snapshot, :for => :instances do
145
- description "Attach an snapshot to instance on create"
145
+ description "Attach a snapshot to instance on create"
146
146
  operation :create do
147
147
  param :snapshot_id, :string, :optional
148
148
  param :device_name, :string, :optional
@@ -150,7 +150,7 @@ module Deltacloud
150
150
  end
151
151
 
152
152
  feature :sandboxing, :for => :instances do
153
- description "Allow lanuching sandbox images"
153
+ description "Allow launching sandbox images"
154
154
  operation :create do
155
155
  param :sandbox, :string, :optional
156
156
  end
@@ -29,6 +29,7 @@ class FgcpDriver < Deltacloud::BaseDriver
29
29
 
30
30
  feature :instances, :user_name
31
31
  feature :instances, :metrics
32
+ feature :instances, :realm_filter
32
33
  feature :images, :user_name
33
34
  feature :images, :user_description
34
35
 
@@ -168,19 +169,18 @@ class FgcpDriver < Deltacloud::BaseDriver
168
169
  realms = []
169
170
  safely do
170
171
  client = new_client(credentials)
171
- # opts may include scope: system, network
172
- # first retrieve list of VSYS ids (and add if scope is not only filtering for network)
172
+
173
173
  if opts and opts[:id]
174
174
 
175
- # determine id belongs to vsys or network
175
+ # determine id belongs to system or network
176
176
  vsys_id = client.extract_vsys_id(opts[:id])
177
177
  vsys = client.get_vsys_attributes(vsys_id)['vsys'][0]
178
178
  realm_name = vsys['vsysName'][0]
179
- limit = '[VSYS]'
179
+ limit = '[System]'
180
180
  if opts[:id] != vsys_id # network id specified
181
181
  opts[:id] =~ /^.*\b(\w+)$/
182
- realm_name += ' [' + $1 + ']' # vsys name or vsys name + network [DMZ/SECURE1/SECURE2]
183
- limit = '[Network segment]'
182
+ realm_name += ' [' + $1 + ']' # system name or system name + network [DMZ/SECURE1/SECURE2]
183
+ limit = '[Network]'
184
184
  end
185
185
  realms << Realm::new(
186
186
  :id => opts[:id],
@@ -188,7 +188,6 @@ class FgcpDriver < Deltacloud::BaseDriver
188
188
  #:limit => :unlimited,
189
189
  :limit => limit,
190
190
  :state => 'AVAILABLE' # map to state of FW/VSYS (reconfiguring = unavailable)?
191
- # :scope => 'system'
192
191
  )
193
192
  elsif xml = client.list_vsys['vsyss']
194
193
 
@@ -197,11 +196,10 @@ class FgcpDriver < Deltacloud::BaseDriver
197
196
 
198
197
  realms << Realm::new(
199
198
  :id => vsys['vsysId'][0], # vsysId or networkId
200
- :name => vsys['vsysName'][0], # vsys name or vsys name + network (DMZ/SECURE1/SECURE2)
199
+ :name => vsys['vsysName'][0], # system name or system name + network (DMZ/SECURE1/SECURE2)
201
200
  #:limit => :unlimited,
202
- :limit => '[VSYS]',
201
+ :limit => '[System]',
203
202
  :state => 'AVAILABLE' # map to state of FW/VSYS (reconfiguring = unavailable)?
204
- # :scope => 'system'
205
203
  )
206
204
  # then retrieve and add list of network segments
207
205
  client.get_vsys_configuration(vsys['vsysId'][0])['vsys'][0]['vnets'][0]['vnet'].each do |vnet|
@@ -212,9 +210,8 @@ class FgcpDriver < Deltacloud::BaseDriver
212
210
  :id => vnet['networkId'][0], # vsysId or networkId
213
211
  :name => realm_name,
214
212
  #:limit => :unlimited,
215
- :limit => '[Network segment]',
213
+ :limit => '[Network]',
216
214
  :state => 'AVAILABLE' # map to state of FW/VSYS (reconfiguring = unavailable)?
217
- # :scope => 'network'
218
215
  )
219
216
  end
220
217
  end
@@ -232,20 +229,25 @@ class FgcpDriver < Deltacloud::BaseDriver
232
229
  safely do
233
230
  client = new_client(credentials)
234
231
 
235
- if opts and opts[:id]
236
- vsys_id = client.extract_vsys_id(opts[:id])
232
+ if opts and opts[:id] or opts[:realm_id]
233
+ vsys_id = client.extract_vsys_id(opts[:id] || opts[:realm_id])
237
234
  vsys_config = client.get_vsys_configuration(vsys_id)
238
235
  vsys_config['vsys'][0]['vservers'][0]['vserver'].each do |vserver|
239
- if vserver['vserverId'][0] == opts[:id]
236
+ network_id = vserver['vnics'][0]['vnic'][0]['networkId'][0]
237
+ # :realm_id can point to system or network
238
+ if vsys_id == opts[:realm_id] or vserver['vserverId'][0] == opts[:id] or network_id == opts[:realm_id]
240
239
 
241
- # check state first as it may be filtered on
242
- state_data = instance_state_data(vserver, client)
243
- if opts[:state].nil? or opts[:state] == state_data[:state]
240
+ # skip firewall if filtering by realm
241
+ unless opts[:realm_id] and determine_server_type(vserver) == 'FW'
242
+ # check state first as it may be filtered on
243
+ state_data = instance_state_data(vserver, client)
244
+ if opts[:state].nil? or opts[:state] == state_data[:state]
244
245
 
245
- instance = convert_to_instance(client, vserver, state_data)
246
- add_instance_details(instance, client, vserver)
246
+ instance = convert_to_instance(client, vserver, state_data)
247
+ add_instance_details(instance, client, vserver)
247
248
 
248
- instances << instance
249
+ instances << instance
250
+ end
249
251
  end
250
252
  end
251
253
  end
@@ -258,12 +260,16 @@ class FgcpDriver < Deltacloud::BaseDriver
258
260
  vsys_config = client.get_vsys_configuration(vsys['vsysId'][0])
259
261
  vsys_config['vsys'][0]['vservers'][0]['vserver'].each do |vserver|
260
262
 
261
- # to keep the response time of this method acceptable, retrieve state
262
- # only if required because state is filtered on
263
- state_data = opts[:state] ? instance_state_data(vserver, client) : nil
264
- # filter on state
265
- if opts[:state].nil? or opts[:state] == state_data[:state]
266
- instances << convert_to_instance(client, vserver, state_data)
263
+ # skip firewalls - they probably don't belong here and their new type ('firewall' instead of
264
+ # 'economy') causes errors when trying to map to available profiles)
265
+ unless determine_server_type(vserver) == 'FW'
266
+ # to keep the response time of this method acceptable, retrieve state
267
+ # only if required because state is filtered on
268
+ state_data = opts[:state] ? instance_state_data(vserver, client) : nil
269
+ # filter on state
270
+ if opts[:state].nil? or opts[:state] == state_data[:state]
271
+ instances << convert_to_instance(client, vserver, state_data)
272
+ end
267
273
  end
268
274
  end
269
275
  end
@@ -343,6 +349,12 @@ class FgcpDriver < Deltacloud::BaseDriver
343
349
  network_id = opts[:realm_id]
344
350
  safely do
345
351
  client = new_client(credentials)
352
+ if not network_id
353
+ xml = client.list_vsys['vsyss']
354
+
355
+ # use first returned system's DMZ as realm
356
+ network_id = xml ? xml[0]['vsys'][0]['vsysId'][0] + '-N-DMZ' : nil
357
+ end
346
358
  xml = client.create_vserver(name, hwp, image_id, network_id)
347
359
  # returns vserver details
348
360
  instances(credentials, {:id => xml['vserverId'][0]}).first
@@ -404,7 +416,12 @@ class FgcpDriver < Deltacloud::BaseDriver
404
416
  safely do
405
417
  client = new_client(credentials)
406
418
  if opts and opts[:id]
407
- vdisk = client.get_vdisk_attributes(opts[:id])['vdisk'][0]
419
+ begin
420
+ vdisk = client.get_vdisk_attributes(opts[:id])['vdisk'][0]
421
+ rescue Exception => ex
422
+ return [] if ex.message =~ /VALIDATION_ERROR.*t exist./
423
+ raise
424
+ end
408
425
  state = client.get_vdisk_status(opts[:id])['vdiskStatus'][0]
409
426
  actions = []
410
427
  if state == 'NORMAL'
@@ -474,7 +491,7 @@ class FgcpDriver < Deltacloud::BaseDriver
474
491
  elsif xml = client.list_vsys['vsyss']
475
492
 
476
493
  # use first vsys returned as realm
477
- opts[:realm_id] = xml[0]['vsys'][0]['vsysId'][0]
494
+ opts[:realm_id] = xml[0]['vsys'][0]['vsysId'][0] if xml
478
495
  end
479
496
 
480
497
  vdisk_id = client.create_vdisk(opts[:realm_id], opts[:name], opts[:capacity])['vdiskId'][0]
@@ -528,18 +545,24 @@ class FgcpDriver < Deltacloud::BaseDriver
528
545
  if opts and opts[:id]
529
546
  vdisk_id, backup_id = split_snapshot_id(opts[:id])
530
547
 
531
- if backups = client.list_vdisk_backup(vdisk_id)['backups']
548
+ begin
549
+ if backups = client.list_vdisk_backup(vdisk_id)['backups']
532
550
 
533
- backups[0]['backup'].each do |backup|
551
+ backups[0]['backup'].each do |backup|
534
552
 
535
- snapshots << StorageSnapshot.new(
536
- :id => opts[:id],
537
- #:state => ?,
538
- :storage_volume_id => vdisk_id,
539
- :created => backup['backupTime'][0]
540
- ) if backup_id = backup['backupId'][0]
553
+ snapshots << StorageSnapshot.new(
554
+ :id => opts[:id],
555
+ #:state => ?,
556
+ :storage_volume_id => vdisk_id,
557
+ :created => backup['backupTime'][0]
558
+ ) if backup_id = backup['backupId'][0]
559
+ end
541
560
  end
561
+ rescue Exception => ex
562
+ return [] if ex.message =~ /RESOURCE_NOT_FOUND/
563
+ raise
542
564
  end
565
+
543
566
  elsif xml = client.list_vsys['vsyss']
544
567
 
545
568
  return [] if xml.nil?
@@ -683,8 +706,8 @@ class FgcpDriver < Deltacloud::BaseDriver
683
706
  opts[:realm_id] = client.extract_vsys_id(opts[:realm_id])
684
707
  else
685
708
  # get first vsys
686
- xml = client.list_vsys
687
- opts[:realm_id] = xml['vsyss'][0]['vsys'][0]['vsysId'][0] if xml['vsyss']
709
+ xml = client.list_vsys['vsyss']
710
+ opts[:realm_id] = xml[0]['vsys'][0]['vsysId'][0] if xml
688
711
  end
689
712
 
690
713
  client.allocate_public_ip(opts[:realm_id])
@@ -834,49 +857,56 @@ class FgcpDriver < Deltacloud::BaseDriver
834
857
  </Request>
835
858
  eofwpxml
836
859
 
837
- fw = client.get_efm_configuration(opts[:id], 'FW_POLICY', configuration_xml)
860
+ begin
861
+ fw = client.get_efm_configuration(opts[:id], 'FW_POLICY', configuration_xml)
862
+ rescue Exception => ex
863
+ return [] if ex.message =~ /RESOURCE_NOT_FOUND/
864
+ raise
865
+ end
838
866
  fw_name = fw['efm'][0]['efmName'][0] # currently always 'Firewall'
839
867
  fw_owner_id = fw['efm'][0]['creator'][0]
840
868
  rule50000_log = true
841
869
 
842
- fw['efm'][0]['firewall'][0]['directions'][0]['direction'].each do |direction|
870
+ if fw['efm'][0]['firewall'][0]['directions'] and fw['efm'][0]['firewall'][0]['directions'][0]['direction']
871
+ fw['efm'][0]['firewall'][0]['directions'][0]['direction'].each do |direction|
843
872
 
844
- direction['policies'][0]['policy'].each do |policy|
873
+ direction['policies'][0]['policy'].each do |policy|
845
874
 
846
- sources = []
847
- ['src', 'dst'].each do |e|
875
+ sources = []
876
+ ['src', 'dst'].each do |e|
848
877
 
849
- if policy[e] and policy[e][0] and not policy[e][0].empty?
878
+ if policy[e] and policy[e][0] and not policy[e][0].empty?
850
879
 
851
- ip_address_type = policy["#{e}Type"][0]
852
- address = policy[e][0]
853
- address.sub!('any', '0.0.0.0/0') if ip_address_type == 'IP'
854
- address += '/32' if ip_address_type == 'IP' and not address =~ /.*\/.*/
880
+ ip_address_type = policy["#{e}Type"][0]
881
+ address = policy[e][0]
882
+ address.sub!('any', '0.0.0.0/0') if ip_address_type == 'IP'
883
+ address += '/32' if ip_address_type == 'IP' and not address =~ /.*\/.*/
855
884
 
856
- sources << {
857
- :type => 'address',
858
- :family => 'ipv4',
859
- :address => address.split('/').first,
860
- :prefix => ip_address_type == 'IP' ? address.split('/').last : nil
861
- }
885
+ sources << {
886
+ :type => 'address',
887
+ :family => 'ipv4',
888
+ :address => address.split('/').first,
889
+ :prefix => ip_address_type == 'IP' ? address.split('/').last : nil
890
+ }
891
+ end
862
892
  end
863
- end
864
893
 
865
- # defining ingress as access going from Internet/Intranet -> DMZ -> SECURE1 -> SECURE2
866
- ingress = policy['id'][0] =~ /[13].*/ ? 'ingress' : 'egress'
867
-
868
- rules << FirewallRule.new({
869
- :id => policy['id'][0],
870
- :rule_action => policy['action'][0].downcase,
871
- :log_rule => policy['log'][0] == 'On',
872
- :allow_protocol => policy['protocol'][0],
873
- :port_from => policy['srcPort'] ? policy['srcPort'][0] : nil, # not set for e.g. ICMP
874
- :port_to => policy['dstPort'] ? policy['dstPort'][0] : nil, # not set for e.g. ICMP
875
- :direction => ingress,
876
- :sources => sources
877
- }) unless policy['id'][0] == '50000' # special case added later
878
-
879
- rule50000_log = (policy['log'][0] == 'On') if policy['id'][0] == '50000'
894
+ # defining ingress as access going from Internet/Intranet -> DMZ -> SECURE1 -> SECURE2
895
+ ingress = policy['id'][0] =~ /[13].*/ ? 'ingress' : 'egress'
896
+
897
+ rules << FirewallRule.new({
898
+ :id => policy['id'][0],
899
+ :rule_action => policy['action'][0].downcase,
900
+ :log_rule => policy['log'][0] == 'On',
901
+ :allow_protocol => policy['protocol'][0],
902
+ :port_from => policy['srcPort'] ? policy['srcPort'][0] : nil, # not set for e.g. ICMP
903
+ :port_to => policy['dstPort'] ? policy['dstPort'][0] : nil, # not set for e.g. ICMP
904
+ :direction => ingress,
905
+ :sources => sources
906
+ }) unless policy['id'][0] == '50000' # special case added later
907
+
908
+ rule50000_log = (policy['log'][0] == 'On') if policy['id'][0] == '50000'
909
+ end
880
910
  end
881
911
  end
882
912
 
@@ -947,7 +977,31 @@ eofwpxml
947
977
  def delete_firewall(credentials, opts={})
948
978
  safely do
949
979
  client = new_client(credentials)
950
- client.destroy_vsys(client.extract_vsys_id(opts[:id]))
980
+ begin
981
+ # try to stop FW first
982
+ opts[:id] =~ /^(.*-S-)\d\d\d\d/
983
+ fw_id = $1 + '0001'
984
+ client.stop_efm(fw_id)
985
+ rescue Exception => ex
986
+ raise ex if not ex.message =~ /ALREADY_STOPPED.*/
987
+ client.destroy_vsys(client.extract_vsys_id(opts[:id]))
988
+ return
989
+ end
990
+
991
+ Thread.new {
992
+ attempts = 0
993
+ begin
994
+ sleep 30
995
+ # this may fail if the FW is still stopping
996
+ client.destroy_vsys(client.extract_vsys_id(opts[:id]))
997
+ rescue Exception => ex
998
+ raise unless attempts < 20 and ex.message =~ /SERVER_RUNNING.*/
999
+ # Stopping takes a few minutes, so keep trying for a while
1000
+ attempts += 1
1001
+ retry
1002
+ end
1003
+ }
1004
+ raise 'Firewall will be deleted once it has stopped'
951
1005
  end
952
1006
  end
953
1007
 
@@ -1050,7 +1104,7 @@ eofwopxml
1050
1104
  realm = Realm::new(
1051
1105
  :id => vserver['vnics'][0]['vnic'][0]['networkId'][0],
1052
1106
  :name => realm_name,
1053
- :limit => '[Network segment]',
1107
+ :limit => '[Network]',
1054
1108
  :state => 'AVAILABLE' # map to state of FW/VSYS (reconfiguring = unavailable)?
1055
1109
  )
1056
1110
  balancer = LoadBalancer.new({
@@ -1085,7 +1139,7 @@ eofwopxml
1085
1139
  realm = Realm::new(
1086
1140
  :id => vserver['vnics'][0]['vnic'][0]['networkId'][0],
1087
1141
  :name => realm_name,
1088
- :limit => '[Network segment]',
1142
+ :limit => '[Network]',
1089
1143
  :state => 'AVAILABLE' # map to state of FW/VSYS (reconfiguring = unavailable)?
1090
1144
  )
1091
1145
  balancer = LoadBalancer.new({
@@ -1143,6 +1197,12 @@ eofwopxml
1143
1197
  # if opts['realm_id'].nil? network id specified, pick first vsys' DMZ?
1144
1198
  # CreateEFM -vsysId vsysId -efmType SLB -efmName opts['name'] -networkId opts['realm_id']
1145
1199
  network_id = opts[:realm_id]
1200
+ if not network_id
1201
+ xml = client.list_vsys['vsyss']
1202
+
1203
+ # use first returned system's DMZ as realm
1204
+ network_id = xml ? xml[0]['vsys'][0]['vsysId'][0] + '-N-DMZ' : nil
1205
+ end
1146
1206
  efm = client.create_efm('SLB', opts[:name], network_id)
1147
1207
  # [{:load_balancer_port => opts['listener_balancer_port'],
1148
1208
  # :instance_port => opts['listener_instance_port'],
@@ -1214,7 +1274,12 @@ eofwopxml
1214
1274
  def metric(credentials, opts={})
1215
1275
  safely do
1216
1276
  client = new_client(credentials)
1217
- perf = client.get_performance_information(opts[:id], 'hour')
1277
+ begin
1278
+ perf = client.get_performance_information(opts[:id], 'hour')
1279
+ rescue Exception => ex
1280
+ return nil if ex.message =~ /RESOURCE_NOT_FOUND/
1281
+ raise
1282
+ end
1218
1283
 
1219
1284
  metric = Metric.new(
1220
1285
  :id => opts[:id],
@@ -1273,47 +1338,47 @@ eofwopxml
1273
1338
 
1274
1339
  exceptions do
1275
1340
 
1341
+ # FW will be deleted in async polling thread, so can't guarantee successful completion
1342
+ on /Firewall will be deleted once it has stopped/ do
1343
+ status 202 # Accepted
1344
+ end
1345
+
1276
1346
  on /ALREADY_STARTED/ do
1277
- status 405
1347
+ status 405 # Method Not Allowed
1278
1348
  end
1279
1349
 
1280
1350
  # trying to start a running vserver, etc.
1281
1351
  on /ILLEGAL_STATE/ do
1282
- status 405
1352
+ status 405 # Method Not Allowed
1283
1353
  end
1284
1354
 
1285
1355
  on /AuthFailure/ do
1286
- status 401
1356
+ status 401 # Unauthorized
1287
1357
  end
1288
1358
 
1289
1359
  # User not found: using certificate with wrong region
1290
1360
  on /User not found in selectData./ do
1291
- status 401
1361
+ status 401 # Unauthorized
1292
1362
  end
1293
1363
 
1294
1364
  # if user doesn't have privileges to view or operate a particular resource
1295
1365
  on /User doesn.t have the right of access./ do
1296
- status 400
1297
- end
1298
-
1299
- # time out of sync with ntp
1300
- on /VALIDATION_ERROR.*synchronized.*API-Server time/ do
1301
- status 502
1366
+ status 403 # Forbidden
1302
1367
  end
1303
1368
 
1304
1369
  # wrong vserverId, etc.
1305
1370
  on /VALIDATION_ERROR/ do
1306
- status 404
1371
+ status 404 # Not Found
1307
1372
  end
1308
1373
 
1309
1374
  # wrong vdiskId, etc.
1310
1375
  on /RESOURCE_NOT_FOUND/ do
1311
- status 404
1376
+ status 404 # Not Found
1312
1377
  end
1313
1378
 
1314
1379
  # wrong FW description (vsys descriptor)
1315
1380
  on /does not exist. Specify one of / do
1316
- status 404
1381
+ status 404 # Not Found
1317
1382
  end
1318
1383
 
1319
1384
  # trying an operation that is not supported (yet) by the target region
@@ -1321,19 +1386,24 @@ eofwopxml
1321
1386
  status 501 # Not Implemented
1322
1387
  end
1323
1388
 
1389
+ # time out of sync with ntp
1390
+ on /VALIDATION_ERROR.*synchronized.*API-Server time/ do
1391
+ status 502 # Bad Gateway
1392
+ end
1393
+
1324
1394
  # destroying a running SLB, etc.
1325
1395
  on /ALREADY_STARTED/ do
1326
- status 502 #?
1396
+ status 502 # Bad Gateway?
1327
1397
  end
1328
1398
 
1329
1399
  # trying to start a running vserver, etc.
1330
1400
  on /ILLEGAL_STATE/ do
1331
- status 502
1401
+ status 502 # Bad Gateway
1332
1402
  end
1333
1403
 
1334
1404
  # endpoint for country of certificate subject not found
1335
1405
  on /API endpoint not found/ do
1336
- status 502
1406
+ status 502 # Bad Gateway
1337
1407
  end
1338
1408
 
1339
1409
  on /.*/ do
@@ -1406,7 +1476,8 @@ eofwopxml
1406
1476
  vsys_id = client.extract_vsys_id(instance.id)
1407
1477
  if slbs = client.list_efm(vsys_id, 'SLB')['efms']
1408
1478
  slbs[0]['efm'].find do |slb|
1409
- instance.private_addresses << InstanceAddress.new(slb['slbVip'][0], :type => :ipv4) if slb['efmId'][0] == instance.id
1479
+ # note that slbVip may not be set yet (in just created SLBs)
1480
+ instance.private_addresses << InstanceAddress.new(slb['slbVip'][0], :type => :ipv4) if slb['slbVip'] and slb['efmId'][0] == instance.id
1410
1481
  end
1411
1482
  end
1412
1483
  end