chef-provisioning-oneview 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +43 -3
  3. data/lib/chef/provisioning/create_machine.rb +52 -0
  4. data/lib/chef/provisioning/customize_machine.rb +78 -0
  5. data/lib/chef/provisioning/icsp/api_v104.rb +27 -0
  6. data/lib/chef/provisioning/icsp/icsp_api.rb +282 -0
  7. data/lib/chef/provisioning/oneview/oneview_api.rb +56 -357
  8. data/lib/chef/provisioning/oneview/san_storage.rb +91 -0
  9. data/lib/chef/provisioning/oneview/v1.2/api.rb +3 -0
  10. data/lib/chef/provisioning/oneview_driver.rb +42 -5
  11. data/lib/chef/provisioning/rest.rb +51 -0
  12. data/lib/chef/provisioning/{oneview/version.rb → version.rb} +1 -1
  13. data/spec/shared_context.rb +77 -0
  14. data/spec/spec_helper.rb +8 -6
  15. data/spec/{unit/support → support}/fake_action_handler.rb +0 -0
  16. data/spec/support/fake_icsp.rb +73 -21
  17. data/spec/support/fake_machine_spec.rb +18 -0
  18. data/spec/support/fake_oneview.rb +148 -21
  19. data/spec/support/fixtures/icsp/v102/error_404.json +13 -13
  20. data/spec/support/fixtures/icsp/v102/login.json +4 -4
  21. data/spec/support/fixtures/icsp/v102/os-deployment-build-plans.json +99 -99
  22. data/spec/support/fixtures/icsp/v102/{os-deployment-servers_managed.json → os-deployment-servers.json} +178 -178
  23. data/spec/support/fixtures/icsp/v102/os-deployment-servers_1670001.json +83 -0
  24. data/spec/support/fixtures/icsp/v102/os-deployment-servers_fakesn.json +9 -0
  25. data/spec/support/fixtures/icsp/v102/{server_by_sn.json → server_by_sn_VCGE9KB041.json} +44 -44
  26. data/spec/support/fixtures/icsp/v102/server_by_sn_empty.json +16 -0
  27. data/spec/support/fixtures/icsp/v102/version.json +3 -3
  28. data/spec/support/fixtures/oneview/v120/error_404.json +13 -13
  29. data/spec/support/fixtures/oneview/v120/login.json +4 -4
  30. data/spec/support/fixtures/oneview/v120/server-hardware.json +1475 -1475
  31. data/spec/support/fixtures/oneview/v120/server-hardware_Template-WebServer.json +468 -0
  32. data/spec/support/fixtures/oneview/v120/server-hardware_specific.json +151 -0
  33. data/spec/support/fixtures/oneview/v120/server-profiles.json +368 -746
  34. data/spec/support/fixtures/oneview/v120/server-profiles_invalid_filter.json +14 -0
  35. data/spec/support/fixtures/oneview/v120/{server-profiles_specific.json → server-profiles_name_Template-WebServer.json} +132 -132
  36. data/spec/support/fixtures/oneview/v120/server-profiles_name_Template-WebServerWithSAN.json +200 -0
  37. data/spec/support/fixtures/oneview/v120/server-profiles_name_chef-web01.json +133 -0
  38. data/spec/support/fixtures/oneview/v120/server-profiles_name_chef-web03.json +133 -0
  39. data/spec/support/fixtures/oneview/v120/server-profiles_name_empty.json +15 -0
  40. data/spec/support/fixtures/oneview/v120/server-profiles_sn_VCGE9KB041.json +133 -0
  41. data/spec/support/fixtures/oneview/v120/server-profiles_sn_VCGE9KB042.json +206 -0
  42. data/spec/support/fixtures/oneview/v120/server-profiles_sn_empty.json +15 -0
  43. data/spec/support/fixtures/oneview/v120/storage-volumes_1B5D3CA2-6C5B-41C2-8B97-1821F1883F22.json +26 -0
  44. data/spec/support/fixtures/oneview/v120/tasks_fake_active.json +5 -0
  45. data/spec/support/fixtures/oneview/v120/tasks_fake_complete.json +5 -0
  46. data/spec/support/fixtures/oneview/v120/version.json +3 -3
  47. data/spec/support/fixtures/oneview/v200/server-profile-templates_WebServerTemplate.json +109 -0
  48. data/spec/support/fixtures/oneview/v200/server-profile-templates_WebServerTemplateWithSAN.json +144 -0
  49. data/spec/support/fixtures/oneview/v200/server-profile-templates_invalid.json +16 -0
  50. data/spec/support/fixtures/oneview/v200/server-profile-templates_new-profile_WebServerTemplate.json +125 -0
  51. data/spec/support/fixtures/oneview/v200/server-profile-templates_new-profile_WebServerTemplateWithSAN.json +178 -0
  52. data/spec/support/fixtures/oneview/v200/version.json +4 -0
  53. data/spec/unit/create_machine_spec.rb +78 -0
  54. data/spec/unit/destroy_spec.rb +26 -0
  55. data/spec/unit/icsp_nic_teams_spec.rb +38 -0
  56. data/spec/unit/icsp_search_spec.rb +25 -0
  57. data/spec/unit/oneview_driver_spec.rb +37 -64
  58. data/spec/unit/oneview_login_spec.rb +23 -0
  59. data/spec/unit/oneview_power_spec.rb +51 -0
  60. data/spec/unit/oneview_san_spec.rb +86 -0
  61. data/spec/unit/oneview_search_spec.rb +63 -0
  62. data/spec/unit/rest_api_spec.rb +115 -0
  63. metadata +90 -9
  64. data/lib/chef/provisioning/oneview/v1.20/api.rb +0 -3
@@ -0,0 +1,91 @@
1
+ # Methods for configuring SAN storage on OneView
2
+ module OneViewSanStorage
3
+ def fill_volume_details(v)
4
+ details = rest_api(:oneview, :get, v['volumeUri'])
5
+ v['volumeName'] = details['name']
6
+ v['permanent'] = details['isPermanent']
7
+ v['volumeShareable'] = details['shareable']
8
+ v['volumeProvisionType'] = details['provisionType']
9
+ v['volumeProvisionedCapacityBytes'] = details['provisionedCapacity']
10
+ v['volumeDescription'] = details['description']
11
+ v
12
+ end
13
+
14
+ # Prepare profile for SAN storage
15
+ def update_san_info(machine_spec, profile)
16
+ san_storage = profile['sanStorage']
17
+ return profile unless san_storage && !san_storage['volumeAttachments'].empty?
18
+
19
+ # Sanitize old SAN entries and fill in details
20
+ boot_vols = []
21
+ san_storage['volumeAttachments'].each do |v|
22
+ fill_volume_details(v) unless profile['serverProfileTemplateUri']
23
+ fail "#{machine_spec.name}: Should know if volume is sharable:\n#{v}" unless v.key?('volumeShareable')
24
+
25
+ # Match boot disks by name
26
+ boot_vols.push(v['volumeName']) if v['volumeName'].downcase.match(/^boot/)
27
+ v['volumeName'] += " #{profile['name']}" unless v['volumeShareable'] # Append profile name to volume name
28
+
29
+ unless profile['serverProfileTemplateUri'] # Only needed when coppied from profile
30
+ v['state'] = nil
31
+ v['status'] = nil
32
+ v['storagePaths'].each { |s| s['status'] = nil }
33
+
34
+ unless v['volumeShareable']
35
+ # It is private in the profile, so we will clone it
36
+ v['volumeUri'] = nil
37
+
38
+ # Assumes all cloned volumes are non-permanet. Might want some global config to control this
39
+ v['permanent'] = false
40
+ v['lun'] = nil if v['lunType'].downcase == 'auto'
41
+ end
42
+ end
43
+ end
44
+ fail "#{machine_spec.name}: There should only be 1 SAN boot volume. Boot volumes: #{boot_vols}" if boot_vols.size > 1
45
+ profile
46
+ end
47
+
48
+ # Make sure connections for SAN boot volumes are configured to boot from the correct SAN volume
49
+ def enable_boot_from_san(action_handler, machine_spec, profile)
50
+ return false if profile['connections'].nil? || profile['connections'].empty?
51
+
52
+ # If there is a san volume we might need to update boot connections
53
+ update_needed = false
54
+ profile['sanStorage']['volumeAttachments'].each do |v|
55
+ vol_details = rest_api(:oneview, :get, v['volumeUri'])
56
+ next unless vol_details['name'].downcase.match(/^boot/)
57
+ # Find the enabled path(s), get target wwpn, and then update connection, setting boot targets
58
+ v['storagePaths'].each do |s|
59
+ next if !s['isEnabled'] || s['storageTargets'].nil? || s['storageTargets'].empty?
60
+ connection = profile['connections'].find { |c| c['id'] == s['connectionId'] }
61
+ fail "#{machine_spec.name}: Connection #{s['connectionId']} not found! Check SAN settings" unless connection
62
+ if connection['boot'].nil? || connection['boot']['priority'] == 'NotBootable'
63
+ msg = "#{machine_spec.name}: Connection #{s['connectionId']} is labeled for boot, but the connection is not marked as bootable."
64
+ fail "#{msg} Set the connection boot target to Primary or Secondary"
65
+ end
66
+ target = {}
67
+ target['arrayWwpn'] = s['storageTargets'].first.delete(':')
68
+ target['lun'] = v['lun']
69
+ unless connection['boot']['targets'] && connection['boot']['targets'].first &&
70
+ connection['boot']['targets'].first['arrayWwpn'] == target['arrayWwpn'] &&
71
+ connection['boot']['targets'].first['lun'] == target['lun']
72
+ connection['boot']['targets'] = [target]
73
+ update_needed = true
74
+ end
75
+ end
76
+ end
77
+
78
+ if update_needed
79
+ action_handler.perform_action "Enable SAN-bootable connections for #{machine_spec.name}" do
80
+ action_handler.report_progress "INFO: Enabling SAN-bootable connections for #{machine_spec.name}"
81
+ power_off(action_handler, machine_spec, profile['serverHardwareUri'])
82
+ task = rest_api(:oneview, :put, profile['uri'], { 'body' => profile })
83
+ task = oneview_wait_for(task['uri'], 90) # Wait for up to 15 min for profile to be updated
84
+ fail "Timed out waiting for enabling SAN-bootable connections on #{machine_spec.name}" if task == false
85
+ fail "Error enabling SAN-bootable connections on #{machine_spec.name}. Response: #{task}" unless task == true
86
+ end
87
+ profile = rest_api(:oneview, :get, profile['uri'])
88
+ end
89
+ profile # Return profile
90
+ end
91
+ end
@@ -0,0 +1,3 @@
1
+ module OneViewAPIv1_2
2
+ # TODO
3
+ end
@@ -7,12 +7,20 @@ require 'chef/provisioning/machine/unix_machine'
7
7
  require 'json'
8
8
  require 'ridley'
9
9
  require_relative 'driver_init/oneview'
10
- require_relative 'oneview/version'
10
+ require_relative 'version'
11
+ require_relative 'rest'
12
+ require_relative 'create_machine'
13
+ require_relative 'customize_machine'
11
14
  require_relative 'oneview/oneview_api'
15
+ require_relative 'icsp/icsp_api'
12
16
 
13
17
  module Chef::Provisioning
14
18
  class OneViewDriver < Chef::Provisioning::Driver
19
+ include CreateMachine
20
+ include CustomizeMachine
21
+ include RestAPI
15
22
  include OneViewAPI
23
+ include ICspAPI
16
24
 
17
25
  def self.canonicalize_url(url, config)
18
26
  _scheme, oneview_url = url.split(':', 2)
@@ -37,7 +45,8 @@ module Chef::Provisioning
37
45
  @oneview_password = config[:knife][:oneview_password]
38
46
  fail 'Must set the knife[:oneview_password] attribute!' if @oneview_password.nil? || @oneview_password.empty?
39
47
  @oneview_disable_ssl = config[:knife][:oneview_ignore_ssl]
40
- @oneview_api_version = 120 # get_oneview_api_version
48
+ @oneview_api_version = 120 # Use this version for all calls that don't override it
49
+ @current_oneview_api_version = get_oneview_api_version
41
50
  @oneview_key = login_to_oneview
42
51
 
43
52
  @icsp_base_url = config[:knife][:icsp_url]
@@ -47,7 +56,8 @@ module Chef::Provisioning
47
56
  @icsp_password = config[:knife][:icsp_password]
48
57
  fail 'Must set the knife[:icsp_password] attribute!' if @icsp_password.nil? || @icsp_password.empty?
49
58
  @icsp_disable_ssl = config[:knife][:icsp_ignore_ssl]
50
- @icsp_api_version = 102 # get_icsp_api_version
59
+ @icsp_api_version = 102 # Use this version for all calls that don't override it
60
+ @current_icsp_api_version = get_icsp_api_version
51
61
  @icsp_key = login_to_icsp
52
62
  end
53
63
 
@@ -58,6 +68,9 @@ module Chef::Provisioning
58
68
  if get_oneview_profile_by_sn(machine_spec.reference['serial_number']).nil? # It doesn't really exist
59
69
  action_handler.report_progress "Machine #{host_name} does not really exist. Recreating ..."
60
70
  machine_spec.reference = nil
71
+ else # Update reference data
72
+ machine_spec.reference['driver_url'] = driver_url
73
+ machine_spec.reference['driver_version'] = ONEVIEW_DRIVER_VERSION
61
74
  end
62
75
  end
63
76
  if !machine_spec.reference
@@ -82,6 +95,7 @@ module Chef::Provisioning
82
95
 
83
96
  def ready_machine(action_handler, machine_spec, machine_options)
84
97
  profile = get_oneview_profile_by_sn(machine_spec.reference['serial_number'])
98
+ fail "Failed to retrieve Server Profile for #{machine_spec.name}. Serial Number used to search: #{machine_spec.reference['serial_number']}" unless profile
85
99
  customize_machine(action_handler, machine_spec, machine_options, profile)
86
100
  machine_for(machine_spec, machine_options) # Return the Machine object
87
101
  end
@@ -89,10 +103,24 @@ module Chef::Provisioning
89
103
 
90
104
  def machine_for(machine_spec, machine_options)
91
105
  bootstrap_ip_address = machine_options[:driver_options][:ip_address]
106
+ unless bootstrap_ip_address
107
+ id, connection = machine_options[:driver_options][:connections].find { |_id, c| c[:bootstrap] == true }
108
+ fail 'Must specify a connection to use to bootstrap!' unless id && connection
109
+ bootstrap_ip_address = connection[:ip4Address] # For static IPs
110
+ unless bootstrap_ip_address # Look for dhcp address given to this connection
111
+ profile = get_oneview_profile_by_sn(machine_spec.reference['serial_number'])
112
+ my_server = get_icsp_server_by_sn(machine_spec.reference['serial_number'])
113
+ mac = profile['connections'].find {|x| x['id'] == id}['mac']
114
+ interface = my_server['interfaces'].find { |i| i['macAddr'] == mac }
115
+ bootstrap_ip_address = interface['ipv4Addr'] || interface['ipv6Addr']
116
+ end
117
+ bootstrap_ip_address ||= my_server['hostName'] # Fall back on hostName
118
+ end
119
+ fail 'Server IP address not specified and could not be retrieved!' unless bootstrap_ip_address
92
120
  username = machine_options[:transport_options][:user] || 'root' rescue 'root'
93
121
  default_ssh_options = {
94
- # auth_methods: ['publickey'],
95
- # keys: ['/home/username/.vagrant.d/insecure_private_key'],
122
+ # auth_methods: ['password', 'publickey'],
123
+ # keys: ['~/.ssh/id_rsa'],
96
124
  password: Chef::Config.knife[:node_root_password]
97
125
  }
98
126
  ssh_options = machine_options[:transport_options][:ssh_options] || default_ssh_options rescue default_ssh_options
@@ -169,5 +197,14 @@ module Chef::Provisioning
169
197
  machine_for(machine_spec, machine_options)
170
198
  end
171
199
 
200
+ private
201
+
202
+ # Login to both OneView and ICsp
203
+ def auth_tokens
204
+ @icsp_key ||= login_to_icsp
205
+ @oneview_key ||= login_to_oneview
206
+ { 'icsp_key' => @icsp_key, 'oneview_key' => @oneview_key }
207
+ end
208
+
172
209
  end # class end
173
210
  end # module end
@@ -0,0 +1,51 @@
1
+ module RestAPI
2
+ # API calls for OneView and ICsp
3
+ def rest_api(host, type, path, options = {})
4
+ disable_ssl = false
5
+ case host
6
+ when 'icsp', :icsp
7
+ uri = URI.parse(URI.escape(@icsp_base_url + path))
8
+ options['X-API-Version'] ||= @icsp_api_version unless [:put, 'put'].include?(type.downcase)
9
+ options['auth'] ||= @icsp_key
10
+ disable_ssl = true if @icsp_disable_ssl
11
+ when 'oneview', :oneview
12
+ uri = URI.parse(URI.escape(@oneview_base_url + path))
13
+ options['X-API-Version'] ||= @oneview_api_version
14
+ options['auth'] ||= @oneview_key
15
+ disable_ssl = true if @oneview_disable_ssl
16
+ else
17
+ fail "Invalid rest host: #{host}"
18
+ end
19
+
20
+ http = Net::HTTP.new(uri.host, uri.port)
21
+ http.use_ssl = true if uri.scheme == 'https'
22
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE if disable_ssl
23
+
24
+ case type.downcase
25
+ when 'get', :get
26
+ request = Net::HTTP::Get.new(uri.request_uri)
27
+ when 'post', :post
28
+ request = Net::HTTP::Post.new(uri.request_uri)
29
+ when 'put', :put
30
+ request = Net::HTTP::Put.new(uri.request_uri)
31
+ when 'delete', :delete
32
+ request = Net::HTTP::Delete.new(uri.request_uri)
33
+ else
34
+ fail "Invalid rest call: #{type}"
35
+ end
36
+ options['Content-Type'] ||= 'application/json'
37
+ options.delete('Content-Type') if [:none, 'none', nil].include?(options['Content-Type'])
38
+ options.delete('X-API-Version') if [:none, 'none', nil].include?(options['X-API-Version'])
39
+ options.delete('auth') if [:none, 'none', nil].include?(options['auth'])
40
+ options.each do |key, val|
41
+ if key.downcase == 'body'
42
+ request.body = val.to_json rescue val
43
+ else
44
+ request[key] = val
45
+ end
46
+ end
47
+
48
+ response = http.request(request)
49
+ JSON.parse(response.body) rescue response
50
+ end
51
+ end # End module
@@ -1,5 +1,5 @@
1
1
  class Chef
2
2
  module Provisioning
3
- ONEVIEW_DRIVER_VERSION = '1.0.1'
3
+ ONEVIEW_DRIVER_VERSION = '1.1.0'
4
4
  end
5
5
  end
@@ -0,0 +1,77 @@
1
+ RSpec.shared_context 'shared context', a: :b do
2
+
3
+ domain = 'my-domain.com'
4
+ chef_server = "https://my-chef-server.#{domain}/organizations/oneview"
5
+ oneview = "https://my-oneview.#{domain}"
6
+ icsp = "https://my-icsp.#{domain}"
7
+
8
+ let(:knife_config) do
9
+ { knife: {
10
+ oneview_url: oneview,
11
+ oneview_username: 'Administrator',
12
+ oneview_password: 'password12',
13
+ oneview_ignore_ssl: true,
14
+
15
+ icsp_url: icsp,
16
+ icsp_username: 'administrator',
17
+ icsp_password: 'password123'
18
+ } }
19
+ end
20
+
21
+ let(:valid_machine_options) do
22
+ {
23
+ convergence_options: {
24
+ ssl_verify_mode: :verify_none,
25
+ bootstrap_proxy: "http://proxy.#{domain}:8080",
26
+ chef_server: {
27
+ chef_server_url: chef_server,
28
+ options: {
29
+ client_name: 'user',
30
+ signing_key_filename: 'spec/fixtures/.chef/user.pem'
31
+ }
32
+ }
33
+ },
34
+ driver_options: {
35
+ server_template: 'Template - Web Server',
36
+ os_build: 'CHEF-RHEL-6.5-x64',
37
+ host_name: 'chef-web01',
38
+ ip_address: '192.168.1.2',
39
+ domainType: 'workgroup',
40
+ domainName: domain,
41
+ gateway: '192.168.1.1',
42
+ dns: '192.168.1.1,10.1.1.1',
43
+ connections: {
44
+ 1 => { dhcp: true, team: 'team1' },
45
+ 2 => { ip4Address: '192.168.1.2', mask: '255.255.254.0', dhcp: false, team: 'team1' }
46
+ }
47
+ },
48
+ custom_attributes: {
49
+
50
+ },
51
+ transport_options: {
52
+ ssh_options: { password: 'password1234' }
53
+ }
54
+ }
55
+ end
56
+
57
+ let(:action_handler) do
58
+ ChefProvisioningOneviewHelpers::FakeActionHandler.new
59
+ end
60
+
61
+ let(:machine_spec) do
62
+ ChefProvisioningOneviewHelpers::FakeMachineSpec.new('server-1', 'VCGE9KB041')
63
+ end
64
+
65
+ let(:machine_spec2) do
66
+ ChefProvisioningOneviewHelpers::FakeMachineSpec.new('server-2', '789123')
67
+ end
68
+
69
+ before :each do
70
+ @oneview_key = 'A954A2A6Psy7Alg3HApAcEbAcAwa-ftA'
71
+ @icsp_key = 'AA_aaAaa3AA3Aa0_aAaAA4AAAA3AAAAA'
72
+ @url = oneview
73
+ @canonical_url = "oneview:#{@url}"
74
+ @instance = Chef::Provisioning::OneViewDriver.new(@canonical_url, knife_config)
75
+ end
76
+
77
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,20 +1,22 @@
1
1
  require 'pry'
2
+ require 'webmock/rspec'
3
+ require 'simplecov'
4
+ SimpleCov.start
5
+
2
6
  require_relative './../lib/chef/provisioning/driver_init/oneview'
3
7
  require_relative 'support/fake_oneview'
4
8
  require_relative 'support/fake_icsp'
5
- require 'webmock/rspec'
9
+ require_relative 'support/fake_machine_spec'
10
+ require_relative 'support/fake_action_handler'
11
+ require_relative 'shared_context'
6
12
  # WebMock.disable_net_connect!(allow_localhost: true)
7
13
 
8
14
  RSpec.configure do |config|
9
15
  config.before(:each) do
10
- allow_any_instance_of(Chef::Provisioning::OneViewDriver).to receive(:get_oneview_api_version).and_return(120)
11
- allow_any_instance_of(Chef::Provisioning::OneViewDriver).to receive(:get_icsp_api_version).and_return(102)
12
- allow_any_instance_of(Chef::Provisioning::OneViewDriver).to receive(:login_to_oneview).and_return('long_oneview_key')
13
- allow_any_instance_of(Chef::Provisioning::OneViewDriver).to receive(:login_to_icsp).and_return('long_icsp_key')
14
-
15
16
  stub_request(:any, /my-oneview.my-domain.com/).to_rack(FakeOneView)
16
17
  stub_request(:any, /my-icsp.my-domain.com/).to_rack(FakeIcsp)
17
18
  end
19
+
18
20
  end
19
21
 
20
22
  # Chef::Log.level = :debug
@@ -1,21 +1,73 @@
1
- require 'sinatra/base'
2
-
3
- class FakeIcsp < Sinatra::Base
4
- get '/rest/version' do
5
- version = request['X-API-Version'] # TODO
6
- json_response(200, 'version.json', version)
7
- end
8
-
9
- post '/rest/login-sessions' do
10
- version = request['X-API-Version'] # TODO
11
- json_response(200, 'login.json', version)
12
- end
13
-
14
- private
15
-
16
- def json_response(response_code, file_name, version = 102)
17
- content_type :json
18
- status response_code
19
- File.open(File.dirname(__FILE__) + "/fixtures/icsp/v#{version.gsub('.', '')}/" + file_name, 'rb').read
20
- end
21
- end
1
+ require 'sinatra/base'
2
+ require 'json'
3
+
4
+ class FakeIcsp < Sinatra::Base
5
+
6
+ get '/rest/version' do
7
+ json_response(200, 'version.json', '102')
8
+ end
9
+
10
+ get '/rest/index/resources' do
11
+ version = env['HTTP_X_API_VERSION']
12
+ category = params['category']
13
+ return json_response(404, 'error_404.json', version) if category.nil?
14
+ if category == 'osdserver' && params['query'].match(/osdServerSerialNumber:"VCGE9KB041"/)
15
+ return json_response(200, 'server_by_sn_VCGE9KB041.json', version)
16
+ elsif category == 'osdserver' && params['query'].match(/osdServerSerialNumber:"FAKESN"/)
17
+ return json_response(200, 'server_by_sn_empty.json', version)
18
+ else
19
+ return json_response(404, 'error_404.json', version)
20
+ end
21
+ end
22
+
23
+ get '/rest/os-deployment-servers' do
24
+ version = env['HTTP_X_API_VERSION']
25
+ json_response(200, 'os-deployment-servers.json', version)
26
+ end
27
+
28
+ get '/rest/os-deployment-servers/:id' do
29
+ version = env['HTTP_X_API_VERSION']
30
+ if params[:id] == '1670001'
31
+ return json_response(200, 'os-deployment-servers_1670001.json', version)
32
+ else
33
+ return json_response(200, 'os-deployment-servers_fakesn.json', version)
34
+ end
35
+ end
36
+
37
+ post '/rest/login-sessions' do
38
+ version = env['HTTP_X_API_VERSION']
39
+ json_response(200, 'login.json', version)
40
+ end
41
+
42
+ get '/' do
43
+ { message: 'Fake ICsp works!', method: env['REQUEST_METHOD'], content_type: env['CONTENT_TYPE'], query: env['QUERY_STRING'],
44
+ api_version: env['HTTP_X_API_VERSION'], auth: env['HTTP_AUTH'], params: params }.to_json
45
+ end
46
+
47
+ post '/' do
48
+ { message: 'Fake ICsp works!', method: env['REQUEST_METHOD'], content_type: env['CONTENT_TYPE'], query: env['QUERY_STRING'],
49
+ api_version: env['HTTP_X_API_VERSION'], auth: env['HTTP_AUTH'], params: params }.to_json
50
+ end
51
+
52
+ put '/' do
53
+ { message: 'Fake ICsp works!', method: env['REQUEST_METHOD'], content_type: env['CONTENT_TYPE'], query: env['QUERY_STRING'],
54
+ api_version: env['HTTP_X_API_VERSION'], auth: env['HTTP_AUTH'], params: params }.to_json
55
+ end
56
+
57
+ delete '/' do
58
+ { message: 'Fake ICsp works!', method: env['REQUEST_METHOD'], content_type: env['CONTENT_TYPE'], query: env['QUERY_STRING'],
59
+ api_version: env['HTTP_X_API_VERSION'], auth: env['HTTP_AUTH'], params: params }.to_json
60
+ end
61
+
62
+ get '/*' do # All other paths should return a 404 error
63
+ json_response(404, 'error_404.json', '102')
64
+ end
65
+
66
+ private
67
+
68
+ def json_response(response_code, file_name, version = 102)
69
+ content_type :json
70
+ status response_code
71
+ File.open(File.dirname(__FILE__) + "/fixtures/icsp/v#{version}/" + file_name, 'rb').read
72
+ end
73
+ end