hcloud 0.1.0.pre.alpha4 → 0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e4dbd2d5d61d5bbe1fce20502673f677a67faf33
4
- data.tar.gz: 0ddfe0a2a9a06490c46e843b6ada4a38ab269ceb
3
+ metadata.gz: 42e5e0786794e6040e88021aeec5ea8d0c3da4d8
4
+ data.tar.gz: b2368e1557cecb9e16089cc9a850979b85faae7e
5
5
  SHA512:
6
- metadata.gz: 3e60745c5f5d8692370d00bcab67ec354b2aa7bef9507417851713c58b687c61d274a039ae89635f1f0a4872fb5a376ab03f39fb3878d63f83b8d577f7faf4fe
7
- data.tar.gz: 14ef3b03e95390258c8f1efc42586e97b6624b152cc61278b0f1b3c9cdffbd5fc79c8dd73228bd8df31df0ae3c4ceac1ffdb84ffbcb3364b13b64b8295b973e9
6
+ metadata.gz: 0e885d2e44be9a4bc6750b55c859de56d02059de3611c63c684f7bff51931f8d8ba677f430e7b74fa48b7f1adea837cefd0fb2607d209682b3ba81035b426b41
7
+ data.tar.gz: b582dc6e91e9dccb04cc5469d83a28795f55d3f7ce7d5da0826fe6c8035a58bbc89ef17cf2163b164a1577c6aba4fde4b0d03b6eb325b2a0cca87efd0a4b0f03
data/.gitignore CHANGED
@@ -1,5 +1,6 @@
1
1
  /.bundle/
2
2
  /vendor
3
+ config.ru
3
4
  /.yardoc
4
5
  /Gemfile.lock
5
6
  /_yardoc/
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format=documentation
2
+ --color
3
+ --tty
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ script: "bundle exec rspec"
3
+ sudo: false
4
+ rvm:
5
+ - 2.3
6
+ - 2.4
7
+ - 2.5
data/Gemfile CHANGED
@@ -3,6 +3,7 @@ source "https://rubygems.org"
3
3
  git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
4
 
5
5
  gem 'pry'
6
+ gem 'codecov', :require => false, :group => :test
6
7
 
7
8
  # Specify your gem's dependencies in hcloud.gemspec
8
9
  gemspec
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # Hcloud
2
2
 
3
+ [![Build Status](https://travis-ci.org/tonobo/hcloud-ruby.svg?branch=master)](https://travis-ci.org/tonobo/hcloud-ruby)
4
+ [![codecov](https://codecov.io/gh/tonobo/hcloud-ruby/branch/master/graph/badge.svg)](https://codecov.io/gh/tonobo/hcloud-ruby)
5
+
3
6
  This is an unoffical ruby client for HetznerCloud Api service.
4
7
 
5
8
  **Its currently in development and lacking a lot of feature.
@@ -43,11 +46,29 @@ end
43
46
 
44
47
  * Create a server
45
48
 
49
+ Nonblocking:
50
+
46
51
  ```ruby
47
52
  c.servers.create(name: "moo5", server_type: "cx11", image: "ubuntu-16.04")
48
53
  #=> [#<Hcloud::Action>, <#Hcloud::Server>, "root_password"]
49
54
  ```
50
55
 
56
+ Wating for finish:
57
+
58
+ ```ruby
59
+ action,server = c.servers.create(name: "moo5", server_type: "cx11", image: "ubuntu-16.04")
60
+
61
+ while action.status == "running"
62
+ puts "Waiting for Action #{action.id} to complete ..."
63
+ action = c.actions.find(action.id)
64
+ server = c.servers.find(server.id)
65
+ puts "Action Status: #{action.status}"
66
+ puts "Server Status: #{server.status}"
67
+ puts "Server IP Config: #{server.public_net["ipv4"]}"
68
+ sleep 5
69
+ end
70
+ ```
71
+
51
72
  * Update servers' name
52
73
 
53
74
  ```ruby
@@ -21,6 +21,10 @@ Gem::Specification.new do |spec|
21
21
 
22
22
  spec.add_development_dependency "bundler", "~> 1.15"
23
23
  spec.add_development_dependency "rake", "~> 10.0"
24
+ spec.add_development_dependency "grape"
25
+ spec.add_development_dependency "activesupport"
26
+ spec.add_development_dependency "rspec"
27
+ spec.add_development_dependency "webmock"
24
28
  spec.add_runtime_dependency "typhoeus"
25
29
  spec.add_runtime_dependency "oj"
26
30
  spec.add_runtime_dependency "activesupport"
@@ -5,6 +5,7 @@ module Hcloud
5
5
  autoload :Error, 'hcloud/errors'
6
6
  autoload :Client, 'hcloud/client'
7
7
  autoload :AbstractResource, 'hcloud/abstract_resource'
8
+ autoload :MultiReply, 'hcloud/multi_reply'
8
9
  autoload :ServerResource, 'hcloud/server_resource'
9
10
  autoload :EntryLoader, 'hcloud/entry_loader'
10
11
  autoload :FloatingIP, 'hcloud/floating_ip'
@@ -24,4 +25,5 @@ module Hcloud
24
25
  autoload :ActionResource, 'hcloud/action_resource'
25
26
  autoload :Iso, 'hcloud/iso'
26
27
  autoload :IsoResource, 'hcloud/iso_resource'
28
+ autoload :Pagination, 'hcloud/pagination'
27
29
  end
@@ -1,12 +1,66 @@
1
1
  module Hcloud
2
2
  class AbstractResource
3
+ include Enumerable
4
+
3
5
  attr_reader :client, :parent, :base_path
4
6
 
5
7
  def initialize(client:, parent: nil, base_path: "")
6
8
  @client = client
7
9
  @parent = parent
10
+ @page = 1
11
+ @per_page = 25
12
+ @order = []
8
13
  @base_path = base_path
9
14
  end
15
+
16
+ def page(page)
17
+ @page = page
18
+ self
19
+ end
20
+
21
+ def per_page(per_page)
22
+ @per_page = per_page
23
+ self
24
+ end
25
+
26
+ def limit(limit)
27
+ @limit = limit
28
+ self
29
+ end
30
+
31
+ def order(*sort)
32
+ @order = sort.flat_map do |s|
33
+ case s
34
+ when Symbol, String then s.to_s
35
+ when Hash then s.map { |k, v| "#{k}:#{v}" }
36
+ else
37
+ raise ArgumentError,
38
+ "Unable to resolve type for given #{s.inspect} from #{sort}"
39
+ end
40
+ end
41
+ self
42
+ end
43
+
44
+ def mj(path, **o, &block)
45
+ if !client.nil? and client.auto_pagination
46
+ requests = __entries__(path, **o)
47
+ if requests.all?{|x| x.is_a? Hash }
48
+ m = MultiReply.new(j: requests, pagination: :auto)
49
+ m.cb = block
50
+ return m
51
+ end
52
+ client.hydra.run
53
+ j = requests.map do |x|
54
+ Oj.load(x.response.body)
55
+ end
56
+ m = MultiReply.new(j: j, pagination: :auto)
57
+ m.cb = block
58
+ return m
59
+ end
60
+ m = MultiReply.new(j: [Oj.load(request(path, o.merge(ep: ep)).run.body)])
61
+ m.cb = block
62
+ m
63
+ end
10
64
 
11
65
  def each(&block)
12
66
  all.each do |member|
@@ -16,8 +70,44 @@ module Hcloud
16
70
 
17
71
  protected
18
72
 
73
+ def page_params(per_page: nil, page: nil)
74
+ { per_page: per_page || @per_page, page: page || @page }.to_param
75
+ end
76
+
77
+ def sort_params
78
+ @order.to_a.map{|x| "sort=#{x}" }.join("&")
79
+ end
80
+
81
+ def ep(per_page: nil, page: nil)
82
+ r = []
83
+ (x = page_params(per_page: per_page, page: page)).empty? ? nil : r << x
84
+ (x = sort_params).empty? ? nil : r << x
85
+ r.compact.join("&")
86
+ end
87
+
19
88
  def request(*args)
20
89
  client.request(*args)
21
90
  end
91
+
92
+ def __entries__(path, **o)
93
+ ret = Oj.load(request(path, o.merge(ep: ep(per_page: 1, page: 1))).run.body)
94
+ a = ret.dig("meta", "pagination", "total_entries").to_i
95
+ if a <= 1
96
+ return [ret]
97
+ end
98
+ unless @limit.nil?
99
+ a = @limit if a > @limit
100
+ end
101
+ r = a / Client::MAX_ENTRIES_PER_PAGE + (a % Client::MAX_ENTRIES_PER_PAGE)
102
+ requests = r.times.map do |i|
103
+ per_page = Client::MAX_ENTRIES_PER_PAGE
104
+ if !@limit.nil? and r == (i+1) and a % per_page != 0
105
+ per_page = a % per_page
106
+ end
107
+ req = request(path, o.merge(ep: ep(per_page: per_page, page: i+1)))
108
+ client.hydra.queue req
109
+ req
110
+ end
111
+ end
22
112
  end
23
113
  end
@@ -1,14 +1,12 @@
1
1
 
2
2
  module Hcloud
3
3
  class ActionResource < AbstractResource
4
- include Enumerable
5
-
6
- def all(sort: nil)
7
- Oj.load(request(base_path("actions"), q: {sort: sort}).run.body)["actions"].map do |x|
8
- Action.new(x, self, client)
4
+ def all
5
+ mj(base_path("actions")) do |j|
6
+ j.flat_map{|x| x["actions"].map{ |x| Action.new(x, self, client) } }
9
7
  end
10
8
  end
11
-
9
+
12
10
  def find(id)
13
11
  Action.new(
14
12
  Oj.load(request(base_path("actions/#{id.to_i}")).run.body)["action"],
@@ -22,12 +20,9 @@ module Hcloud
22
20
  rescue Error::NotFound
23
21
  end
24
22
 
25
- def where(status: nil, sort: nil)
26
- Oj.load(
27
- request(base_path("actions"),
28
- q: {status: status, sort: sort}).run.body
29
- )["actions"].map do |x|
30
- Action.new(x, self, client)
23
+ def where(status: nil)
24
+ mj(base_path("actions"), q: {status: status}) do |j|
25
+ j.flat_map{|x| x["actions"].map{ |x| Action.new(x, self, client) }}
31
26
  end
32
27
  end
33
28
 
@@ -3,9 +3,14 @@ autoload :Oj, "oj"
3
3
 
4
4
  module Hcloud
5
5
  class Client
6
- attr_reader :token
7
- def initialize(token:)
6
+ MAX_ENTRIES_PER_PAGE = 50
7
+
8
+ attr_reader :token, :auto_pagination, :hydra
9
+ def initialize(token:, auto_pagination: false, concurrency: 20)
8
10
  @token = token
11
+ @auto_pagination = auto_pagination
12
+ @concurrency = concurrency
13
+ @hydra = Typhoeus::Hydra.new(max_concurrency: concurrency)
9
14
  end
10
15
 
11
16
  def authorized?
@@ -57,9 +62,13 @@ module Hcloud
57
62
  options[:body] = Oj.dump(x, mode: :compat)
58
63
  options[:method] ||= :post
59
64
  end
65
+ q = []
66
+ q << options.delete(:ep).to_s
60
67
  if x = options.delete(:q)
61
- path << "?"+x.to_param
68
+ q << x.to_param
62
69
  end
70
+ path = path.dup
71
+ path << "?"+q.join("&")
63
72
  r = Typhoeus::Request.new(
64
73
  "https://api.hetzner.cloud/v1/#{path}",
65
74
  {
@@ -34,7 +34,7 @@ module Hcloud
34
34
  )
35
35
  end
36
36
 
37
- def destory
37
+ def destroy
38
38
  request("images/#{id.to_i}", method: :delete).run
39
39
  true
40
40
  end
@@ -1,10 +1,8 @@
1
1
  module Hcloud
2
2
  class ImageResource < AbstractResource
3
- include Enumerable
4
-
5
3
  def all
6
- Oj.load(request("images").run.body)["images"].map do |x|
7
- Image.new(x, self, client)
4
+ mj("images") do |j|
5
+ j.flat_map{|x| x["images"].map{ |x| Image.new(x, self, client) } }
8
6
  end
9
7
  end
10
8
 
@@ -33,10 +31,8 @@ module Hcloud
33
31
  method(:where).parameters.inject(query) do |r,x|
34
32
  (var = eval(x.last.to_s)).nil? ? r : r.merge!(x.last => var)
35
33
  end
36
- Oj.load(
37
- request("images", q: query).run.body
38
- )["images"].map do |x|
39
- Image.new(x, self, client)
34
+ mj("images", q: query) do |j|
35
+ j.flat_map{|x| x["images"].map{ |x| Image.new(x, self, client) } }
40
36
  end
41
37
  end
42
38
 
@@ -1,10 +1,8 @@
1
1
  module Hcloud
2
2
  class IsoResource < AbstractResource
3
- include Enumerable
4
-
5
3
  def all
6
- Oj.load(request("isos").run.body)["isos"].map do |x|
7
- Iso.new(x, self, client)
4
+ mj("isos") do |j|
5
+ j.flat_map{|x| x["isos"].map{ |x| Iso.new(x, self, client) } }
8
6
  end
9
7
  end
10
8
 
@@ -1,10 +1,9 @@
1
1
  module Hcloud
2
2
  class LocationResource < AbstractResource
3
- include Enumerable
4
-
5
3
  def all
6
- j = Oj.load(request("locations").run.body)
7
- j["locations"].map{|x| Location.new(x, self, client) }
4
+ mj("locations") do |j|
5
+ j.flat_map{|x| x["locations"].map{ |x| Location.new(x, self, client) } }
6
+ end
8
7
  end
9
8
 
10
9
  def find(id)
@@ -0,0 +1,22 @@
1
+ module Hcloud
2
+ class MultiReply
3
+ include Enumerable
4
+ attr_accessor :cb
5
+
6
+ def initialize(j:, pagination: nil)
7
+ @j = j
8
+ @pagination = pagination
9
+ end
10
+
11
+ def pagination
12
+ @pagination || Pagination.new(@j.first.to_h["meta"].to_h["pagination"], nil, nil)
13
+ end
14
+
15
+ def each(&block)
16
+ @cb.call(@j).each do |member|
17
+ block.call(member)
18
+ end
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,14 @@
1
+ module Hcloud
2
+ class Pagination
3
+ Attributes = {
4
+ page: nil,
5
+ per_page: nil,
6
+ previous_page: nil,
7
+ next_page: nil,
8
+ last_page: nil,
9
+ total_entries: nil,
10
+ }
11
+
12
+ include EntryLoader
13
+ end
14
+ end
@@ -1,7 +1,5 @@
1
1
  module Hcloud
2
2
  class ServerResource < AbstractResource
3
- include Enumerable
4
-
5
3
  def create(name:,
6
4
  server_type:,
7
5
  datacenter: nil,
@@ -23,8 +21,8 @@ module Hcloud
23
21
  end
24
22
 
25
23
  def all
26
- Oj.load(request("servers").run.body)["servers"].map do |x|
27
- Server.new(x, self, client)
24
+ mj("servers") do |j|
25
+ j.flat_map{|x| x["servers"].map{ |x| Server.new(x, self, client) } }
28
26
  end
29
27
  end
30
28
 
@@ -1,15 +1,14 @@
1
1
  module Hcloud
2
2
  class SSHKeyResource < AbstractResource
3
- include Enumerable
4
-
5
3
  def all
6
- j = Oj.load(request("ssh_keys").run.body)
7
- j["ssh_keys"].map{|x| SSHKey.new(x, self, client) }
4
+ mj("ssh_keys") do |j|
5
+ j.flat_map{|x| x["ssh_keys"].map{ |x| SSHKey.new(x, self, client) } }
6
+ end
8
7
  end
9
8
 
10
9
  def create(name:, public_key:)
11
10
  j = Oj.load(request("ssh_keys", j: {name: name, public_key: public_key}).run.body)
12
- SSHKey.new(j, self, client)
11
+ SSHKey.new(j["ssh_key"], self, client)
13
12
  end
14
13
 
15
14
  def find(id)
@@ -1,3 +1,3 @@
1
1
  module Hcloud
2
- VERSION = "0.1.0-alpha4"
2
+ VERSION = "0.1.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hcloud
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.pre.alpha4
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Foerster
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-01-30 00:00:00.000000000 Z
11
+ date: 2018-02-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -38,6 +38,62 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: grape
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: activesupport
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: webmock
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
41
97
  - !ruby/object:Gem::Dependency
42
98
  name: typhoeus
43
99
  requirement: !ruby/object:Gem::Requirement
@@ -88,6 +144,8 @@ extensions: []
88
144
  extra_rdoc_files: []
89
145
  files:
90
146
  - ".gitignore"
147
+ - ".rspec"
148
+ - ".travis.yml"
91
149
  - Gemfile
92
150
  - README.md
93
151
  - Rakefile
@@ -111,6 +169,8 @@ files:
111
169
  - lib/hcloud/iso_resource.rb
112
170
  - lib/hcloud/location.rb
113
171
  - lib/hcloud/location_resource.rb
172
+ - lib/hcloud/multi_reply.rb
173
+ - lib/hcloud/pagination.rb
114
174
  - lib/hcloud/server.rb
115
175
  - lib/hcloud/server_resource.rb
116
176
  - lib/hcloud/server_type.rb
@@ -132,9 +192,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
132
192
  version: '0'
133
193
  required_rubygems_version: !ruby/object:Gem::Requirement
134
194
  requirements:
135
- - - ">"
195
+ - - ">="
136
196
  - !ruby/object:Gem::Version
137
- version: 1.3.1
197
+ version: '0'
138
198
  requirements: []
139
199
  rubyforge_project:
140
200
  rubygems_version: 2.5.2.2