lunanode 0.1.5

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.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +16 -0
  3. data/.gitignore +13 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +94 -0
  6. data/.ruby-gemset +1 -0
  7. data/.ruby-version +1 -0
  8. data/.travis.yml +11 -0
  9. data/.yardopts +1 -0
  10. data/CODE_OF_CONDUCT.md +74 -0
  11. data/Gemfile +5 -0
  12. data/LICENSE.txt +21 -0
  13. data/README.md +50 -0
  14. data/Rakefile +19 -0
  15. data/bin/console +8 -0
  16. data/bin/setup +8 -0
  17. data/lib/lunanode.rb +12 -0
  18. data/lib/lunanode/action_generator.rb +105 -0
  19. data/lib/lunanode/api.rb +172 -0
  20. data/lib/lunanode/api_actions.rb +41 -0
  21. data/lib/lunanode/api_actions/default/dns.rb +55 -0
  22. data/lib/lunanode/api_actions/default/email.rb +59 -0
  23. data/lib/lunanode/api_actions/default/floating.rb +19 -0
  24. data/lib/lunanode/api_actions/default/image.rb +31 -0
  25. data/lib/lunanode/api_actions/default/lb.rb +35 -0
  26. data/lib/lunanode/api_actions/default/monitor.rb +47 -0
  27. data/lib/lunanode/api_actions/default/network.rb +19 -0
  28. data/lib/lunanode/api_actions/default/plan.rb +11 -0
  29. data/lib/lunanode/api_actions/default/region.rb +11 -0
  30. data/lib/lunanode/api_actions/default/script.rb +11 -0
  31. data/lib/lunanode/api_actions/default/securitygroup.rb +35 -0
  32. data/lib/lunanode/api_actions/default/vm.rb +99 -0
  33. data/lib/lunanode/api_actions/default/volume.rb +47 -0
  34. data/lib/lunanode/api_actions/dns.rb +10 -0
  35. data/lib/lunanode/api_actions/email.rb +10 -0
  36. data/lib/lunanode/api_actions/floating.rb +10 -0
  37. data/lib/lunanode/api_actions/image.rb +17 -0
  38. data/lib/lunanode/api_actions/lb.rb +10 -0
  39. data/lib/lunanode/api_actions/monitor.rb +10 -0
  40. data/lib/lunanode/api_actions/network.rb +10 -0
  41. data/lib/lunanode/api_actions/plan.rb +10 -0
  42. data/lib/lunanode/api_actions/region.rb +10 -0
  43. data/lib/lunanode/api_actions/script.rb +10 -0
  44. data/lib/lunanode/api_actions/securitygroup.rb +10 -0
  45. data/lib/lunanode/api_actions/vm.rb +10 -0
  46. data/lib/lunanode/api_actions/volume.rb +10 -0
  47. data/lib/lunanode/api_error.rb +5 -0
  48. data/lib/lunanode/version.rb +4 -0
  49. data/lunanode.gemspec +33 -0
  50. data/lunanode_api_def.yaml +391 -0
  51. metadata +191 -0
@@ -0,0 +1,172 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "rest-client"
5
+
6
+ module Lunanode
7
+ # Class for accessing the Lunanode API.
8
+ #
9
+ # The class is instantiated by either passing it a JSON file containing
10
+ # the keys `api_id` and `api_key`, or specifying the ID and key directly:
11
+ # api = Lunanode::API.new("credentials_file.json")
12
+ # api = Lunanode::API.new(api_id: "ABCDEFG", api_key: "HIJKLMNOP")
13
+ #
14
+ # Once instantiated, action methods follow the example:
15
+ # api.vm_list # no parameters
16
+ # api.vm_info(vm_id: "My-VM-ID") # required parameters
17
+ # api.image_list(region: "Toronto") # optional parameters
18
+ #
19
+ # Required and optional arguments are specified in the method definitions,
20
+ # but can can be queried via {API.params_for}. They follow the API
21
+ # specification athttps://wiki.lunanode.com/index.php/API
22
+ #
23
+ class API
24
+ #
25
+ # Class-level definitions
26
+ #
27
+
28
+ API_ENDPOINT = "https://dynamic.lunanode.com/api/".freeze
29
+ @params_for = {}
30
+
31
+ # Show parameter info for any API method.
32
+ #
33
+ # @param method_name[#to_sym] The name of the API method
34
+ # @return [Hash] information about the method parameters
35
+ #
36
+ def self.params_for(method_name)
37
+ @params_for[method_name] ||= begin
38
+ method_name = method_name.to_sym
39
+ param_groups = instance_method(method_name).parameters.group_by(&:first)
40
+ out = {
41
+ required: param_groups[:keyreq] && param_group[:keyreq].map(&:last),
42
+ optional: param_groups[:key] && param_groups[:key].map(&:last),
43
+ additional: param_groups.key?(:keyrest),
44
+ }
45
+ out.each do |k, v|
46
+ if v
47
+ v.freeze
48
+ else
49
+ out.delete(k)
50
+ end
51
+ end
52
+ out.freeze
53
+ end
54
+ end
55
+
56
+ #
57
+ # Instance-level definitions
58
+ #
59
+
60
+ include APIActions
61
+ attr_reader :api_id
62
+
63
+ # @overload initialize(credentials_file)
64
+ # Instantiate an API object from a credentials file.
65
+ # @param credentials_file[IO,String] a JSON credentials file
66
+ # (which contains the keys `api_id` and `api_key`)
67
+ #
68
+ # @overload initialize(api_id: nil, api_key: nil)
69
+ # Instantiate an API object from an API ID and API Key.
70
+ # @param api_id[String] A LunaNode API ID
71
+ # @param api_key[String] A LunaNode API Key
72
+ #
73
+ def initialize(credentials_file = nil, api_id: nil, api_key: nil)
74
+ if !credentials_file.nil? && File.exist?(credentials_file)
75
+ credentials_data = File.read(credentials_file)
76
+ credentials = JSON.parse(credentials_data, symbolize_names: true)
77
+ @api_id = credentials[:api_id]
78
+ @api_key = credentials[:api_key]
79
+ else
80
+ @api_id = api_id
81
+ @api_key = api_key
82
+ end
83
+ @api_id = @api_id.to_s.freeze
84
+ @api_key = @api_key.to_s.freeze
85
+ @rest_client = RestClient::Resource.new(
86
+ API_ENDPOINT,
87
+ verify_ssl: OpenSSL::SSL::VERIFY_PEER
88
+ )
89
+ end
90
+
91
+ # Display a string representation of the object without key information.
92
+ def inspect
93
+ "#<#{self.class.name}: api_id=#{api_id.inspect}>"
94
+ end
95
+ alias to_s inspect
96
+
97
+ # Send an arbitrary API action without any parameter checks.
98
+ #
99
+ # @param category[#to_sym] The API action category (i.e. dns, image, vm...)
100
+ # @param action[#to_sym] The API action name (i.e. create, list...)
101
+ # @param params[Hash] Any parameters required for the action.
102
+ #
103
+ # @return [Hash,Array,String] Response data from the API action.
104
+ # @raise [APIError] If there was a problem with the action.
105
+ #
106
+ def action(category, action, **params)
107
+ resp = call_api("#{category}/#{action}/", params)
108
+ raise APIError, %("#{resp[:error]}") unless resp[:success] == "yes"
109
+ resp.delete(:success)
110
+
111
+ if resp.size == 1
112
+ resp.values.first
113
+ else
114
+ resp
115
+ end
116
+ end
117
+
118
+ private
119
+
120
+ attr_reader :api_key, :rest_client
121
+
122
+ # Make an API call and return response.
123
+ def call_api(handler_path, params)
124
+ req_formdata = auth_request_formdata(handler_path, clean_params(params))
125
+ JSON.parse(rest_client[handler_path].post(req_formdata),
126
+ symbolize_names: true)
127
+ rescue RestClient::Exception => err
128
+ err.message += "\n Request Path: #{rest_client.url}#{handler_path}" \
129
+ "\n Request Data: #{req_data}"
130
+ raise err
131
+ end
132
+
133
+ # Clean empty request parameters
134
+ def clean_params(params)
135
+ params.each_with_object({}) do |(k, v), acc|
136
+ if k && k.respond_to?(:to_sym) && v && v.respond_to?(:to_s)
137
+ acc[k.to_sym] = v.to_s
138
+ end
139
+ end
140
+ end
141
+
142
+ # Create signed request data
143
+ def auth_request_formdata(handler_path, params)
144
+ req_msg = raw_request_message(params)
145
+ nonce = gen_nonce
146
+ signature = gen_signature(handler_path, req_msg, nonce)
147
+ {
148
+ req: req_msg,
149
+ signature: signature,
150
+ nonce: nonce,
151
+ }
152
+ end
153
+
154
+ # Generate raw, unsigned request message.
155
+ def raw_request_message(params)
156
+ params[:api_id] = api_id
157
+ params[:api_partialkey] = api_key.slice(0, 64)
158
+ params.to_json
159
+ end
160
+
161
+ # Generate nonce for request
162
+ def gen_nonce
163
+ Time.now.utc.to_i.to_s
164
+ end
165
+
166
+ # Generate signature for request
167
+ def gen_signature(handler_path, req_msg, nonce)
168
+ message = "#{handler_path}|#{req_msg}|#{nonce}"
169
+ OpenSSL::HMAC.hexdigest("SHA512", api_key, message)
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lunanode/api_actions/dns"
4
+ require "lunanode/api_actions/email"
5
+ require "lunanode/api_actions/floating"
6
+ require "lunanode/api_actions/image"
7
+ require "lunanode/api_actions/lb"
8
+ require "lunanode/api_actions/monitor"
9
+ require "lunanode/api_actions/network"
10
+ require "lunanode/api_actions/plan"
11
+ require "lunanode/api_actions/region"
12
+ require "lunanode/api_actions/script"
13
+ require "lunanode/api_actions/securitygroup"
14
+ require "lunanode/api_actions/vm"
15
+ require "lunanode/api_actions/volume"
16
+
17
+ module Lunanode
18
+ # Module containing all API action methods included from various component
19
+ # modules.
20
+ #
21
+ # Standard API action methods were automatically generated from a datafile to
22
+ # specifying all required and optional parameters as keyword arguments.
23
+ #
24
+ # See https://wiki.lunanode.com/index.php/API for more details on the
25
+ # individual actions and parameters.
26
+ module APIActions
27
+ # Modules are included in reverse order so that YARD shows them correctly.
28
+ include Volume
29
+ include VM
30
+ include Securitygroup
31
+ include Script
32
+ include Plan
33
+ include Network
34
+ include Monitor
35
+ include LB
36
+ include Image
37
+ include Floating
38
+ include Email
39
+ include DNS
40
+ end
41
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lunanode
4
+ module APIActions
5
+ module DNS
6
+ def dns_list
7
+ action(:dns, :list)
8
+ end
9
+
10
+ def dns_set(ip:, hostname:)
11
+ action(:dns, :set, ip: ip, hostname: hostname)
12
+ end
13
+
14
+ def dns_zone_list
15
+ action(:dns, :zone_list)
16
+ end
17
+
18
+ def dns_zone_add(origin:, ttl: nil)
19
+ action(:dns, :zone_add, origin: origin, ttl: ttl)
20
+ end
21
+
22
+ def dns_zone_remove(zone_id:)
23
+ action(:dns, :zone_remove, zone_id: zone_id)
24
+ end
25
+
26
+ def dns_record_list(zone_id:)
27
+ action(:dns, :record_list, zone_id: zone_id)
28
+ end
29
+
30
+ def dns_record_add(zone_id:, name:, data:, ttl:, type:)
31
+ action(:dns, :record_add, zone_id: zone_id, name: name, data: data, ttl: ttl, type: type)
32
+ end
33
+
34
+ def dns_record_remove(record_id:)
35
+ action(:dns, :record_remove, record_id: record_id)
36
+ end
37
+
38
+ def dns_dyn_list
39
+ action(:dns, :dyn_list)
40
+ end
41
+
42
+ def dns_dyn_add(name:, ip:)
43
+ action(:dns, :dyn_add, name: name, ip: ip)
44
+ end
45
+
46
+ def dns_dyn_update(dyn_id:, name:, ip:)
47
+ action(:dns, :dyn_update, dyn_id: dyn_id, name: name, ip: ip)
48
+ end
49
+
50
+ def dns_dyn_remove(dyn_id:)
51
+ action(:dns, :dyn_remove, dyn_id: dyn_id)
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lunanode
4
+ module APIActions
5
+ module Email
6
+ def email_usage
7
+ action(:email, :usage)
8
+ end
9
+
10
+ def email_domain_list
11
+ action(:email, :domain_list)
12
+ end
13
+
14
+ def email_domain_add(name:)
15
+ action(:email, :domain_add, name: name)
16
+ end
17
+
18
+ def email_domain_remove(domain_id:)
19
+ action(:email, :domain_remove, domain_id: domain_id)
20
+ end
21
+
22
+ def email_domain_dkim_set(domain_id:, selector:, private_key:)
23
+ action(:email, :domain_dkim_set, domain_id: domain_id, selector: selector, private_key: private_key)
24
+ end
25
+
26
+ def email_domain_dkim_unset(domain_id:)
27
+ action(:email, :domain_dkim_unset, domain_id: domain_id)
28
+ end
29
+
30
+ def email_user_list(domain_id:)
31
+ action(:email, :user_list, domain_id: domain_id)
32
+ end
33
+
34
+ def email_user_add(domain_id:, username:, password:)
35
+ action(:email, :user_add, domain_id: domain_id, username: username, password: password)
36
+ end
37
+
38
+ def email_user_set_password(domain_id:, user_id:, password:)
39
+ action(:email, :user_set_password, domain_id: domain_id, user_id: user_id, password: password)
40
+ end
41
+
42
+ def email_user_remove(domain_id:, user_id:)
43
+ action(:email, :user_remove, domain_id: domain_id, user_id: user_id)
44
+ end
45
+
46
+ def email_alias_list(domain_id:)
47
+ action(:email, :alias_list, domain_id: domain_id)
48
+ end
49
+
50
+ def email_alias_add(domain_id:, name:, target:)
51
+ action(:email, :alias_add, domain_id: domain_id, name: name, target: target)
52
+ end
53
+
54
+ def email_alias_remove(domain_id:, alias_id:)
55
+ action(:email, :alias_remove, domain_id: domain_id, alias_id: alias_id)
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lunanode
4
+ module APIActions
5
+ module Floating
6
+ def floating_list
7
+ action(:floating, :list)
8
+ end
9
+
10
+ def floating_add(region:)
11
+ action(:floating, :add, region: region)
12
+ end
13
+
14
+ def floating_delete(region:, ip:)
15
+ action(:floating, :delete, region: region, ip: ip)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lunanode
4
+ module APIActions
5
+ module Image
6
+ def image_list(region: nil)
7
+ action(:image, :list, region: region)
8
+ end
9
+
10
+ def image_delete(image_id:)
11
+ action(:image, :delete, image_id: image_id)
12
+ end
13
+
14
+ def image_details(image_id:)
15
+ action(:image, :details, image_id: image_id)
16
+ end
17
+
18
+ def image_replicate(image_id:, region:)
19
+ action(:image, :replicate, image_id: image_id, region: region)
20
+ end
21
+
22
+ def image_fetch(region:, name:, location:, format:, virtio: nil)
23
+ action(:image, :fetch, region: region, name: name, location: location, format: format, virtio: virtio)
24
+ end
25
+
26
+ def image_retrieve(image_id:)
27
+ action(:image, :retrieve, image_id: image_id)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lunanode
4
+ module APIActions
5
+ module LB
6
+ def lb_list(region:, net_id: nil)
7
+ action(:lb, :list, region: region, net_id: net_id)
8
+ end
9
+
10
+ def lb_create(region:, net_id:, name:, method:, protocol:, connection_limit:, port:)
11
+ action(:lb, :create, region: region, net_id: net_id, name: name, method: method, protocol: protocol, connection_limit: connection_limit, port: port)
12
+ end
13
+
14
+ def lb_delete(region:, lb_id:)
15
+ action(:lb, :delete, region: region, lb_id: lb_id)
16
+ end
17
+
18
+ def lb_info(region:, lb_id:)
19
+ action(:lb, :info, region: region, lb_id: lb_id)
20
+ end
21
+
22
+ def lb_member_add(region:, lb_id:, ip:, port:)
23
+ action(:lb, :member_add, region: region, lb_id: lb_id, ip: ip, port: port)
24
+ end
25
+
26
+ def lb_member_remove(region:, lb_id:, member_id:)
27
+ action(:lb, :member_remove, region: region, lb_id: lb_id, member_id: member_id)
28
+ end
29
+
30
+ def lb_associate(region:, lb_id:, ip:)
31
+ action(:lb, :associate, region: region, lb_id: lb_id, ip: ip)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lunanode
4
+ module APIActions
5
+ module Monitor
6
+ def monitor_check_list
7
+ action(:monitor, :check_list)
8
+ end
9
+
10
+ def monitor_check_types
11
+ action(:monitor, :check_types)
12
+ end
13
+
14
+ def monitor_check_add(name:, type:, fail_count:, success_count:, check_interval:, **from_check_type)
15
+ action(:monitor, :check_add, name: name, type: type, fail_count: fail_count, success_count: success_count, check_interval: check_interval, **from_check_type)
16
+ end
17
+
18
+ def monitor_check_remove(check_id:)
19
+ action(:monitor, :check_remove, check_id: check_id)
20
+ end
21
+
22
+ def monitor_contact_list
23
+ action(:monitor, :contact_list)
24
+ end
25
+
26
+ def monitor_contact_add
27
+ action(:monitor, :contact_add)
28
+ end
29
+
30
+ def monitor_contact_remove(type:, rel:)
31
+ action(:monitor, :contact_remove, type: type, rel: rel)
32
+ end
33
+
34
+ def monitor_alert_list(check_id:)
35
+ action(:monitor, :alert_list, check_id: check_id)
36
+ end
37
+
38
+ def monitor_alert_add(check_id:, contact_id:)
39
+ action(:monitor, :alert_add, check_id: check_id, contact_id: contact_id)
40
+ end
41
+
42
+ def monitor_alert_remove(alert_id:)
43
+ action(:monitor, :alert_remove, alert_id: alert_id)
44
+ end
45
+ end
46
+ end
47
+ end