restfully 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -9,7 +9,7 @@ module Restfully
9
9
  content_type = options[:content_type]
10
10
  content_type ||= object.headers['Content-Type'] if object.respond_to?(:headers)
11
11
  case content_type
12
- when /^application\/json/i
12
+ when /^application\/.*?json/i
13
13
  JSON.parse(object)
14
14
  else
15
15
  raise ParserNotFound.new("Content-Type '#{content_type}' is not supported. Cannot parse the given object.")
@@ -20,7 +20,7 @@ module Restfully
20
20
  content_type = options[:content_type]
21
21
  content_type ||= object.headers['Content-Type'] if object.respond_to?(:headers)
22
22
  case content_type
23
- when /^application\/json/i
23
+ when /^application\/.*?json/i
24
24
  JSON.dump(object)
25
25
  else
26
26
  raise ParserNotFound, [object, content_type]
@@ -7,13 +7,12 @@ module Restfully
7
7
  class Resource < DelegateClass(Hash)
8
8
 
9
9
  undef :type if self.respond_to? :type
10
- attr_reader :uri, :session, :state, :raw, :uid, :associations, :type
10
+ attr_reader :uri, :session, :state, :raw, :associations, :uid, :type
11
11
 
12
12
  def initialize(uri, session, options = {})
13
13
  options = options.symbolize_keys
14
14
  @uri = uri
15
15
  @session = session
16
- @raw = options[:raw]
17
16
  @state = :unloaded
18
17
  @attributes = {}
19
18
  super(@attributes)
@@ -34,11 +33,12 @@ module Restfully
34
33
  def load(options = {})
35
34
  options = options.symbolize_keys
36
35
  force_reload = !!options.delete(:reload) || options.has_key?(:query)
37
- if loaded? && !force_reload
36
+ if loaded? && !force_reload && options[:raw].nil?
38
37
  self
39
38
  else
40
39
  @associations.clear
41
40
  @attributes.clear
41
+ @raw = options[:raw]
42
42
  if raw.nil? || force_reload
43
43
  response = session.get(uri, options)
44
44
  @raw = response.body
@@ -46,9 +46,9 @@ module Restfully
46
46
  (raw['links'] || []).each{|link| define_link(Link.new(link))}
47
47
  raw.each do |key, value|
48
48
  case key
49
+ when "uid", "type"
50
+ instance_variable_set "@#{key}".to_sym, value
49
51
  when 'links' then next
50
- when 'uid' then @uid = value
51
- when 'type' then @type = value
52
52
  else
53
53
  case value
54
54
  when Hash
@@ -9,16 +9,21 @@ module Restfully
9
9
  end
10
10
  end
11
11
  class Session
12
- include Parsing
12
+ include Parsing, HTTP::Headers
13
13
  attr_reader :base_uri, :root_path, :logger, :connection, :root, :default_headers
14
14
 
15
15
  # TODO: use CacheableResource
16
- def initialize(base_uri, options = {})
16
+ def initialize(options = {})
17
17
  options = options.symbolize_keys
18
- @base_uri = base_uri
19
- @root_path = options.delete(:root_path) || '/'
20
- @logger = options.delete(:logger) || NullLogger.new
21
- @default_headers = options.delete(:default_headers) || {'Accept' => 'application/json'}
18
+ if (config_filename = options.delete(:configuration_file)) && File.exists?(File.expand_path(config_filename))
19
+ config = YAML.load_file(File.expand_path(config_filename)).symbolize_keys
20
+ options.merge!(config)
21
+ end
22
+ @base_uri = options.delete(:base_uri) || "http://localhost:8888"
23
+ @root_path = options.delete(:root_path) || "/"
24
+ @logger = options.delete(:logger) || NullLogger.new
25
+ user_default_headers = sanitize_http_headers(options.delete(:default_headers) || {})
26
+ @default_headers = {'User-Agent' => "Restfully/#{Restfully::VERSION}", 'Accept' => 'application/json'}.merge(user_default_headers)
22
27
  @connection = Restfully.adapter.new(@base_uri, options.merge(:logger => @logger))
23
28
  @root = Resource.new(URI.parse(@root_path), self)
24
29
  yield @root.load, self if block_given?
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{restfully}
8
- s.version = "0.2.3"
8
+ s.version = "0.3.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Cyril Rohr"]
12
- s.date = %q{2009-10-05}
12
+ s.date = %q{2009-10-26}
13
13
  s.default_executable = %q{restfully}
14
14
  s.description = %q{Experimental code for auto-generation of wrappers on top of RESTful APIs that follow HATEOAS principles and provide OPTIONS methods and/or Allow headers.}
15
15
  s.email = %q{cyril.rohr@gmail.com}
@@ -61,12 +61,11 @@ Gem::Specification.new do |s|
61
61
  "spec/session_spec.rb",
62
62
  "spec/spec_helper.rb"
63
63
  ]
64
- s.has_rdoc = true
65
64
  s.homepage = %q{http://github.com/crohr/restfully}
66
65
  s.rdoc_options = ["--charset=UTF-8"]
67
66
  s.require_paths = ["lib"]
68
67
  s.rubyforge_project = %q{restfully}
69
- s.rubygems_version = %q{1.3.2}
68
+ s.rubygems_version = %q{1.3.5}
70
69
  s.summary = %q{Experimental code for auto-generation of wrappers on top of RESTful APIs that follow some specific conventions.}
71
70
  s.test_files = [
72
71
  "spec/collection_spec.rb",
@@ -1,21 +1,24 @@
1
- require File.dirname(__FILE__)+'/spec_helper'
1
+ require File.expand_path(File.dirname(__FILE__)+'/spec_helper')
2
2
 
3
3
  include Restfully
4
4
  describe Collection do
5
-
6
- it "should have all methods of a hash" do
7
- collection = Collection.new("uri", session=mock('session'))
8
- collection.size.should == 0
9
- collection.store("rennes", resource = mock(Resource))
10
- collection.size.should == 1
11
- collection.should == {'rennes' => resource}
12
- collection.should respond_to(:each)
13
- collection.should respond_to(:store)
14
- collection.should respond_to(:[])
15
- collection.should respond_to(:length)
16
- end
5
+ describe "general behaviour" do
6
+ before do
7
+ @collection = Collection.new("uri", session=mock('session')).load(:raw => JSON.parse(fixture("grid5000-sites.json")))
8
+ end
9
+ it "should be enumerable" do
10
+ @collection.length.should == 9
11
+ @collection.map{|site| site.uid}.sort.should == ["bordeaux", "grenoble", "lille", "lyon", "nancy", "orsay", "rennes", "sophia", "toulouse"]
12
+ end
17
13
 
14
+ it "should have a :total method" do
15
+ @collection.total.should == 9
16
+ end
18
17
 
18
+ it "should have a :offset method" do
19
+ @collection.offset.should == 0
20
+ end
21
+ end
19
22
 
20
23
  describe "loading" do
21
24
  before(:all) do
@@ -47,46 +50,48 @@ describe Collection do
47
50
  end
48
51
  it "should not initialize resources lacking a self link" do
49
52
  collection = Collection.new("uri", session = mock("session", :get => mock("restfully response", :body => {
50
- 'rennes' => {
51
- 'links' => [
52
- {'rel' => 'collection', 'href' => '/grid5000/sites/rennes/versions', 'resolvable' => false, 'title' => 'versions'}
53
- ],
54
- 'uid' => 'rennes'
55
- }
53
+ "total" => 1,
54
+ "offset" => 0,
55
+ "items" => [
56
+ {
57
+ 'links' => [
58
+ {'rel' => 'collection', 'href' => '/grid5000/sites/rennes/versions', 'resolvable' => false, 'title' => 'versions'}
59
+ ],
60
+ 'uid' => 'rennes'
61
+ }
62
+ ]
56
63
  }), :logger => @logger))
57
64
  Resource.should_not_receive(:new)
58
65
  collection.load
59
- collection['rennes'].should be_nil
66
+ collection.by_uid('rennes').should be_nil
60
67
  end
61
68
  it "should initialize resources having a self link" do
62
69
  collection = Collection.new("uri", session = mock("session", :get => mock("restfully response", :body => {
63
- 'rennes' => {
64
- 'links' => [
65
- {'rel' => 'self', 'href' => '/grid5000/sites/rennes'},
66
- {'rel' => 'collection', 'href' => '/grid5000/sites/rennes/versions', 'resolvable' => false, 'title' => 'versions'}
67
- ],
68
- 'uid' => 'rennes'
69
- }
70
+ "total" => 1,
71
+ "offset" => 0,
72
+ "items" => [
73
+ {
74
+ 'links' => [
75
+ {'rel' => 'self', 'href' => '/grid5000/sites/rennes'},
76
+ {'rel' => 'collection', 'href' => '/grid5000/sites/rennes/versions', 'title' => 'versions'}
77
+ ],
78
+ 'uid' => 'rennes'
79
+ }
80
+ ]
70
81
  }), :logger => @logger))
71
- Resource.should_receive(:new).with('/grid5000/sites/rennes', session, :raw => {
72
- 'links' => [
73
- {'rel' => 'self', 'href' => '/grid5000/sites/rennes'},
74
- {'rel' => 'collection', 'href' => '/grid5000/sites/rennes/versions', 'resolvable' => false, 'title' => 'versions'}
75
- ],
76
- 'uid' => 'rennes'
77
- }).and_return(resource=mock("restfully resource"))
78
- resource.should_receive(:load).and_return(resource)
79
82
  collection.load
80
- collection['rennes'].should == resource
83
+ collection.length.should == 1
84
+ collection.by_uid('rennes').class.should == Restfully::Resource
81
85
  end
82
86
  it "should correctly initialize its resources [integration test]" do
83
87
  collection = Collection.new("uri", session=mock("session", :logger => Logger.new(STDOUT), :get => @response_200))
84
88
  collection.load
85
89
  collection.should be_loaded
86
90
  collection.uri.should == "uri"
87
- collection['rennes'].uid.should == 'rennes'
88
- collection['rennes'].type.should == 'site'
89
- collection.keys.should =~ ['rennes', 'lille', 'bordeaux', 'nancy', 'sophia', 'toulouse', 'lyon', 'grenoble', 'orsay']
91
+ collection.by_uid('rennes').uid.should == 'rennes'
92
+ collection.by_uid('rennes').type.should == 'site'
93
+ collection.by_uid.keys.should =~ ['rennes', 'lille', 'bordeaux', 'nancy', 'sophia', 'toulouse', 'lyon', 'grenoble', 'orsay']
94
+ collection.by_uid('rennes', 'bordeaux').length.should == 2
90
95
  end
91
96
  end
92
97
 
@@ -1,489 +1,540 @@
1
1
  {
2
- "lille": {
3
- "name": "Lille",
4
- "latitude": 50.65,
5
- "location": "Lille, France",
6
- "security_contact": null,
7
- "uid": "lille",
8
- "type": "site",
9
- "user_support_contact": null,
10
- "version": "747d2af24c5f3c2578a96626e0b00413c8484f04",
11
- "links": [
12
- {
13
- "href": "\/grid5000\/sites\/lille",
14
- "rel": "self"
15
- },
16
- {
17
- "href": "\/grid5000\/sites\/lille\/versions\/747d2af24c5f3c2578a96626e0b00413c8484f04",
18
- "title": "version",
19
- "rel": "member"
20
- },
21
- {
22
- "href": "\/grid5000\/sites\/lille\/versions",
23
- "title": "versions",
24
- "rel": "collection"
25
- },
26
- {
27
- "href": "\/grid5000\/sites\/lille\/clusters",
28
- "resolvable": true,
29
- "title": "clusters",
30
- "rel": "collection",
31
- "resolved": false
32
- },
33
- {
34
- "href": "\/grid5000\/sites\/lille\/environments",
35
- "resolvable": true,
36
- "title": "environments",
37
- "rel": "collection",
38
- "resolved": false
39
- },
40
- {
41
- "href": "\/grid5000",
42
- "rel": "parent"
43
- },
44
- {
45
- "href": "\/grid5000\/sites\/lille\/status",
46
- "title": "status",
47
- "rel": "collection"
48
- }
49
- ],
50
- "description": "",
51
- "longitude": 3.0833,
52
- "email_contact": null,
53
- "web": null,
54
- "sys_admin_contact": null
55
- },
56
- "grenoble": {
57
- "name": "Grenoble",
58
- "latitude": 45.1833,
59
- "location": "Grenoble, France",
60
- "security_contact": null,
61
- "uid": "grenoble",
62
- "type": "site",
63
- "user_support_contact": null,
64
- "version": "747d2af24c5f3c2578a96626e0b00413c8484f04",
65
- "links": [
66
- {
67
- "href": "\/grid5000\/sites\/grenoble",
68
- "rel": "self"
69
- },
70
- {
71
- "href": "\/grid5000\/sites\/grenoble\/versions\/747d2af24c5f3c2578a96626e0b00413c8484f04",
72
- "title": "version",
73
- "rel": "member"
74
- },
75
- {
76
- "href": "\/grid5000\/sites\/grenoble\/versions",
77
- "title": "versions",
78
- "rel": "collection"
79
- },
80
- {
81
- "href": "\/grid5000\/sites\/grenoble\/clusters",
82
- "resolvable": true,
83
- "title": "clusters",
84
- "rel": "collection",
85
- "resolved": false
86
- },
87
- {
88
- "href": "\/grid5000\/sites\/grenoble\/environments",
89
- "resolvable": true,
90
- "title": "environments",
91
- "rel": "collection",
92
- "resolved": false
93
- },
94
- {
95
- "href": "\/grid5000",
96
- "rel": "parent"
97
- },
98
- {
99
- "href": "\/grid5000\/sites\/grenoble\/status",
100
- "title": "status",
101
- "rel": "collection"
102
- }
103
- ],
104
- "description": "",
105
- "longitude": 5.7167,
106
- "email_contact": null,
107
- "web": null,
108
- "sys_admin_contact": null
109
- },
110
- "toulouse": {
111
- "name": "Toulouse",
112
- "latitude": 43.6167,
113
- "location": "Toulouse, France",
114
- "security_contact": null,
115
- "uid": "toulouse",
116
- "type": "site",
117
- "user_support_contact": null,
118
- "version": "747d2af24c5f3c2578a96626e0b00413c8484f04",
119
- "links": [
120
- {
121
- "href": "\/grid5000\/sites\/toulouse",
122
- "rel": "self"
123
- },
124
- {
125
- "href": "\/grid5000\/sites\/toulouse\/versions\/747d2af24c5f3c2578a96626e0b00413c8484f04",
126
- "title": "version",
127
- "rel": "member"
128
- },
129
- {
130
- "href": "\/grid5000\/sites\/toulouse\/versions",
131
- "title": "versions",
132
- "rel": "collection"
133
- },
134
- {
135
- "href": "\/grid5000\/sites\/toulouse\/clusters",
136
- "resolvable": true,
137
- "title": "clusters",
138
- "rel": "collection",
139
- "resolved": false
140
- },
141
- {
142
- "href": "\/grid5000\/sites\/toulouse\/environments",
143
- "resolvable": true,
144
- "title": "environments",
145
- "rel": "collection",
146
- "resolved": false
147
- },
148
- {
149
- "href": "\/grid5000",
150
- "rel": "parent"
151
- },
152
- {
153
- "href": "\/grid5000\/sites\/toulouse\/status",
154
- "title": "status",
155
- "rel": "collection"
156
- }
157
- ],
158
- "description": "",
159
- "longitude": 1.4333,
160
- "email_contact": null,
161
- "web": null,
162
- "sys_admin_contact": null
163
- },
164
- "sophia": {
165
- "name": "Sophia-Antipolis",
166
- "latitude": 43.6161,
167
- "location": "Sophia-Antipolis, France",
168
- "security_contact": "sophia-staff@lists.grid5000.fr",
169
- "uid": "sophia",
170
- "type": "site",
171
- "user_support_contact": "sophia-staff@lists.grid5000.fr",
172
- "version": "747d2af24c5f3c2578a96626e0b00413c8484f04",
173
- "links": [
174
- {
175
- "href": "\/grid5000\/sites\/sophia",
176
- "rel": "self"
177
- },
178
- {
179
- "href": "\/grid5000\/sites\/sophia\/versions\/747d2af24c5f3c2578a96626e0b00413c8484f04",
180
- "title": "version",
181
- "rel": "member"
182
- },
183
- {
184
- "href": "\/grid5000\/sites\/sophia\/versions",
185
- "title": "versions",
186
- "rel": "collection"
187
- },
188
- {
189
- "href": "\/grid5000\/sites\/sophia\/clusters",
190
- "resolvable": true,
191
- "title": "clusters",
192
- "rel": "collection",
193
- "resolved": false
194
- },
195
- {
196
- "href": "\/grid5000\/sites\/sophia\/environments",
197
- "resolvable": true,
198
- "title": "environments",
199
- "rel": "collection",
200
- "resolved": false
201
- },
202
- {
203
- "href": "\/grid5000",
204
- "rel": "parent"
205
- },
206
- {
207
- "href": "\/grid5000\/sites\/sophia\/status",
208
- "title": "status",
209
- "rel": "collection"
210
- }
211
- ],
212
- "description": "",
213
- "longitude": 7.0678,
214
- "compilation_server": true,
215
- "email_contact": "sophia-staff@lists.grid5000.fr",
216
- "web": null,
217
- "sys_admin_contact": "sophia-staff@lists.grid5000.fr"
218
- },
219
- "rennes": {
220
- "name": "Rennes",
221
- "latitude": 48.1,
222
- "location": "Rennes, France",
223
- "security_contact": "rennes-staff@lists.grid5000.fr",
224
- "uid": "rennes",
225
- "type": "site",
226
- "user_support_contact": "rennes-staff@lists.grid5000.fr",
227
- "version": "747d2af24c5f3c2578a96626e0b00413c8484f04",
228
- "links": [
229
- {
230
- "href": "\/grid5000\/sites\/rennes",
231
- "rel": "self"
232
- },
233
- {
234
- "href": "\/grid5000\/sites\/rennes\/versions\/747d2af24c5f3c2578a96626e0b00413c8484f04",
235
- "title": "version",
236
- "rel": "member"
237
- },
238
- {
239
- "href": "\/grid5000\/sites\/rennes\/versions",
240
- "title": "versions",
241
- "rel": "collection"
242
- },
243
- {
244
- "href": "\/grid5000\/sites\/rennes\/clusters",
245
- "resolvable": true,
246
- "title": "clusters",
247
- "rel": "collection",
248
- "resolved": false
249
- },
250
- {
251
- "href": "\/grid5000\/sites\/rennes\/environments",
252
- "resolvable": true,
253
- "title": "environments",
254
- "rel": "collection",
255
- "resolved": false
256
- },
257
- {
258
- "href": "\/grid5000",
259
- "rel": "parent"
260
- },
261
- {
262
- "href": "\/grid5000\/sites\/rennes\/status",
263
- "title": "status",
264
- "rel": "collection"
265
- }
266
- ],
267
- "description": "",
268
- "longitude": -1.6667,
269
- "compilation_server": false,
270
- "email_contact": "rennes-staff@lists.grid5000.fr",
271
- "web": "http:\/\/www.irisa.fr",
272
- "sys_admin_contact": "rennes-staff@lists.grid5000.fr"
273
- },
274
- "lyon": {
275
- "name": "Lyon",
276
- "latitude": 45.7667,
277
- "location": "Lyon, France",
278
- "security_contact": null,
279
- "uid": "lyon",
280
- "type": "site",
281
- "user_support_contact": null,
282
- "version": "747d2af24c5f3c2578a96626e0b00413c8484f04",
283
- "links": [
284
- {
285
- "href": "\/grid5000\/sites\/lyon",
286
- "rel": "self"
287
- },
288
- {
289
- "href": "\/grid5000\/sites\/lyon\/versions\/747d2af24c5f3c2578a96626e0b00413c8484f04",
290
- "title": "version",
291
- "rel": "member"
292
- },
293
- {
294
- "href": "\/grid5000\/sites\/lyon\/versions",
295
- "title": "versions",
296
- "rel": "collection"
297
- },
298
- {
299
- "href": "\/grid5000\/sites\/lyon\/clusters",
300
- "resolvable": true,
301
- "title": "clusters",
302
- "rel": "collection",
303
- "resolved": false
304
- },
305
- {
306
- "href": "\/grid5000\/sites\/lyon\/environments",
307
- "resolvable": true,
308
- "title": "environments",
309
- "rel": "collection",
310
- "resolved": false
311
- },
312
- {
313
- "href": "\/grid5000",
314
- "rel": "parent"
315
- },
316
- {
317
- "href": "\/grid5000\/sites\/lyon\/status",
318
- "title": "status",
319
- "rel": "collection"
320
- }
321
- ],
322
- "description": "",
323
- "longitude": 4.8333,
324
- "email_contact": null,
325
- "web": null,
326
- "sys_admin_contact": null
327
- },
328
- "nancy": {
329
- "name": "Nancy",
330
- "latitude": 48.7,
331
- "location": "Nancy, France",
332
- "security_contact": null,
333
- "uid": "nancy",
334
- "type": "site",
335
- "user_support_contact": null,
336
- "version": "747d2af24c5f3c2578a96626e0b00413c8484f04",
337
- "links": [
338
- {
339
- "href": "\/grid5000\/sites\/nancy",
340
- "rel": "self"
341
- },
342
- {
343
- "href": "\/grid5000\/sites\/nancy\/versions\/747d2af24c5f3c2578a96626e0b00413c8484f04",
344
- "title": "version",
345
- "rel": "member"
346
- },
347
- {
348
- "href": "\/grid5000\/sites\/nancy\/versions",
349
- "title": "versions",
350
- "rel": "collection"
351
- },
352
- {
353
- "href": "\/grid5000\/sites\/nancy\/clusters",
354
- "resolvable": true,
355
- "title": "clusters",
356
- "rel": "collection",
357
- "resolved": false
358
- },
359
- {
360
- "href": "\/grid5000\/sites\/nancy\/environments",
361
- "resolvable": true,
362
- "title": "environments",
363
- "rel": "collection",
364
- "resolved": false
365
- },
366
- {
367
- "href": "\/grid5000",
368
- "rel": "parent"
369
- },
370
- {
371
- "href": "\/grid5000\/sites\/nancy\/status",
372
- "title": "status",
373
- "rel": "collection"
374
- }
375
- ],
376
- "description": "",
377
- "longitude": 6.2,
378
- "web": null,
379
- "sys_admin_contact": null
380
- },
381
- "bordeaux": {
382
- "name": "Bordeaux",
383
- "latitude": 44.833333,
384
- "location": "Bordeaux, France",
385
- "security_contact": "bordeaux-staff@lists.grid5000.fr",
386
- "uid": "bordeaux",
387
- "type": "site",
388
- "user_support_contact": "bordeaux-staff@lists.grid5000.fr",
389
- "version": "747d2af24c5f3c2578a96626e0b00413c8484f04",
390
- "links": [
391
- {
392
- "href": "\/grid5000\/sites\/bordeaux",
393
- "rel": "self"
394
- },
395
- {
396
- "href": "\/grid5000\/sites\/bordeaux\/versions\/747d2af24c5f3c2578a96626e0b00413c8484f04",
397
- "title": "version",
398
- "rel": "member"
399
- },
400
- {
401
- "href": "\/grid5000\/sites\/bordeaux\/versions",
402
- "title": "versions",
403
- "rel": "collection"
404
- },
405
- {
406
- "href": "\/grid5000\/sites\/bordeaux\/clusters",
407
- "resolvable": true,
408
- "title": "clusters",
409
- "rel": "collection",
410
- "resolved": false
411
- },
412
- {
413
- "href": "\/grid5000\/sites\/bordeaux\/environments",
414
- "resolvable": true,
415
- "title": "environments",
416
- "rel": "collection",
417
- "resolved": false
418
- },
419
- {
420
- "href": "\/grid5000",
421
- "rel": "parent"
422
- },
423
- {
424
- "href": "\/grid5000\/sites\/bordeaux\/status",
425
- "title": "status",
426
- "rel": "collection"
427
- }
428
- ],
429
- "description": "Grid5000 Bordeaux site",
430
- "longitude": -0.566667,
431
- "email_contact": "bordeaux-staff@lists.grid5000.fr",
432
- "web": "http:\/\/www.grid5000.fr\/mediawiki\/index.php\/Bordeaux:Home",
433
- "sys_admin_contact": "bordeaux-staff@lists.grid5000.fr"
434
- },
435
- "orsay": {
436
- "name": "Orsay",
437
- "latitude": 48.7,
438
- "location": "Orsay, France",
439
- "security_contact": null,
440
- "uid": "orsay",
441
- "type": "site",
442
- "user_support_contact": null,
443
- "version": "747d2af24c5f3c2578a96626e0b00413c8484f04",
444
- "links": [
445
- {
446
- "href": "\/grid5000\/sites\/orsay",
447
- "rel": "self"
448
- },
449
- {
450
- "href": "\/grid5000\/sites\/orsay\/versions\/747d2af24c5f3c2578a96626e0b00413c8484f04",
451
- "title": "version",
452
- "rel": "member"
453
- },
454
- {
455
- "href": "\/grid5000\/sites\/orsay\/versions",
456
- "title": "versions",
457
- "rel": "collection"
458
- },
459
- {
460
- "href": "\/grid5000\/sites\/orsay\/clusters",
461
- "resolvable": true,
462
- "title": "clusters",
463
- "rel": "collection",
464
- "resolved": false
465
- },
466
- {
467
- "href": "\/grid5000\/sites\/orsay\/environments",
468
- "resolvable": true,
469
- "title": "environments",
470
- "rel": "collection",
471
- "resolved": false
472
- },
473
- {
474
- "href": "\/grid5000",
475
- "rel": "parent"
476
- },
477
- {
478
- "href": "\/grid5000\/sites\/orsay\/status",
479
- "title": "status",
480
- "rel": "collection"
481
- }
482
- ],
483
- "description": "",
484
- "longitude": 2.2,
485
- "email_contact": null,
486
- "web": null,
487
- "sys_admin_contact": null
488
- }
2
+ "items": [
3
+ {
4
+ "name": "Bordeaux",
5
+ "latitude": 44.833333,
6
+ "location": "Bordeaux, France",
7
+ "security_contact": "bordeaux-staff@lists.grid5000.fr",
8
+ "uid": "bordeaux",
9
+ "type": "site",
10
+ "user_support_contact": "bordeaux-staff@lists.grid5000.fr",
11
+ "version": "4fe96b25d2cbfee16abe5a4fb999c82dbafc2ee8",
12
+ "links": [
13
+ {
14
+ "href": "/grid5000/sites/bordeaux/versions/4fe96b25d2cbfee16abe5a4fb999c82dbafc2ee8",
15
+ "title": "version",
16
+ "rel": "member",
17
+ "type": "application/vnd.fr.grid5000.api.Version+json;level=1"
18
+ },
19
+ {
20
+ "href": "/grid5000/sites/bordeaux/versions",
21
+ "title": "versions",
22
+ "rel": "collection",
23
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
24
+ },
25
+ {
26
+ "href": "/grid5000/sites/bordeaux",
27
+ "rel": "self",
28
+ "type": "application/vnd.fr.grid5000.api.Site+json;level=1"
29
+ },
30
+ {
31
+ "href": "/grid5000/sites/bordeaux/clusters",
32
+ "title": "clusters",
33
+ "rel": "collection",
34
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
35
+ },
36
+ {
37
+ "href": "/grid5000/sites/bordeaux/environments",
38
+ "title": "environments",
39
+ "rel": "collection",
40
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
41
+ },
42
+ {
43
+ "href": "/grid5000",
44
+ "rel": "parent",
45
+ "type": "application/vnd.fr.grid5000.api.Grid+json;level=1"
46
+ },
47
+ {
48
+ "href": "/grid5000/sites/bordeaux/status",
49
+ "title": "status",
50
+ "rel": "collection",
51
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
52
+ }
53
+ ],
54
+ "description": "Grid5000 Bordeaux site",
55
+ "longitude": -0.566667,
56
+ "email_contact": "bordeaux-staff@lists.grid5000.fr",
57
+ "web": "http://www.grid5000.fr/mediawiki/index.php/Bordeaux:Home",
58
+ "sys_admin_contact": "bordeaux-staff@lists.grid5000.fr"
59
+ },
60
+ {
61
+ "name": "Grenoble",
62
+ "latitude": 45.1833,
63
+ "location": "Grenoble, France",
64
+ "security_contact": null,
65
+ "uid": "grenoble",
66
+ "type": "site",
67
+ "user_support_contact": null,
68
+ "version": "4fe96b25d2cbfee16abe5a4fb999c82dbafc2ee8",
69
+ "links": [
70
+ {
71
+ "href": "/grid5000/sites/grenoble/versions/4fe96b25d2cbfee16abe5a4fb999c82dbafc2ee8",
72
+ "title": "version",
73
+ "rel": "member",
74
+ "type": "application/vnd.fr.grid5000.api.Version+json;level=1"
75
+ },
76
+ {
77
+ "href": "/grid5000/sites/grenoble/versions",
78
+ "title": "versions",
79
+ "rel": "collection",
80
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
81
+ },
82
+ {
83
+ "href": "/grid5000/sites/grenoble",
84
+ "rel": "self",
85
+ "type": "application/vnd.fr.grid5000.api.Site+json;level=1"
86
+ },
87
+ {
88
+ "href": "/grid5000/sites/grenoble/clusters",
89
+ "title": "clusters",
90
+ "rel": "collection",
91
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
92
+ },
93
+ {
94
+ "href": "/grid5000/sites/grenoble/environments",
95
+ "title": "environments",
96
+ "rel": "collection",
97
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
98
+ },
99
+ {
100
+ "href": "/grid5000",
101
+ "rel": "parent",
102
+ "type": "application/vnd.fr.grid5000.api.Grid+json;level=1"
103
+ },
104
+ {
105
+ "href": "/grid5000/sites/grenoble/status",
106
+ "title": "status",
107
+ "rel": "collection",
108
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
109
+ }
110
+ ],
111
+ "description": "",
112
+ "longitude": 5.7167,
113
+ "email_contact": null,
114
+ "web": null,
115
+ "sys_admin_contact": null
116
+ },
117
+ {
118
+ "name": "Lille",
119
+ "latitude": 50.65,
120
+ "location": "Lille, France",
121
+ "security_contact": null,
122
+ "uid": "lille",
123
+ "type": "site",
124
+ "user_support_contact": null,
125
+ "version": "4fe96b25d2cbfee16abe5a4fb999c82dbafc2ee8",
126
+ "links": [
127
+ {
128
+ "href": "/grid5000/sites/lille/versions/4fe96b25d2cbfee16abe5a4fb999c82dbafc2ee8",
129
+ "title": "version",
130
+ "rel": "member",
131
+ "type": "application/vnd.fr.grid5000.api.Version+json;level=1"
132
+ },
133
+ {
134
+ "href": "/grid5000/sites/lille/versions",
135
+ "title": "versions",
136
+ "rel": "collection",
137
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
138
+ },
139
+ {
140
+ "href": "/grid5000/sites/lille",
141
+ "rel": "self",
142
+ "type": "application/vnd.fr.grid5000.api.Site+json;level=1"
143
+ },
144
+ {
145
+ "href": "/grid5000/sites/lille/clusters",
146
+ "title": "clusters",
147
+ "rel": "collection",
148
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
149
+ },
150
+ {
151
+ "href": "/grid5000/sites/lille/environments",
152
+ "title": "environments",
153
+ "rel": "collection",
154
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
155
+ },
156
+ {
157
+ "href": "/grid5000",
158
+ "rel": "parent",
159
+ "type": "application/vnd.fr.grid5000.api.Grid+json;level=1"
160
+ },
161
+ {
162
+ "href": "/grid5000/sites/lille/status",
163
+ "title": "status",
164
+ "rel": "collection",
165
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
166
+ }
167
+ ],
168
+ "description": "",
169
+ "longitude": 3.0833,
170
+ "email_contact": null,
171
+ "web": null,
172
+ "sys_admin_contact": null
173
+ },
174
+ {
175
+ "name": "Lyon",
176
+ "latitude": 45.7667,
177
+ "location": "Lyon, France",
178
+ "security_contact": null,
179
+ "uid": "lyon",
180
+ "type": "site",
181
+ "user_support_contact": null,
182
+ "version": "4fe96b25d2cbfee16abe5a4fb999c82dbafc2ee8",
183
+ "links": [
184
+ {
185
+ "href": "/grid5000/sites/lyon/versions/4fe96b25d2cbfee16abe5a4fb999c82dbafc2ee8",
186
+ "title": "version",
187
+ "rel": "member",
188
+ "type": "application/vnd.fr.grid5000.api.Version+json;level=1"
189
+ },
190
+ {
191
+ "href": "/grid5000/sites/lyon/versions",
192
+ "title": "versions",
193
+ "rel": "collection",
194
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
195
+ },
196
+ {
197
+ "href": "/grid5000/sites/lyon",
198
+ "rel": "self",
199
+ "type": "application/vnd.fr.grid5000.api.Site+json;level=1"
200
+ },
201
+ {
202
+ "href": "/grid5000/sites/lyon/clusters",
203
+ "title": "clusters",
204
+ "rel": "collection",
205
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
206
+ },
207
+ {
208
+ "href": "/grid5000/sites/lyon/environments",
209
+ "title": "environments",
210
+ "rel": "collection",
211
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
212
+ },
213
+ {
214
+ "href": "/grid5000",
215
+ "rel": "parent",
216
+ "type": "application/vnd.fr.grid5000.api.Grid+json;level=1"
217
+ },
218
+ {
219
+ "href": "/grid5000/sites/lyon/status",
220
+ "title": "status",
221
+ "rel": "collection",
222
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
223
+ }
224
+ ],
225
+ "description": "",
226
+ "longitude": 4.8333,
227
+ "email_contact": null,
228
+ "web": null,
229
+ "sys_admin_contact": null
230
+ },
231
+ {
232
+ "name": "Nancy",
233
+ "latitude": 48.7,
234
+ "location": "Nancy, France",
235
+ "security_contact": null,
236
+ "uid": "nancy",
237
+ "type": "site",
238
+ "user_support_contact": null,
239
+ "version": "4fe96b25d2cbfee16abe5a4fb999c82dbafc2ee8",
240
+ "links": [
241
+ {
242
+ "href": "/grid5000/sites/nancy/versions/4fe96b25d2cbfee16abe5a4fb999c82dbafc2ee8",
243
+ "title": "version",
244
+ "rel": "member",
245
+ "type": "application/vnd.fr.grid5000.api.Version+json;level=1"
246
+ },
247
+ {
248
+ "href": "/grid5000/sites/nancy/versions",
249
+ "title": "versions",
250
+ "rel": "collection",
251
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
252
+ },
253
+ {
254
+ "href": "/grid5000/sites/nancy",
255
+ "rel": "self",
256
+ "type": "application/vnd.fr.grid5000.api.Site+json;level=1"
257
+ },
258
+ {
259
+ "href": "/grid5000/sites/nancy/clusters",
260
+ "title": "clusters",
261
+ "rel": "collection",
262
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
263
+ },
264
+ {
265
+ "href": "/grid5000/sites/nancy/environments",
266
+ "title": "environments",
267
+ "rel": "collection",
268
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
269
+ },
270
+ {
271
+ "href": "/grid5000",
272
+ "rel": "parent",
273
+ "type": "application/vnd.fr.grid5000.api.Grid+json;level=1"
274
+ },
275
+ {
276
+ "href": "/grid5000/sites/nancy/status",
277
+ "title": "status",
278
+ "rel": "collection",
279
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
280
+ }
281
+ ],
282
+ "description": "",
283
+ "longitude": 6.2,
284
+ "web": null,
285
+ "sys_admin_contact": null
286
+ },
287
+ {
288
+ "name": "Orsay",
289
+ "latitude": 48.7,
290
+ "location": "Orsay, France",
291
+ "security_contact": null,
292
+ "uid": "orsay",
293
+ "type": "site",
294
+ "user_support_contact": null,
295
+ "version": "4fe96b25d2cbfee16abe5a4fb999c82dbafc2ee8",
296
+ "links": [
297
+ {
298
+ "href": "/grid5000/sites/orsay/versions/4fe96b25d2cbfee16abe5a4fb999c82dbafc2ee8",
299
+ "title": "version",
300
+ "rel": "member",
301
+ "type": "application/vnd.fr.grid5000.api.Version+json;level=1"
302
+ },
303
+ {
304
+ "href": "/grid5000/sites/orsay/versions",
305
+ "title": "versions",
306
+ "rel": "collection",
307
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
308
+ },
309
+ {
310
+ "href": "/grid5000/sites/orsay",
311
+ "rel": "self",
312
+ "type": "application/vnd.fr.grid5000.api.Site+json;level=1"
313
+ },
314
+ {
315
+ "href": "/grid5000/sites/orsay/clusters",
316
+ "title": "clusters",
317
+ "rel": "collection",
318
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
319
+ },
320
+ {
321
+ "href": "/grid5000/sites/orsay/environments",
322
+ "title": "environments",
323
+ "rel": "collection",
324
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
325
+ },
326
+ {
327
+ "href": "/grid5000",
328
+ "rel": "parent",
329
+ "type": "application/vnd.fr.grid5000.api.Grid+json;level=1"
330
+ },
331
+ {
332
+ "href": "/grid5000/sites/orsay/status",
333
+ "title": "status",
334
+ "rel": "collection",
335
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
336
+ }
337
+ ],
338
+ "description": "",
339
+ "longitude": 2.2,
340
+ "email_contact": null,
341
+ "web": null,
342
+ "sys_admin_contact": null
343
+ },
344
+ {
345
+ "name": "Rennes",
346
+ "latitude": 48.1,
347
+ "location": "Rennes, France",
348
+ "security_contact": "rennes-staff@lists.grid5000.fr",
349
+ "uid": "rennes",
350
+ "type": "site",
351
+ "user_support_contact": "rennes-staff@lists.grid5000.fr",
352
+ "version": "4fe96b25d2cbfee16abe5a4fb999c82dbafc2ee8",
353
+ "links": [
354
+ {
355
+ "href": "/grid5000/sites/rennes/versions/4fe96b25d2cbfee16abe5a4fb999c82dbafc2ee8",
356
+ "title": "version",
357
+ "rel": "member",
358
+ "type": "application/vnd.fr.grid5000.api.Version+json;level=1"
359
+ },
360
+ {
361
+ "href": "/grid5000/sites/rennes/versions",
362
+ "title": "versions",
363
+ "rel": "collection",
364
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
365
+ },
366
+ {
367
+ "href": "/grid5000/sites/rennes",
368
+ "rel": "self",
369
+ "type": "application/vnd.fr.grid5000.api.Site+json;level=1"
370
+ },
371
+ {
372
+ "href": "/grid5000/sites/rennes/clusters",
373
+ "title": "clusters",
374
+ "rel": "collection",
375
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
376
+ },
377
+ {
378
+ "href": "/grid5000/sites/rennes/environments",
379
+ "title": "environments",
380
+ "rel": "collection",
381
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
382
+ },
383
+ {
384
+ "href": "/grid5000",
385
+ "rel": "parent",
386
+ "type": "application/vnd.fr.grid5000.api.Grid+json;level=1"
387
+ },
388
+ {
389
+ "href": "/grid5000/sites/rennes/status",
390
+ "title": "status",
391
+ "rel": "collection",
392
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
393
+ }
394
+ ],
395
+ "description": "",
396
+ "longitude": -1.6667,
397
+ "compilation_server": false,
398
+ "email_contact": "rennes-staff@lists.grid5000.fr",
399
+ "web": "http://www.irisa.fr",
400
+ "sys_admin_contact": "rennes-staff@lists.grid5000.fr"
401
+ },
402
+ {
403
+ "name": "Sophia-Antipolis",
404
+ "latitude": 43.6161,
405
+ "location": "Sophia-Antipolis, France",
406
+ "security_contact": "sophia-staff@lists.grid5000.fr",
407
+ "uid": "sophia",
408
+ "type": "site",
409
+ "user_support_contact": "sophia-staff@lists.grid5000.fr",
410
+ "version": "4fe96b25d2cbfee16abe5a4fb999c82dbafc2ee8",
411
+ "links": [
412
+ {
413
+ "href": "/grid5000/sites/sophia/versions/4fe96b25d2cbfee16abe5a4fb999c82dbafc2ee8",
414
+ "title": "version",
415
+ "rel": "member",
416
+ "type": "application/vnd.fr.grid5000.api.Version+json;level=1"
417
+ },
418
+ {
419
+ "href": "/grid5000/sites/sophia/versions",
420
+ "title": "versions",
421
+ "rel": "collection",
422
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
423
+ },
424
+ {
425
+ "href": "/grid5000/sites/sophia",
426
+ "rel": "self",
427
+ "type": "application/vnd.fr.grid5000.api.Site+json;level=1"
428
+ },
429
+ {
430
+ "href": "/grid5000/sites/sophia/clusters",
431
+ "title": "clusters",
432
+ "rel": "collection",
433
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
434
+ },
435
+ {
436
+ "href": "/grid5000/sites/sophia/environments",
437
+ "title": "environments",
438
+ "rel": "collection",
439
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
440
+ },
441
+ {
442
+ "href": "/grid5000",
443
+ "rel": "parent",
444
+ "type": "application/vnd.fr.grid5000.api.Grid+json;level=1"
445
+ },
446
+ {
447
+ "href": "/grid5000/sites/sophia/status",
448
+ "title": "status",
449
+ "rel": "collection",
450
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
451
+ }
452
+ ],
453
+ "description": "",
454
+ "longitude": 7.0678,
455
+ "compilation_server": true,
456
+ "email_contact": "sophia-staff@lists.grid5000.fr",
457
+ "web": null,
458
+ "sys_admin_contact": "sophia-staff@lists.grid5000.fr"
459
+ },
460
+ {
461
+ "name": "Toulouse",
462
+ "latitude": 43.6167,
463
+ "location": "Toulouse, France",
464
+ "security_contact": null,
465
+ "uid": "toulouse",
466
+ "type": "site",
467
+ "user_support_contact": null,
468
+ "version": "4fe96b25d2cbfee16abe5a4fb999c82dbafc2ee8",
469
+ "links": [
470
+ {
471
+ "href": "/grid5000/sites/toulouse/versions/4fe96b25d2cbfee16abe5a4fb999c82dbafc2ee8",
472
+ "title": "version",
473
+ "rel": "member",
474
+ "type": "application/vnd.fr.grid5000.api.Version+json;level=1"
475
+ },
476
+ {
477
+ "href": "/grid5000/sites/toulouse/versions",
478
+ "title": "versions",
479
+ "rel": "collection",
480
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
481
+ },
482
+ {
483
+ "href": "/grid5000/sites/toulouse",
484
+ "rel": "self",
485
+ "type": "application/vnd.fr.grid5000.api.Site+json;level=1"
486
+ },
487
+ {
488
+ "href": "/grid5000/sites/toulouse/clusters",
489
+ "title": "clusters",
490
+ "rel": "collection",
491
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
492
+ },
493
+ {
494
+ "href": "/grid5000/sites/toulouse/environments",
495
+ "title": "environments",
496
+ "rel": "collection",
497
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
498
+ },
499
+ {
500
+ "href": "/grid5000",
501
+ "rel": "parent",
502
+ "type": "application/vnd.fr.grid5000.api.Grid+json;level=1"
503
+ },
504
+ {
505
+ "href": "/grid5000/sites/toulouse/status",
506
+ "title": "status",
507
+ "rel": "collection",
508
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
509
+ }
510
+ ],
511
+ "description": "",
512
+ "longitude": 1.4333,
513
+ "email_contact": null,
514
+ "web": null,
515
+ "sys_admin_contact": null
516
+ }
517
+ ],
518
+ "total": 9,
519
+ "version": "4fe96b25d2cbfee16abe5a4fb999c82dbafc2ee8",
520
+ "links": [
521
+ {
522
+ "href": "/grid5000/sites/versions/4fe96b25d2cbfee16abe5a4fb999c82dbafc2ee8",
523
+ "title": "version",
524
+ "rel": "member",
525
+ "type": "application/vnd.fr.grid5000.api.Version+json;level=1"
526
+ },
527
+ {
528
+ "href": "/grid5000/sites/versions",
529
+ "title": "versions",
530
+ "rel": "collection",
531
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
532
+ },
533
+ {
534
+ "href": "/grid5000/sites",
535
+ "rel": "self",
536
+ "type": "application/vnd.fr.grid5000.api.Collection+json;level=1"
537
+ }
538
+ ],
539
+ "offset": 0
489
540
  }