cloudstack_client 1.5.11 → 1.6.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f12a44b9de9caef1d8ca803d2661fbf236b45428b00e9a9e88f222c630aee140
4
- data.tar.gz: 90e786e18f99f3a6fcb19b94298d617f42d18d8892722e288da76891945bf9b3
3
+ metadata.gz: 99f564bf41bdccf82b53c267179080034a91d8ab0650b164c8099a6e4cdba289
4
+ data.tar.gz: 79fc42e2f3dcef1ae5111edc9e19d70158e42c444d2814f5a637d4de4e8612bb
5
5
  SHA512:
6
- metadata.gz: 92cd5f09d2864d21556c524262ce2187ded3a28c65c1a324bc7a8a236d98e0f44261bb0a334b879955efdc0e1065c58235bf7c6077fd1635d2bad8657ec70308
7
- data.tar.gz: 11a672cd0b5f2dbd377a0e4684a1a71c090ddb29e4b90b1e938f87c3eac1df638bb22d49570830442af687aa197fa7bfea3fbbf7de453aaa0e008ddd5d1e6345
6
+ metadata.gz: 76fadda1e05ea7b8083323bd780bd8ac876e29a3f807d8e2486a1142dd6f88d4f8ef71dfececb105c4f180f8cf4650bfad113eb9483048762df6b5c9aac42669
7
+ data.tar.gz: a140a1f97df576782796745c7f64a012b9be86a355f48cd50a223765889cce489c2cb8698cbed70ee4d7479c25c88ded4b45540148282ff636e8c753028ed943
@@ -0,0 +1,32 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ test:
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ ruby-version: ['3.2', '3.3']
17
+
18
+ steps:
19
+ - name: Checkout repository
20
+ uses: actions/checkout@v4
21
+
22
+ - name: Set up Ruby
23
+ uses: ruby/setup-ruby@v1
24
+ with:
25
+ ruby-version: ${{ matrix.ruby-version }}
26
+ bundler-cache: true
27
+
28
+ - name: Run tests
29
+ run: bundle exec rake test
30
+
31
+ - name: Build gem
32
+ run: bundle exec rake build
@@ -0,0 +1,62 @@
1
+ name: Release
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ push:
7
+ branches: [ "main" ]
8
+
9
+ permissions:
10
+ contents: write
11
+ id-token: write
12
+
13
+ jobs:
14
+ verify:
15
+ runs-on: ubuntu-latest
16
+
17
+ steps:
18
+ - name: Checkout repository
19
+ uses: actions/checkout@v4
20
+
21
+ - name: Set up Ruby
22
+ uses: ruby/setup-ruby@v1
23
+ with:
24
+ ruby-version: '3.2'
25
+ bundler-cache: true
26
+
27
+ - name: Run tests
28
+ run: bundle exec rake test
29
+
30
+ - name: Ensure version is bumped
31
+ run: |
32
+ CURRENT_VERSION="$(ruby -Ilib -e "require 'cloudstack_client/version'; puts CloudstackClient::VERSION")"
33
+ LATEST_JSON="$(curl -fsSL https://rubygems.org/api/v1/versions/cloudstack_client/latest.json || true)"
34
+ if [ -n "$LATEST_JSON" ]; then
35
+ LATEST_VERSION="$(printf '%s' "$LATEST_JSON" | ruby -rjson -e "puts JSON.parse(STDIN.read)['version']")"
36
+ ruby -e "require 'rubygems/version'; current = Gem::Version.new('$CURRENT_VERSION'); latest = Gem::Version.new('$LATEST_VERSION'); abort(\"Version must be bumped before building (current=#{current}, latest=#{latest})\") unless current > latest"
37
+ fi
38
+
39
+ - name: Build gem
40
+ run: bundle exec rake build
41
+
42
+ publish:
43
+ runs-on: ubuntu-latest
44
+ needs: verify
45
+ environment: rubygems
46
+
47
+
48
+
49
+ steps:
50
+ - name: Checkout repository
51
+ uses: actions/checkout@v4
52
+
53
+ - name: Set up Ruby
54
+ uses: ruby/setup-ruby@v1
55
+ with:
56
+ ruby-version: '3.2'
57
+ bundler-cache: true
58
+
59
+ - name: Publish gem to RubyGems
60
+ uses: rubygems/release-gem@v1
61
+ with:
62
+ api-key: ${{ secrets.RUBYGEMS_AUTH_TOKEN }}
data/.travis.yml CHANGED
@@ -1,7 +1,8 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.7
4
- - 3.0
3
+ - 3.2
4
+ - 3.4
5
+ - 4.0
5
6
  before_install:
6
7
  - gem update --system
7
8
  - gem install bundler
data/Gemfile.lock CHANGED
@@ -1,17 +1,17 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cloudstack_client (1.5.11)
4
+ cloudstack_client (1.6.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
9
  bond (0.5.1)
10
- minitest (5.26.1)
11
- rake (13.3.1)
10
+ minitest (5.27.0)
11
+ rake (13.4.1)
12
12
  ripl (0.7.1)
13
13
  bond (~> 0.5.1)
14
- thor (1.4.0)
14
+ thor (1.5.0)
15
15
 
16
16
  PLATFORMS
17
17
  x86_64-linux
@@ -24,4 +24,4 @@ DEPENDENCIES
24
24
  thor (~> 1.1)
25
25
 
26
26
  BUNDLED WITH
27
- 2.5.22
27
+ 2.6.9
data/README.md CHANGED
@@ -1,7 +1,6 @@
1
1
  # cloudstack_client
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/cloudstack_client.png)](http://badge.fury.io/rb/cloudstack_client)
4
- [![Build Status](https://travis-ci.com/niwo/cloudstack_client.svg?branch=master)](https://travis-ci.com/niwo/cloudstack_client)
5
4
 
6
5
  A CloudStack API client written in Ruby.
7
6
 
@@ -120,17 +119,26 @@ test:
120
119
  ```
121
120
 
122
121
  ### Configuration options
122
+
123
123
  You can pass `options` as 4th argument in `CloudstackClient::Client.new`. All its keys are optional.
124
124
 
125
125
  ```ruby
126
126
  options = {
127
127
  symbolize_keys: true, # pass symbolize_names: true in JSON#parse for Cloudstack responses, default: false
128
128
  host: 'localhost', # custom host header to be used in Net::Http. May be useful when Cloudstack is set up locally via docker (i.e. Cloudstack-simulator), default: parsed from config[:url] via Net::Http
129
- read_timeout: 10 # timeout in seconds of a connection to the Cloudstack, default: 60
129
+ read_timeout: 10, # timeout in seconds of a connection to the Cloudstack, default: 60
130
+ request_retries: 3 # number of attempts for HTTP requests before raising a ConnectionError, default: 1 (no retries). Uses incremental back-off between attempts.
130
131
  }
131
132
  cs = CloudstackClient::Client.new(config[:url], config[:api_key], config[:secret_key], options)
132
133
  ```
133
134
 
135
+ For a single call you can override defaults on the **second** hash (client options), without changing the client instance:
136
+
137
+ ```ruby
138
+ cs.deploy_virtual_machine({ zoneid: "...", serviceofferingid: "...", templateid: "..." },
139
+ async_timeout: 600, async_poll_interval: 5)
140
+ ```
141
+
134
142
  ### Interactive Console
135
143
 
136
144
  cloudstack_client comes with an interactive console.
@@ -156,6 +164,19 @@ $ cloudstack_client list_apis > data/4.15.json
156
164
  $ gzip data/4.15.json
157
165
  ```
158
166
 
167
+ ### GitHub Actions
168
+
169
+ This repository includes GitHub Actions workflows for:
170
+
171
+ - Running tests and gem build on every push and pull request (`CI`)
172
+ - Publishing the gem to RubyGems when a GitHub Release is published (`Release`)
173
+
174
+ To enable publishing, add this repository secret:
175
+
176
+ - `RUBYGEMS_AUTH_TOKEN`: your RubyGems API key with push permissions
177
+
178
+ The release workflow checks that `CloudstackClient::VERSION` is greater than the latest version on RubyGems before building, then uses the `rubygems` environment to publish.
179
+
159
180
  ## References
160
181
 
161
182
  - [Apache CloudStack API documentation](http://cloudstack.apache.org/api/apidocs-4.15/)
@@ -10,11 +10,12 @@ module CloudstackClient
10
10
  include Utils
11
11
 
12
12
  attr_accessor :api_url, :api_key, :secret_key, :verbose, :debug, :symbolize_keys, :host, :read_timeout
13
- attr_accessor :async_poll_interval, :async_timeout
13
+ attr_accessor :async_poll_interval, :async_timeout, :request_retries
14
14
 
15
15
  DEF_POLL_INTERVAL = 2.0
16
16
  DEF_ASYNC_TIMEOUT = 400
17
17
  DEF_REQ_TIMEOUT = 60
18
+ DEF_REQUEST_RETRIES = 1
18
19
 
19
20
  def initialize(api_url, api_key, secret_key, options = {})
20
21
  @api_url = api_url
@@ -27,6 +28,7 @@ module CloudstackClient
27
28
  @read_timeout = options[:read_timeout] || DEF_REQ_TIMEOUT
28
29
  @async_poll_interval = options[:async_poll_interval] || DEF_POLL_INTERVAL
29
30
  @async_timeout = options[:async_timeout] || DEF_ASYNC_TIMEOUT
31
+ @request_retries = options[:request_retries] || DEF_REQUEST_RETRIES
30
32
  @options = options
31
33
  validate_input!
32
34
  end
@@ -50,12 +52,19 @@ module CloudstackClient
50
52
  end
51
53
  http.read_timeout = @read_timeout
52
54
 
55
+ retries = 0
53
56
  begin
54
57
  req = Net::HTTP::Get.new(uri.request_uri)
55
58
  req['Host'] = host if host.present?
56
59
  response = http.request(req)
57
- rescue
58
- raise ConnectionError, "API URL \'#{@api_url}\' is not reachable."
60
+ rescue => e
61
+ retries += 1
62
+ if retries < @request_retries
63
+ sleep(retries) # incremental back-off
64
+ print "." if @verbose
65
+ retry
66
+ end
67
+ raise ConnectionError, "API URL \'#{@api_url}\' is not reachable (after #{retries} attempt#{'s' if retries > 1}): #{e.message}"
59
68
  end
60
69
 
61
70
  begin
@@ -87,7 +96,11 @@ module CloudstackClient
87
96
  #
88
97
  # The contents of the 'jobresult' element are returned upon completion of the command.
89
98
 
90
- def send_async_request(params, **opts)
99
+ def send_async_request(params, opts = {})
100
+ request_timeout = opts[:async_timeout] || @async_timeout
101
+ poll_interval = opts[:async_poll_interval] || @async_poll_interval
102
+ validate_async_timeouts!(request_timeout, poll_interval)
103
+
91
104
  data = send_request(params, opts)
92
105
 
93
106
  params = {
@@ -95,7 +108,7 @@ module CloudstackClient
95
108
  'jobid' => data[k('jobid')]
96
109
  }
97
110
 
98
- max_tries.times do
111
+ max_tries(request_timeout, poll_interval).times do
99
112
  data = send_request(params)
100
113
  print "." if @verbose
101
114
 
@@ -107,7 +120,7 @@ module CloudstackClient
107
120
  end
108
121
 
109
122
  STDOUT.flush if @verbose
110
- sleep @async_poll_interval
123
+ sleep poll_interval
111
124
  end
112
125
 
113
126
  raise TimeoutError, "Asynchronous request timed out."
@@ -119,8 +132,13 @@ module CloudstackClient
119
132
  raise InputError, "API URL not set." if @api_url == nil
120
133
  raise InputError, "API KEY not set." if @api_key == nil
121
134
  raise InputError, "API SECRET KEY not set." if @secret_key == nil
122
- raise InputError, "ASYNC POLL INTERVAL must be at least 1." if @async_poll_interval < 1.0
123
- raise InputError, "ASYNC TIMEOUT must be at least 60." if @async_timeout < 60
135
+ validate_async_timeouts!(@async_timeout, @async_poll_interval)
136
+ raise InputError, "REQUEST RETRIES must be at least 1." if @request_retries < 1
137
+ end
138
+
139
+ def validate_async_timeouts!(timeout, interval)
140
+ raise InputError, "ASYNC POLL INTERVAL must be at least 1." if interval < 1.0
141
+ raise InputError, "ASYNC TIMEOUT must be at least 60." if timeout < 60
124
142
  end
125
143
 
126
144
  def params_to_data(params)
@@ -150,8 +168,8 @@ module CloudstackClient
150
168
  CGI.escape(signature)
151
169
  end
152
170
 
153
- def max_tries
154
- (@async_timeout / @async_poll_interval).round
171
+ def max_tries(timeout, interval)
172
+ (timeout / interval).round
155
173
  end
156
174
 
157
175
  def escape(input)
@@ -1,3 +1,3 @@
1
1
  module CloudstackClient
2
- VERSION = "1.5.11"
2
+ VERSION = "1.6.0"
3
3
  end
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cloudstack_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.11
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nik Wolfgramm
8
+ autorequire:
8
9
  bindir: bin
9
10
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
11
+ date: 2026-04-16 00:00:00.000000000 Z
11
12
  dependencies:
12
13
  - !ruby/object:Gem::Dependency
13
14
  name: rake
@@ -73,6 +74,8 @@ executables:
73
74
  extensions: []
74
75
  extra_rdoc_files: []
75
76
  files:
77
+ - ".github/workflows/ci.yml"
78
+ - ".github/workflows/release.yml"
76
79
  - ".gitignore"
77
80
  - ".travis.yml"
78
81
  - Gemfile
@@ -105,6 +108,7 @@ homepage: https://github.com/niwo/cloudstack_client
105
108
  licenses:
106
109
  - MIT
107
110
  metadata: {}
111
+ post_install_message:
108
112
  rdoc_options:
109
113
  - "--line-numbers"
110
114
  - "--inline-source"
@@ -121,7 +125,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
121
125
  - !ruby/object:Gem::Version
122
126
  version: '0'
123
127
  requirements: []
124
- rubygems_version: 3.6.9
128
+ rubygems_version: 3.4.19
129
+ signing_key:
125
130
  specification_version: 4
126
131
  summary: CloudStack API client written in Ruby
127
132
  test_files: