chef-provisioning-oneview 1.0.1

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.
@@ -0,0 +1,3 @@
1
+ module OneViewAPIv1_20
2
+ # TODO
3
+ end
@@ -0,0 +1,3 @@
1
+ module OneViewAPIv2_0
2
+ # TODO
3
+ end
@@ -0,0 +1,5 @@
1
+ class Chef
2
+ module Provisioning
3
+ ONEVIEW_DRIVER_VERSION = '1.0.1'
4
+ end
5
+ end
@@ -0,0 +1,173 @@
1
+ require 'chef/json_compat'
2
+ require 'chef/knife'
3
+ require 'chef/provisioning/convergence_strategy/install_sh'
4
+ require 'chef/provisioning/driver'
5
+ require 'chef/provisioning/transport/ssh'
6
+ require 'chef/provisioning/machine/unix_machine'
7
+ require 'json'
8
+ require 'ridley'
9
+ require_relative 'driver_init/oneview'
10
+ require_relative 'oneview/version'
11
+ require_relative 'oneview/oneview_api'
12
+
13
+ module Chef::Provisioning
14
+ class OneViewDriver < Chef::Provisioning::Driver
15
+ include OneViewAPI
16
+
17
+ def self.canonicalize_url(url, config)
18
+ _scheme, oneview_url = url.split(':', 2)
19
+ if oneview_url.nil? || oneview_url == ''
20
+ oneview_url = config[:knife][:oneview_url]
21
+ end
22
+ fail 'Must set the knife[:oneview_url] attribute!' if oneview_url.nil? || oneview_url.empty?
23
+ 'oneview:' + oneview_url
24
+ end
25
+
26
+ def self.from_url(oneview_url, config)
27
+ OneViewDriver.new(oneview_url, config)
28
+ end
29
+
30
+ def initialize(canonical_url, config)
31
+ super(canonical_url, config)
32
+
33
+ @oneview_base_url = config[:knife][:oneview_url]
34
+ fail 'Must set the knife[:oneview_url] attribute!' if @oneview_base_url.nil? || @oneview_base_url.empty?
35
+ @oneview_username = config[:knife][:oneview_username]
36
+ fail 'Must set the knife[:oneview_username] attribute!' if @oneview_username.nil? || @oneview_username.empty?
37
+ @oneview_password = config[:knife][:oneview_password]
38
+ fail 'Must set the knife[:oneview_password] attribute!' if @oneview_password.nil? || @oneview_password.empty?
39
+ @oneview_disable_ssl = config[:knife][:oneview_ignore_ssl]
40
+ @oneview_api_version = 120 # get_oneview_api_version
41
+ @oneview_key = login_to_oneview
42
+
43
+ @icsp_base_url = config[:knife][:icsp_url]
44
+ fail 'Must set the knife[:icsp_url] attribute!' if @icsp_base_url.nil? || @icsp_base_url.empty?
45
+ @icsp_username = config[:knife][:icsp_username]
46
+ fail 'Must set the knife[:icsp_username] attribute!' if @icsp_username.nil? || @icsp_username.empty?
47
+ @icsp_password = config[:knife][:icsp_password]
48
+ fail 'Must set the knife[:icsp_password] attribute!' if @icsp_password.nil? || @icsp_password.empty?
49
+ @icsp_disable_ssl = config[:knife][:icsp_ignore_ssl]
50
+ @icsp_api_version = 102 # get_icsp_api_version
51
+ @icsp_key = login_to_icsp
52
+ end
53
+
54
+
55
+ def allocate_machine(action_handler, machine_spec, machine_options)
56
+ host_name = machine_options[:driver_options][:host_name]
57
+ if machine_spec.reference
58
+ if get_oneview_profile_by_sn(machine_spec.reference['serial_number']).nil? # It doesn't really exist
59
+ action_handler.report_progress "Machine #{host_name} does not really exist. Recreating ..."
60
+ machine_spec.reference = nil
61
+ end
62
+ end
63
+ if !machine_spec.reference
64
+ action_handler.perform_action "Creating server #{machine_spec.name}" do
65
+ profile = create_machine(action_handler, machine_spec, machine_options)
66
+ machine_spec.reference = {
67
+ 'driver_url' => driver_url,
68
+ 'driver_version' => ONEVIEW_DRIVER_VERSION,
69
+ 'serial_number' => profile['serialNumber']
70
+ }
71
+ end
72
+ end
73
+ end
74
+
75
+
76
+ def allocate_machines(action_handler, specs_and_options, _parallelizer)
77
+ specs_and_options.each do |machine_spec, machine_options|
78
+ allocate_machine(action_handler, machine_spec, machine_options)
79
+ end
80
+ end
81
+
82
+
83
+ def ready_machine(action_handler, machine_spec, machine_options)
84
+ profile = get_oneview_profile_by_sn(machine_spec.reference['serial_number'])
85
+ customize_machine(action_handler, machine_spec, machine_options, profile)
86
+ machine_for(machine_spec, machine_options) # Return the Machine object
87
+ end
88
+
89
+
90
+ def machine_for(machine_spec, machine_options)
91
+ bootstrap_ip_address = machine_options[:driver_options][:ip_address]
92
+ username = machine_options[:transport_options][:user] || 'root' rescue 'root'
93
+ default_ssh_options = {
94
+ # auth_methods: ['publickey'],
95
+ # keys: ['/home/username/.vagrant.d/insecure_private_key'],
96
+ password: Chef::Config.knife[:node_root_password]
97
+ }
98
+ ssh_options = machine_options[:transport_options][:ssh_options] || default_ssh_options rescue default_ssh_options
99
+ default_options = {
100
+ prefix: 'sudo ',
101
+ ssh_pty_enable: true
102
+ }
103
+ options = machine_options[:transport_options][:options] || default_options rescue default_options
104
+
105
+ transport = Chef::Provisioning::Transport::SSH.new(bootstrap_ip_address, username, ssh_options, options, config)
106
+ convergence_strategy = Chef::Provisioning::ConvergenceStrategy::InstallSh.new(
107
+ machine_options[:convergence_options], {})
108
+ Chef::Provisioning::Machine::UnixMachine.new(machine_spec, transport, convergence_strategy)
109
+ end
110
+
111
+
112
+ def stop_machine(action_handler, machine_spec, _machine_options)
113
+ power_off(action_handler, machine_spec) if machine_spec.reference
114
+ end
115
+
116
+
117
+ def destroy_machine(action_handler, machine_spec, machine_options)
118
+ if machine_spec.reference
119
+ power_off(action_handler, machine_spec) # Power off server
120
+ destroy_icsp_server(action_handler, machine_spec) # Delete os deployment server from ICSP
121
+ destroy_oneview_profile(action_handler, machine_spec) # Delete server profile from OneView
122
+
123
+ name = machine_spec.name # Save for next steps
124
+
125
+ # Delete the node from the Chef server
126
+ action_handler.perform_action "Release machine #{machine_spec.reference['serial_number']}" do
127
+ machine_spec.reference = nil
128
+ machine_spec.delete(action_handler)
129
+ end
130
+
131
+ # Delete client from the Chef server
132
+ action_handler.perform_action "Delete client '#{name}' from Chef server" do
133
+ begin
134
+ ridley = Ridley.new(
135
+ server_url: machine_options[:convergence_options][:chef_server][:chef_server_url],
136
+ client_name: machine_options[:convergence_options][:chef_server][:options][:client_name],
137
+ client_key: machine_options[:convergence_options][:chef_server][:options][:signing_key_filename]
138
+ )
139
+ ridley.client.delete(name)
140
+ rescue Exception => e
141
+ action_handler.report_progress "WARN: Failed to delete client #{name} from server!"
142
+ puts "Error: #{e.message}"
143
+ end
144
+ end
145
+
146
+ # Remove entry from known_hosts file(s)
147
+ if machine_options[:driver_options][:ip_address]
148
+ action_handler.perform_action "Delete entry for '#{machine_options[:driver_options][:ip_address]}' from known_hosts file(s)" do
149
+ files = [File.expand_path('~/.ssh/known_hosts'), File.expand_path('/etc/ssh/known_hosts')]
150
+ files.each do |f|
151
+ next if !File.exist?(f)
152
+ begin
153
+ text = File.read(f)
154
+ text.gsub!(/#{machine_options[:driver_options][:ip_address]} ssh-rsa.*(\n|\r\n)/, '')
155
+ File.open(f, 'w') {|file| file.puts text } if text
156
+ rescue Exception => e
157
+ action_handler.report_progress "WARN: Failed to delete entry for '#{machine_options[:driver_options][:ip_address]}' from known_hosts file: '#{f}'! "
158
+ puts "Error: #{e.message}"
159
+ end
160
+ end
161
+ end
162
+ end
163
+
164
+ end # End if machine_spec.reference
165
+ end # destroy_machine method end
166
+
167
+
168
+ def connect_to_machine(machine_spec, machine_options)
169
+ machine_for(machine_spec, machine_options)
170
+ end
171
+
172
+ end # class end
173
+ end # module end
@@ -0,0 +1,21 @@
1
+ require 'pry'
2
+ require_relative './../lib/chef/provisioning/driver_init/oneview'
3
+ require_relative 'support/fake_oneview'
4
+ require_relative 'support/fake_icsp'
5
+ require 'webmock/rspec'
6
+ # WebMock.disable_net_connect!(allow_localhost: true)
7
+
8
+ RSpec.configure do |config|
9
+ 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
+ stub_request(:any, /my-oneview.my-domain.com/).to_rack(FakeOneView)
16
+ stub_request(:any, /my-icsp.my-domain.com/).to_rack(FakeIcsp)
17
+ end
18
+ end
19
+
20
+ # Chef::Log.level = :debug
21
+ Chef::Config[:log_level] = :warn
@@ -0,0 +1,21 @@
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
@@ -0,0 +1,21 @@
1
+ require 'sinatra/base'
2
+
3
+ class FakeOneView < 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 = 120)
17
+ content_type :json
18
+ status response_code
19
+ File.open(File.dirname(__FILE__) + "/fixtures/oneview/v#{version.gsub('.', '')}/" + file_name, 'rb').read
20
+ end
21
+ end
@@ -0,0 +1,14 @@
1
+ {
2
+ "errorSource": null,
3
+ "nestedErrors": [
4
+
5
+ ],
6
+ "errorCode": "GENERIC_HTTP_404",
7
+ "data": {
8
+ },
9
+ "recommendedActions": [
10
+ "Check the request URI, then resend the request."
11
+ ],
12
+ "details": "The requested resource could not be found.",
13
+ "message": "Not Found"
14
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "partnerData": {
3
+ },
4
+ "sessionID": "AA_aaAaa3AA3Aa0_aAaAA4AAAA3AAAAA"
5
+ }
@@ -0,0 +1,99 @@
1
+ {
2
+ "type": "OsdPaginatedCollection",
3
+ "members": [
4
+ {
5
+ "modifiedBy": "applianceserviceaccount",
6
+ "createdBy": "applianceserviceaccount",
7
+ "buildPlanHistory": [],
8
+ "buildPlanStepType": null,
9
+ "isCustomerContent": true,
10
+ "buildPlanCustAttrs": [],
11
+ "buildPlanItems": [],
12
+ "os": "OS - Red Hat Enterprise Linux Server 6",
13
+ "arch": "x64",
14
+ "lifeCycle": "AVAILABLE",
15
+ "description": "Performs a scripted install of Red Hat Enterprise Linux 6.5 using a generic kickstart file.\n(c) Copyright 2014 Hewlett-Packard Development Company, L.P.\n\nRequirements:\n* HP ProLiant server with iLO\n* IC server provisioning Media Server must contain the OS distribution\n\nRequired Custom Attribute: None\n\nOptional Custom Attributes:\n* encrypted_root_password (must be encrypted)\n* boot_disk\n* kernel_arguments",
16
+ "status": "",
17
+ "name": "CHEF-RHEL-6.5-x64",
18
+ "state": "",
19
+ "modified": "2015-07-14T03:51:30.000Z",
20
+ "eTag": "2015-07-14T03:51:30.000Z",
21
+ "created": "2015-05-19T19:05:37.000Z",
22
+ "category": "os-deployment-build-plans",
23
+ "uri": "/rest/os-deployment-build-plans/1280001"
24
+ },
25
+ {
26
+ "modifiedBy": "applianceserviceaccount",
27
+ "createdBy": "applianceserviceaccount",
28
+ "buildPlanHistory": [],
29
+ "buildPlanStepType": null,
30
+ "isCustomerContent": true,
31
+ "buildPlanCustAttrs": [],
32
+ "buildPlanItems": [],
33
+ "os": "Other",
34
+ "arch": "x64",
35
+ "lifeCycle": "AVAILABLE",
36
+ "description": "Reboots a target server in maintenance mode to the local disk. \n(c) Copyright 2013 Hewlett-Packard Development Company, L.P.\n\nRequirements:\n* HP ProLiant server with iLO\n\nCustom Attributes: None",
37
+ "status": "",
38
+ "name": "CHEF - RHEL 6.6 x64",
39
+ "state": "",
40
+ "modified": "2015-05-21T17:23:58.000Z",
41
+ "eTag": "2015-05-21T17:23:58.000Z",
42
+ "created": "2015-05-21T17:23:58.000Z",
43
+ "category": "os-deployment-build-plans",
44
+ "uri": "/rest/os-deployment-build-plans/1300001"
45
+ },
46
+ {
47
+ "modifiedBy": "applianceserviceaccount",
48
+ "createdBy": "applianceserviceaccount",
49
+ "buildPlanHistory": [],
50
+ "buildPlanStepType": null,
51
+ "isCustomerContent": true,
52
+ "buildPlanCustAttrs": [],
53
+ "buildPlanItems": [],
54
+ "os": "OS - Red Hat Enterprise Linux Server 7",
55
+ "arch": "x64",
56
+ "lifeCycle": "AVAILABLE",
57
+ "description": "Performs a scripted install of Red Hat Enterprise Linux 7.0 using a generic kickstart file.\n(c) Copyright 2014 Hewlett-Packard Development Company, L.P.\n\nRequirements:\n* HP ProLiant server with iLO\n* IC server provisioning Media Server must contain the OS distribution\n\nRequired Custom Attribute: None\n\nOptional Custom Attributes:\n* encrypted_root_password (must be encrypted)\n* boot_disk\n* kernel_arguments",
58
+ "status": "",
59
+ "name": "CHEF - RHEL 7.0 x64",
60
+ "state": "",
61
+ "modified": "2015-07-24T09:32:52.000Z",
62
+ "eTag": "2015-07-24T09:32:52.000Z",
63
+ "created": "2015-07-15T17:46:32.000Z",
64
+ "category": "os-deployment-build-plans",
65
+ "uri": "/rest/os-deployment-build-plans/1340001"
66
+ },
67
+ {
68
+ "modifiedBy": "detuser",
69
+ "createdBy": "opsware",
70
+ "buildPlanHistory": [],
71
+ "buildPlanStepType": null,
72
+ "isCustomerContent": false,
73
+ "buildPlanCustAttrs": [],
74
+ "buildPlanItems": [],
75
+ "os": "OS - Windows Server 2008 R2",
76
+ "arch": "x64",
77
+ "lifeCycle": "AVAILABLE",
78
+ "description": "Performs a scripted install of Windows 2008 R2 SP1 Standard using a generic unattend file.\n(c) Copyright 2013, 2014 Hewlett-Packard Development Company, L.P.\n\nRequirements:\n* HP ProLiant server with iLO\n* IC server provisioning Media Server must contain the OS distribution\n\nRequired Custom Attribute:\n* ProductKey_Win2008R2-Std-x64 - Set using the Settings -> Product Key page.\n\nOptional Custom Attributes:\n* ComputerName\n* EncryptedAdminPassword (must be encrypted)\n* SystemDisk\n* SystemDiskNumber",
79
+ "status": "",
80
+ "name": "ProLiant OS - Windows 2008 R2 SP1 Standard x64 Scripted Install",
81
+ "state": "",
82
+ "modified": "2014-09-15T02:30:17.000Z",
83
+ "eTag": "2014-09-15T02:30:17.000Z",
84
+ "created": "2014-09-15T02:30:17.000Z",
85
+ "category": "os-deployment-build-plans",
86
+ "uri": "/rest/os-deployment-build-plans/1040001"
87
+ }
88
+ ],
89
+ "start": 0,
90
+ "prevPageUri": null,
91
+ "nextPageUri": null,
92
+ "total": 0,
93
+ "count": 71,
94
+ "modified": null,
95
+ "eTag": null,
96
+ "created": null,
97
+ "category": null,
98
+ "uri": null
99
+ }
@@ -0,0 +1,179 @@
1
+ {
2
+ "type": "OsdPaginatedCollection",
3
+ "members": [
4
+ {
5
+ "modified": "2015-08-10T16:45:57.019Z",
6
+ "deviceGroups": null,
7
+ "customAttributes": [],
8
+ "created": "2015-08-10T04:35:52.000Z",
9
+ "uuid": "2b4e5e6c-6154-7849-9807-c96a7e0d445b",
10
+ "cpus": [
11
+ {
12
+ "cacheSize": "15360",
13
+ "speed": "1200",
14
+ "stepping": "7",
15
+ "model": "Intel(R) Xeon(R) CPU E5-2620 0 @ 2.00GHz",
16
+ "family": "X64",
17
+ "status": "ON-LINE",
18
+ "slot": "0"
19
+ }
20
+ ],
21
+ "ilo": null,
22
+ "serverLocation": {
23
+ "rack": "DemoRack",
24
+ "enclosure": "dazzle",
25
+ "bay": "3"
26
+ },
27
+ "operatingSystemVersion": null,
28
+ "opswLifecycle": "MANAGED",
29
+ "osSPVersion": null,
30
+ "peerIP": "192.168.133.41",
31
+ "stage": "UNKNOWN",
32
+ "running": "false",
33
+ "reporting": true,
34
+ "storageDevices": [],
35
+ "ram": "16291780",
36
+ "swap": "8216568",
37
+ "architecture": null,
38
+ "defaultGateway": "16.125.32.1",
39
+ "discoveredDate": "2015-08-10T04:35:52.000Z",
40
+ "facility": "Appliance",
41
+ "hardwareModel": "PROLIANT BL460C GEN8",
42
+ "jobsHistory": null,
43
+ "lastScannedDate": null,
44
+ "loopbackIP": null,
45
+ "managementIP": "192.168.133.41",
46
+ "manufacturer": "HP",
47
+ "mid": "1680001",
48
+ "netBios": null,
49
+ "operatingSystem": null,
50
+ "osFlavor": null,
51
+ "serialNumber": "VCGE9KB042",
52
+ "locale": null,
53
+ "description": null,
54
+ "status": "OK",
55
+ "uri": "/rest/os-deployment-servers/1680001",
56
+ "name": "chef-web02.domain.com",
57
+ "interfaces": [
58
+ {
59
+ "speed": "10000",
60
+ "netmask": "255.255.254.0",
61
+ "duplex": "FULL",
62
+ "ipv6Addr": "",
63
+ "macAddr": "AE:B2:F8:20:01:17",
64
+ "dhcpEnabled": false,
65
+ "ipv4Addr": "16.125.32.39",
66
+ "type": "ETHERNET",
67
+ "slot": "eth1"
68
+ },
69
+ {
70
+ "speed": "10000",
71
+ "netmask": "255.255.255.0",
72
+ "duplex": "FULL",
73
+ "ipv6Addr": "",
74
+ "macAddr": "AE:B2:F8:20:01:16",
75
+ "dhcpEnabled": true,
76
+ "ipv4Addr": "192.168.133.41",
77
+ "type": "ETHERNET",
78
+ "slot": "eth0"
79
+ }
80
+ ],
81
+ "state": "OK",
82
+ "hostName": "chef-web02.domain.com",
83
+ "eTag": "2015-08-10T16:45:57.019Z",
84
+ "category": "os-deployment-servers"
85
+ },
86
+ {
87
+ "modified": "2015-08-10T04:55:27.017Z",
88
+ "deviceGroups": null,
89
+ "customAttributes": [],
90
+ "created": "2015-08-10T04:35:40.000Z",
91
+ "uuid": "7d805e1c-beac-e84e-868b-2fb0b6504474",
92
+ "cpus": [
93
+ {
94
+ "cacheSize": "15360",
95
+ "speed": "1200",
96
+ "stepping": "7",
97
+ "model": "Intel(R) Xeon(R) CPU E5-2620 0 @ 2.00GHz",
98
+ "family": "X64",
99
+ "status": "ON-LINE",
100
+ "slot": "0"
101
+ }
102
+ ],
103
+ "ilo": null,
104
+ "serverLocation": {
105
+ "rack": "DemoRack",
106
+ "enclosure": "dazzle",
107
+ "bay": "2"
108
+ },
109
+ "operatingSystemVersion": null,
110
+ "opswLifecycle": "MANAGED",
111
+ "osSPVersion": null,
112
+ "peerIP": "192.168.133.36",
113
+ "stage": "UNKNOWN",
114
+ "running": "false",
115
+ "reporting": true,
116
+ "storageDevices": [],
117
+ "ram": "16291780",
118
+ "swap": "8216568",
119
+ "architecture": null,
120
+ "defaultGateway": "16.125.32.1",
121
+ "discoveredDate": "2015-08-10T04:35:39.000Z",
122
+ "facility": "Appliance",
123
+ "hardwareModel": "PROLIANT BL460C GEN8",
124
+ "jobsHistory": null,
125
+ "lastScannedDate": null,
126
+ "loopbackIP": null,
127
+ "managementIP": "192.168.133.36",
128
+ "manufacturer": "HP",
129
+ "mid": "1670001",
130
+ "netBios": null,
131
+ "operatingSystem": null,
132
+ "osFlavor": null,
133
+ "serialNumber": "VCGE9KB041",
134
+ "locale": null,
135
+ "description": null,
136
+ "status": "OK",
137
+ "uri": "/rest/os-deployment-servers/1670001",
138
+ "name": "chef-web01.domain.com",
139
+ "interfaces": [
140
+ {
141
+ "speed": "10000",
142
+ "netmask": "255.255.254.0",
143
+ "duplex": "FULL",
144
+ "ipv6Addr": "",
145
+ "macAddr": "AE:B2:F8:20:01:15",
146
+ "dhcpEnabled": false,
147
+ "ipv4Addr": "16.125.32.38",
148
+ "type": "ETHERNET",
149
+ "slot": "eth1"
150
+ },
151
+ {
152
+ "speed": "10000",
153
+ "netmask": "255.255.255.0",
154
+ "duplex": "FULL",
155
+ "ipv6Addr": "",
156
+ "macAddr": "AE:B2:F8:20:01:14",
157
+ "dhcpEnabled": true,
158
+ "ipv4Addr": "192.168.133.36",
159
+ "type": "ETHERNET",
160
+ "slot": "eth0"
161
+ }
162
+ ],
163
+ "state": "OK",
164
+ "hostName": "chef-web01.domain.com",
165
+ "eTag": "2015-08-10T04:55:27.017Z",
166
+ "category": "os-deployment-servers"
167
+ }
168
+ ],
169
+ "start": 0,
170
+ "prevPageUri": null,
171
+ "nextPageUri": null,
172
+ "total": 2,
173
+ "count": 2,
174
+ "modified": null,
175
+ "eTag": null,
176
+ "created": null,
177
+ "category": null,
178
+ "uri": null
179
+ }