lunanode 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
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