chef-provisioning-oneview 1.0.1 → 1.1.0

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.
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