ovirt-engine-sdk 4.2.0 → 4.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bf11e3460b2e00a5fd673a768a84b1e22657fec7
4
- data.tar.gz: '028c4fd704c4591c5753de18f2dbbfdecbeac1e1'
3
+ metadata.gz: 573f19600decb51717ca7b46538158f0bfe145c9
4
+ data.tar.gz: a42480a7c2627d263106163ecd835c80f0ef2b53
5
5
  SHA512:
6
- metadata.gz: cc8b6ac930ddb084da2dcd0e8164044939c8601e81e8d432495e0b3673401ecd583c77da9240498c4329a7085d41e1caa984585ae3da33a6d7086ee3acf6770d
7
- data.tar.gz: 739766ec3dd856e92d9829c44a321109b6e5568097a98fb6a739ba435c293e8c6c85bf08fefb7b32df8da19dd1c4f8b889657fe29bff9a548648fae0414c07c8
6
+ metadata.gz: 3a8a06fe3746bf4c82c9d18c5d9dce0920f6202857444e830c4e917e2d8bacfc2ac9bdd802402a9049b7df029105837c41f1c0c94e3cd7ffc50750abefd66547
7
+ data.tar.gz: 97c010a0aee2fa5e496df698790a65be800522c4271db84aba09cf3fe6be1794aec263a0f7607edc22eb8aa48fda629a018e182d9e1d872c716b68626deb1219
@@ -2,6 +2,16 @@
2
2
 
3
3
  This document describes the relevant changes between releases of the SDK.
4
4
 
5
+ == 4.2.1 / Dec 13 2017
6
+
7
+ Bug fixes:
8
+
9
+ * Fix handling of the `all_content` parameter
10
+ https://bugzilla.redhat.com/1525555[#1525555].
11
+
12
+ * Limit the number of requests sent to `libcurl`
13
+ https://bugzilla.redhat.com/1525302[#1525302].
14
+
5
15
  == 4.2.0 / Dec 4 2017
6
16
 
7
17
  No chages, version `4.2.0` is identical to `4.2.0-beta2`, only the
@@ -64,16 +64,21 @@ static ID READ_ID;
64
64
  static ID STRING_ID;
65
65
  static ID STRING_IO_ID;
66
66
  static ID URI_ID;
67
+ static ID WARN_ID;
68
+ static ID WARN_Q_ID;
67
69
  static ID WRITE_ID;
68
70
 
69
71
  /* References to classes: */
70
- static VALUE URI_CLASS;
71
72
  static VALUE STRING_IO_CLASS;
73
+ static VALUE URI_CLASS;
72
74
 
73
75
  /* Constants: */
74
76
  const char CR = '\x0D';
75
77
  const char LF = '\x0A';
76
78
 
79
+ /* Version of libcurl: */
80
+ static curl_version_info_data* libcurl_version;
81
+
77
82
  /* Before version 7.38.0 of libcurl the NEGOTIATE authentication method was named GSSNEGOTIATE: */
78
83
  #ifndef CURLAUTH_NEGOTIATE
79
84
  #define CURLAUTH_NEGOTIATE CURLAUTH_GSSNEGOTIATE
@@ -85,6 +90,21 @@ const char LF = '\x0A';
85
90
  #define CURLPIPE_HTTP1 1
86
91
  #endif
87
92
 
93
+ /* Define options that may not be available in some versions of libcurl: */
94
+ #if LIBCURL_VERSION_NUM < 0x071e00 /* 7.30.0 */
95
+ #define CURLMOPT_MAX_HOST_CONNECTIONS 7
96
+ #define CURLMOPT_MAX_PIPELINE_LENGTH 8
97
+ #define CURLMOPT_MAX_TOTAL_CONNECTIONS 13
98
+ #endif
99
+
100
+ #if LIBCURL_VERSION_NUM < 0x070f03 /* 7.16.3 */
101
+ #define CURLMOPT_MAXCONNECTS 6
102
+ #endif
103
+
104
+ #if LIBCURL_VERSION_NUM < 0x070f00 /* 7.16.0 */
105
+ #define CURLMOPT_PIPELINING 3
106
+ #endif
107
+
88
108
  typedef struct {
89
109
  VALUE io; /* IO */
90
110
  char* ptr;
@@ -131,6 +151,22 @@ static void ov_http_client_log_info(VALUE log, const char* format, ...) {
131
151
  }
132
152
  }
133
153
 
154
+ static void ov_http_client_log_warn(VALUE log, const char* format, ...) {
155
+ VALUE enabled;
156
+ VALUE message;
157
+ va_list args;
158
+
159
+ if (!NIL_P(log)) {
160
+ enabled = rb_funcall(log, WARN_Q_ID, 0);
161
+ if (RTEST(enabled)) {
162
+ va_start(args, format);
163
+ message = rb_vsprintf(format, args);
164
+ rb_funcall(log, WARN_ID, 1, message);
165
+ va_end(args);
166
+ }
167
+ }
168
+ }
169
+
134
170
  static void ov_http_client_check_closed(ov_http_client_object* object) {
135
171
  if (object->handle == NULL) {
136
172
  rb_raise(ov_error_class, "The client is already closed");
@@ -142,6 +178,7 @@ static void ov_http_client_mark(void* vptr) {
142
178
 
143
179
  ptr = vptr;
144
180
  rb_gc_mark(ptr->log);
181
+ rb_gc_mark(ptr->queue);
145
182
  rb_gc_mark(ptr->pending);
146
183
  rb_gc_mark(ptr->completed);
147
184
  }
@@ -192,6 +229,8 @@ static VALUE ov_http_client_alloc(VALUE klass) {
192
229
  ptr->handle = NULL;
193
230
  ptr->share = NULL;
194
231
  ptr->log = Qnil;
232
+ ptr->limit = 0;
233
+ ptr->queue = Qnil;
195
234
  ptr->pending = Qnil;
196
235
  ptr->completed = Qnil;
197
236
  ptr->compress = false;
@@ -567,16 +606,22 @@ static VALUE ov_http_client_initialize(int argc, VALUE* argv, VALUE self) {
567
606
  Check_Type(opt, T_FIXNUM);
568
607
  pipeline = NUM2LONG(opt);
569
608
  }
609
+ if (pipeline < 0) {
610
+ rb_raise(rb_eArgError, "The maximum pipeline length can't be %ld, minimum is 0.", pipeline);
611
+ }
570
612
 
571
613
  /* Get the value of the 'connections' parameter: */
572
614
  opt = rb_hash_aref(opts, CONNECTIONS_SYMBOL);
573
615
  if (NIL_P(opt)) {
574
- connections = 0;
616
+ connections = 1;
575
617
  }
576
618
  else {
577
619
  Check_Type(opt, T_FIXNUM);
578
620
  connections = NUM2LONG(opt);
579
621
  }
622
+ if (connections < 1) {
623
+ rb_raise(rb_eArgError, "The maximum number of connections can't be %ld, minimum is 1.", connections);
624
+ }
580
625
 
581
626
  /* Get the value of the 'cookies' parameter. If it is a string it will be used as the path of the file where the
582
627
  cookies will be stored. If it is any other thing it will be treated as a boolean flag indicating if cookies
@@ -592,11 +637,22 @@ static VALUE ov_http_client_initialize(int argc, VALUE* argv, VALUE self) {
592
637
  ptr->cookies = NULL;
593
638
  }
594
639
 
640
+ /* Create the queue that contains requests that haven't been sent to libcurl yet: */
641
+ ptr->queue = rb_ary_new();
642
+
595
643
  /* Create the hash that contains the transfers are pending an completed. Both use the identity of the request
596
644
  as key. */
597
645
  ptr->completed = rb_funcall(rb_hash_new(), COMPARE_BY_IDENTITY_ID, 0);
598
646
  ptr->pending = rb_funcall(rb_hash_new(), COMPARE_BY_IDENTITY_ID, 0);
599
647
 
648
+ /* Calculate the max number of requests that can be handled by libcurl simultaneously. For versions of libcurl
649
+ newer than 7.30.0 the limit can be increased when using pipelining. For older versions it can't be increased
650
+ because libcurl would create additional connections for the requests that can't be pipelined. */
651
+ ptr->limit = connections;
652
+ if (pipeline > 0 && libcurl_version->version_num >= 0x071e00 /* 7.30.0 */) {
653
+ ptr->limit *= pipeline;
654
+ }
655
+
600
656
  /* Create the libcurl multi handle: */
601
657
  ptr->handle = curl_multi_init();
602
658
  if (ptr->handle == NULL) {
@@ -615,14 +671,47 @@ static VALUE ov_http_client_initialize(int argc, VALUE* argv, VALUE self) {
615
671
  /* Enable pipelining: */
616
672
  if (pipeline > 0) {
617
673
  curl_multi_setopt(ptr->handle, CURLMOPT_PIPELINING, CURLPIPE_HTTP1);
618
- #ifdef CURLMOPT_MAX_PIPELINE_LENGTH
619
- curl_multi_setopt(ptr->handle, CURLMOPT_MAX_PIPELINE_LENGTH, pipeline);
620
- #endif
674
+ if (libcurl_version->version_num >= 0x071e00 /* 7.30.0 */) {
675
+ curl_multi_setopt(ptr->handle, CURLMOPT_MAX_PIPELINE_LENGTH, pipeline);
676
+ }
677
+ else {
678
+ ov_http_client_log_warn(
679
+ ptr->log,
680
+ "Can't set maximum pipeline length to %d, it isn't supported by libcurl %s. Upgrade to 7.30.0 or "
681
+ "newer to avoid this issue.",
682
+ pipeline,
683
+ libcurl_version->version
684
+ );
685
+ }
621
686
  }
687
+
688
+ /* Set the max number of connections: */
622
689
  if (connections > 0) {
623
- #ifdef CURLMOPT_MAX_HOST_CONNECTIONS
624
- curl_multi_setopt(ptr->handle, CURLMOPT_MAX_HOST_CONNECTIONS, connections);
625
- #endif
690
+ if (libcurl_version->version_num >= 0x071e00 /* 7.30.0 */) {
691
+ curl_multi_setopt(ptr->handle, CURLMOPT_MAX_HOST_CONNECTIONS, connections);
692
+ curl_multi_setopt(ptr->handle, CURLMOPT_MAX_TOTAL_CONNECTIONS, connections);
693
+ }
694
+ else {
695
+ ov_http_client_log_warn(
696
+ ptr->log,
697
+ "Can't set maximum number of connections to %d, it isn't supported by libcurl %s. Upgrade to 7.30.0 "
698
+ "or newer to avoid this issue.",
699
+ connections,
700
+ libcurl_version->version
701
+ );
702
+ }
703
+ if (libcurl_version->version_num >= 0x070f03 /* 7.16.3 */) {
704
+ curl_multi_setopt(ptr->handle, CURLMOPT_MAXCONNECTS, connections);
705
+ }
706
+ else {
707
+ ov_http_client_log_warn(
708
+ ptr->log,
709
+ "Can't set total maximum connection cache size to %d, it isn't supported by libcurl %s. Upgrade to "
710
+ "7.16.3 or newer to avoid this issue.",
711
+ connections,
712
+ libcurl_version->version
713
+ );
714
+ }
626
715
  }
627
716
 
628
717
  return self;
@@ -922,7 +1011,7 @@ static void ov_http_client_prepare_handle(ov_http_client_object* client_ptr, ov_
922
1011
  );
923
1012
  }
924
1013
 
925
- static VALUE ov_http_client_send(VALUE self, VALUE request) {
1014
+ static VALUE ov_http_client_submit(VALUE self, VALUE request) {
926
1015
  CURL* handle;
927
1016
  VALUE response;
928
1017
  VALUE transfer;
@@ -992,7 +1081,26 @@ static VALUE ov_http_client_send(VALUE self, VALUE request) {
992
1081
  return Qnil;
993
1082
  }
994
1083
 
1084
+ static VALUE ov_http_client_send(VALUE self, VALUE request) {
1085
+ ov_http_client_object* ptr;
1086
+
1087
+ /* Get the pointer to the native object and check that it isn't closed: */
1088
+ ov_http_client_ptr(self, ptr);
1089
+ ov_http_client_check_closed(ptr);
1090
+
1091
+ /* If the limit hasn't been reached then submit the request directly to libcurl, otherwise put it in the queue: */
1092
+ if (RHASH_SIZE(ptr->pending) < ptr->limit) {
1093
+ ov_http_client_submit(self, request);
1094
+ }
1095
+ else {
1096
+ rb_ary_push(ptr->queue, request);
1097
+ }
1098
+
1099
+ return Qnil;
1100
+ }
1101
+
995
1102
  static VALUE ov_http_client_wait(VALUE self, VALUE request) {
1103
+ VALUE next;
996
1104
  VALUE result;
997
1105
  ov_http_client_object* ptr;
998
1106
  ov_http_client_wait_context context;
@@ -1001,15 +1109,24 @@ static VALUE ov_http_client_wait(VALUE self, VALUE request) {
1001
1109
  ov_http_client_ptr(self, ptr);
1002
1110
  ov_http_client_check_closed(ptr);
1003
1111
 
1004
- /* Work till the transfer has been completed: */
1112
+ /* Work till the transfer has been completed. */
1005
1113
  context.handle = ptr->handle;
1006
1114
  context.code = CURLE_OK;
1007
1115
  context.cancel = false;
1008
1116
  for (;;) {
1117
+ /* Move requests from the queue to libcurl: */
1118
+ while (RARRAY_LEN(ptr->queue) > 0 && RHASH_SIZE(ptr->pending) < ptr->limit) {
1119
+ next = rb_ary_shift(ptr->queue);
1120
+ ov_http_client_submit(self, next);
1121
+ }
1122
+
1123
+ /* Check if the response is already available, if so then return it: */
1009
1124
  result = rb_hash_delete(ptr->completed, request);
1010
1125
  if (!NIL_P(result)) {
1011
1126
  return result;
1012
1127
  }
1128
+
1129
+ /* If the response isn't available yet, then do some real work: */
1013
1130
  rb_thread_call_without_gvl(
1014
1131
  ov_http_client_wait_task,
1015
1132
  &context,
@@ -1082,6 +1199,8 @@ void ov_http_client_define(void) {
1082
1199
  STRING_ID = rb_intern("string");
1083
1200
  STRING_IO_ID = rb_intern("StringIO");
1084
1201
  URI_ID = rb_intern("URI");
1202
+ WARN_ID = rb_intern("warn");
1203
+ WARN_Q_ID = rb_intern("warn?");
1085
1204
  WRITE_ID = rb_intern("write");
1086
1205
 
1087
1206
  /* Locate classes: */
@@ -1093,4 +1212,7 @@ void ov_http_client_define(void) {
1093
1212
  if (code != CURLE_OK) {
1094
1213
  rb_raise(ov_error_class, "Can't initialize libcurl: %s", curl_easy_strerror(code));
1095
1214
  }
1215
+
1216
+ /* Get the libcurl version: */
1217
+ libcurl_version = curl_version_info(CURLVERSION_NOW);
1096
1218
  }
@@ -37,7 +37,14 @@ typedef struct {
37
37
  /* The logger: */
38
38
  VALUE log;
39
39
 
40
- /* This hash store the transfers that are pending. The key of the hash is the request that initiated the transfer,
40
+ /* The max number of requests that can be processed simultaneously by libcurl. Will be calculated multiplying the
41
+ max number of connections by the pipeline length: */
42
+ int limit;
43
+
44
+ /* This queue contains the requests that have not yet been sent to libcurl for processing: */
45
+ VALUE queue;
46
+
47
+ /* This hash stores the transfers that are pending. The key of the hash is the request that initiated the transfer,
41
48
  and the value is the transfer itself. */
42
49
  VALUE pending;
43
50
 
@@ -101,8 +101,8 @@ module OvirtSDK4
101
101
  # as the names of the headers. If the same header is provided here and in the `headers` parameter of a specific
102
102
  # method call, then the `headers` parameter of the specific method call will have precedence.
103
103
  #
104
- # @option opts [Integer] :connections (0) The maximum number of connections to open to the host. If the value is
105
- # `0` (the default) then the number of connections will be unlimited.
104
+ # @option opts [Integer] :connections (1) The maximum number of connections to open to the host. The value must
105
+ # be greater than 0.
106
106
  #
107
107
  # @option opts [Integer] :pipeline (0) The maximum number of request to put in an HTTP pipeline without waiting for
108
108
  # the response. If the value is `0` (the default) then pipelining is disabled.
@@ -126,7 +126,7 @@ module OvirtSDK4
126
126
  @proxy_username = opts[:proxy_username]
127
127
  @proxy_password = opts[:proxy_password]
128
128
  @headers = opts[:headers]
129
- @connections = opts[:connections] || 0
129
+ @connections = opts[:connections] || 1
130
130
  @pipeline = opts[:pipeline] || 0
131
131
 
132
132
  # Check that the URL has been provided:
@@ -275,9 +275,7 @@ module OvirtSDK4
275
275
  def follow_link(object)
276
276
  # Check that the "href" has a value, as it is needed in order to retrieve the representation of the object:
277
277
  href = object.href
278
- if href.nil?
279
- raise Error, "Can't follow link because the 'href' attribute doesn't have a value"
280
- end
278
+ raise Error, "Can't follow link because the 'href' attribute doesn't have a value" if href.nil?
281
279
 
282
280
  # Check that the value of the "href" attribute is compatible with the base URL of the connection:
283
281
  prefix = URI(@url).path
@@ -634,7 +632,7 @@ module OvirtSDK4
634
632
  # parameter. In order to better support those older versions of the engine we need to check if this parameter is
635
633
  # included in the request, and add the corresponding header.
636
634
  unless request.query.nil?
637
- all_content = request.query['all_content']
635
+ all_content = request.query[:all_content]
638
636
  request.headers['All-Content'] = all_content unless all_content.nil?
639
637
  end
640
638
 
@@ -175,7 +175,7 @@ module OvirtSDK4
175
175
  # Get the values of the options specific to this operation:
176
176
  specs.each do |name, kind|
177
177
  value = opts.delete(name)
178
- query[name] = Writer.render(value, kind) if value
178
+ query[name] = Writer.render(value, kind) unless value.nil?
179
179
  end
180
180
 
181
181
  # Check the remaining options:
@@ -224,7 +224,7 @@ module OvirtSDK4
224
224
  # Get the values of the options specific to this operation:
225
225
  specs.each do |name, kind|
226
226
  value = opts.delete(name)
227
- query[name] = Writer.render(value, kind) if value
227
+ query[name] = Writer.render(value, kind) unless value.nil?
228
228
  end
229
229
 
230
230
  # Check the remaining options:
@@ -274,7 +274,7 @@ module OvirtSDK4
274
274
  # Get the values of the options specific to this operation:
275
275
  specs.each do |name, kind|
276
276
  value = opts.delete(name)
277
- query[name] = Writer.render(value, kind) if value
277
+ query[name] = Writer.render(value, kind) unless value.nil?
278
278
  end
279
279
 
280
280
  # Check the remaining options:
@@ -321,7 +321,7 @@ module OvirtSDK4
321
321
  # Get the values of the options specific to this operation:
322
322
  specs.each do |name, kind|
323
323
  value = opts.delete(name)
324
- query[name] = Writer.render(value, kind) if value
324
+ query[name] = Writer.render(value, kind) unless value.nil?
325
325
  end
326
326
 
327
327
  # Check the remaining options:
@@ -407,9 +407,7 @@ module OvirtSDK4
407
407
  def internal_read_body(response)
408
408
  # First check if the response body is empty, as it makes no sense to check the content type if there is
409
409
  # no body:
410
- if response.body.nil? || response.body.length.zero?
411
- connection.raise_error(response, 'The response body is empty')
412
- end
410
+ connection.raise_error(response, 'The response body is empty') if response.body.nil? || response.body.length.zero?
413
411
 
414
412
  # Check the content type, as otherwise the parsing will fail, and the resulting error message won't be explicit
415
413
  # about the cause of the problem:
@@ -16,5 +16,5 @@
16
16
 
17
17
 
18
18
  module OvirtSDK4
19
- VERSION = '4.2.0'.freeze
19
+ VERSION = '4.2.1'.freeze
20
20
  end
@@ -195,9 +195,7 @@ module OvirtSDK4
195
195
  begin
196
196
  if object.is_a?(Array)
197
197
  # For arrays we can't decide which tag to use, so the 'root' parameter is mandatory in this case:
198
- if root.nil?
199
- raise Error, "The 'root' option is mandatory when writing arrays"
200
- end
198
+ raise Error, "The 'root' option is mandatory when writing arrays" if root.nil?
201
199
 
202
200
  # Write the root tag, and then recursively call the method to write each of the items of the array:
203
201
  cursor.write_start(root)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ovirt-engine-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.2.0
4
+ version: 4.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Juan Hernandez
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-12-04 00:00:00.000000000 Z
11
+ date: 2017-12-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -151,7 +151,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
151
151
  requirements:
152
152
  - - ">="
153
153
  - !ruby/object:Gem::Version
154
- version: '2.0'
154
+ version: '2.1'
155
155
  required_rubygems_version: !ruby/object:Gem::Requirement
156
156
  requirements:
157
157
  - - ">="