vmfloaty 0.8.1 → 0.10.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.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'vmfloaty/errors'
2
4
  require 'vmfloaty/http'
3
5
  require 'faraday'
@@ -15,27 +17,17 @@ class NonstandardPooler
15
17
  os_filter ? os_list.select { |i| i[/#{os_filter}/] } : os_list
16
18
  end
17
19
 
18
- def self.list_active(verbose, url, token)
20
+ def self.list_active(verbose, url, token, _user)
19
21
  status = Auth.token_status(verbose, url, token)
20
22
  status['reserved_hosts'] || []
21
23
  end
22
24
 
23
- def self.retrieve(verbose, os_type, token, url)
25
+ def self.retrieve(verbose, os_type, token, url, _user, _options)
24
26
  conn = Http.get_conn(verbose, url)
25
27
  conn.headers['X-AUTH-TOKEN'] = token if token
26
28
 
27
- os_string = ''
28
- os_type.each do |os, num|
29
- num.times do |_i|
30
- os_string << os + '+'
31
- end
32
- end
33
-
34
- os_string = os_string.chomp('+')
35
-
36
- if os_string.empty?
37
- raise MissingParamError, 'No operating systems provided to obtain.'
38
- end
29
+ os_string = os_type.map { |os, num| Array(os) * num }.flatten.join('+')
30
+ raise MissingParamError, 'No operating systems provided to obtain.' if os_string.empty?
39
31
 
40
32
  response = conn.post "host/#{os_string}"
41
33
 
@@ -51,14 +43,10 @@ class NonstandardPooler
51
43
  end
52
44
 
53
45
  def self.modify(verbose, url, hostname, token, modify_hash)
54
- if token.nil?
55
- raise TokenError, 'Token provided was nil; Request cannot be made to modify VM'
56
- end
46
+ raise TokenError, 'Token provided was nil; Request cannot be made to modify VM' if token.nil?
57
47
 
58
- modify_hash.each do |key, value|
59
- unless [:reason, :reserved_for_reason].include? key
60
- raise ModifyError, "Configured service type does not support modification of #{key}"
61
- end
48
+ modify_hash.each do |key, _value|
49
+ raise ModifyError, "Configured service type does not support modification of #{key}" unless %i[reason reserved_for_reason].include? key
62
50
  end
63
51
 
64
52
  if modify_hash[:reason]
@@ -77,22 +65,20 @@ class NonstandardPooler
77
65
  response.body.empty? ? {} : JSON.parse(response.body)
78
66
  end
79
67
 
80
- def self.disk(verbose, url, hostname, token, disk)
68
+ def self.disk(_verbose, _url, _hostname, _token, _disk)
81
69
  raise ModifyError, 'Configured service type does not support modification of disk space'
82
70
  end
83
71
 
84
- def self.snapshot(verbose, url, hostname, token)
72
+ def self.snapshot(_verbose, _url, _hostname, _token)
85
73
  raise ModifyError, 'Configured service type does not support snapshots'
86
74
  end
87
75
 
88
- def self.revert(verbose, url, hostname, token, snapshot_sha)
76
+ def self.revert(_verbose, _url, _hostname, _token, _snapshot_sha)
89
77
  raise ModifyError, 'Configured service type does not support snapshots'
90
78
  end
91
79
 
92
- def self.delete(verbose, url, hosts, token)
93
- if token.nil?
94
- raise TokenError, 'Token provided was nil; Request cannot be made to delete VM'
95
- end
80
+ def self.delete(verbose, url, hosts, token, _user)
81
+ raise TokenError, 'Token provided was nil; Request cannot be made to delete VM' if token.nil?
96
82
 
97
83
  conn = Http.get_conn(verbose, url)
98
84
 
@@ -100,9 +86,7 @@ class NonstandardPooler
100
86
 
101
87
  response_body = {}
102
88
 
103
- unless hosts.is_a? Array
104
- hosts = hosts.split(',')
105
- end
89
+ hosts = hosts.split(',') unless hosts.is_a? Array
106
90
  hosts.each do |host|
107
91
  response = conn.delete "host/#{host}"
108
92
  res_body = JSON.parse(response.body)
@@ -1,77 +1,91 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'faraday'
2
4
  require 'vmfloaty/http'
3
5
  require 'json'
4
6
  require 'vmfloaty/errors'
5
7
 
6
8
  class Pooler
7
- def self.list(verbose, url, os_filter=nil)
9
+ def self.list(verbose, url, os_filter = nil)
8
10
  conn = Http.get_conn(verbose, url)
9
11
 
10
12
  response = conn.get 'vm'
11
13
  response_body = JSON.parse(response.body)
12
14
 
13
- if os_filter
14
- hosts = response_body.select { |i| i[/#{os_filter}/] }
15
- else
16
- hosts = response_body
17
- end
15
+ hosts = if os_filter
16
+ response_body.select { |i| i[/#{os_filter}/] }
17
+ else
18
+ response_body
19
+ end
18
20
 
19
21
  hosts
20
22
  end
21
23
 
22
- def self.list_active(verbose, url, token)
24
+ def self.list_active(verbose, url, token, _user)
23
25
  status = Auth.token_status(verbose, url, token)
24
26
  vms = []
25
- if status[token] && status[token]['vms']
26
- vms = status[token]['vms']['running']
27
- end
27
+ vms = status[token]['vms']['running'] if status[token] && status[token]['vms']
28
28
  vms
29
29
  end
30
30
 
31
- def self.retrieve(verbose, os_type, token, url)
31
+ def self.retrieve(verbose, os_type, token, url, _user, _options, ondemand = nil)
32
32
  # NOTE:
33
33
  # Developers can use `Utils.generate_os_hash` to
34
34
  # generate the os_type param.
35
35
  conn = Http.get_conn(verbose, url)
36
- if token
37
- conn.headers['X-AUTH-TOKEN'] = token
38
- end
36
+ conn.headers['X-AUTH-TOKEN'] = token if token
39
37
 
40
- os_string = ""
41
- os_type.each do |os,num|
42
- num.times do |i|
43
- os_string << os+"+"
44
- end
45
- end
46
-
47
- os_string = os_string.chomp("+")
48
-
49
- if os_string.size == 0
50
- raise MissingParamError, "No operating systems provided to obtain."
51
- end
38
+ os_string = os_type.map { |os, num| Array(os) * num }.flatten.join('+')
39
+ raise MissingParamError, 'No operating systems provided to obtain.' if os_string.empty?
52
40
 
53
- response = conn.post "vm/#{os_string}"
41
+ response = conn.post "vm/#{os_string}" unless ondemand
42
+ response ||= conn.post "ondemandvm/#{os_string}"
54
43
 
55
44
  res_body = JSON.parse(response.body)
56
45
 
57
- if res_body["ok"]
46
+ if res_body['ok']
58
47
  res_body
59
48
  elsif response.status == 401
60
49
  raise AuthError, "HTTP #{response.status}: The token provided could not authenticate to the pooler.\n#{res_body}"
50
+ elsif response.status == 403
51
+ raise "HTTP #{response.status}: Failed to obtain VMs from the pooler at #{url}/vm/#{os_string}. Request exceeds the configured per pool maximum. #{res_body}"
61
52
  else
62
- raise "HTTP #{response.status}: Failed to obtain VMs from the pooler at #{url}/vm/#{os_string}. #{res_body}"
53
+ raise "HTTP #{response.status}: Failed to obtain VMs from the pooler at #{url}/vm/#{os_string}. #{res_body}" unless ondemand
54
+ raise "HTTP #{response.status}: Failed to obtain VMs from the pooler at #{url}/ondemandvm/#{os_string}. #{res_body}"
63
55
  end
64
56
  end
65
57
 
66
- def self.modify(verbose, url, hostname, token, modify_hash)
67
- if token.nil?
68
- raise TokenError, "Token provided was nil. Request cannot be made to modify vm"
58
+ def self.wait_for_request(verbose, request_id, url, timeout = 300)
59
+ start_time = Time.now
60
+ while check_ondemandvm(verbose, request_id, url) == false
61
+ return false if (Time.now - start_time).to_i > timeout
62
+
63
+ STDOUT.puts "waiting for request #{request_id} to be fulfilled"
64
+ sleep 5
69
65
  end
66
+ STDOUT.puts "The request has been fulfilled"
67
+ check_ondemandvm(verbose, request_id, url)
68
+ end
69
+
70
+ def self.check_ondemandvm(verbose, request_id, url)
71
+ conn = Http.get_conn(verbose, url)
72
+
73
+ response = conn.get "ondemandvm/#{request_id}"
74
+ res_body = JSON.parse(response.body)
75
+ return res_body if response.status == 200
76
+
77
+ return false if response.status == 202
78
+
79
+ raise "HTTP #{response.status}: The request cannot be found, or an unknown error occurred" if response.status == 404
80
+
81
+ false
82
+ end
83
+
84
+ def self.modify(verbose, url, hostname, token, modify_hash)
85
+ raise TokenError, 'Token provided was nil. Request cannot be made to modify vm' if token.nil?
70
86
 
71
87
  modify_hash.keys.each do |key|
72
- unless [:tags, :lifetime, :disk].include? key
73
- raise ModifyError, "Configured service type does not support modification of #{key}."
74
- end
88
+ raise ModifyError, "Configured service type does not support modification of #{key}." unless %i[tags lifetime disk].include? key
75
89
  end
76
90
 
77
91
  conn = Http.get_conn(verbose, url)
@@ -88,13 +102,18 @@ class Pooler
88
102
  end
89
103
 
90
104
  res_body = JSON.parse(response.body)
91
- res_body
105
+
106
+ if res_body['ok']
107
+ res_body
108
+ elsif response.status == 401
109
+ raise AuthError, "HTTP #{response.status}: The token provided could not authenticate to the pooler.\n#{res_body}"
110
+ else
111
+ raise ModifyError, "HTTP #{response.status}: Failed to modify VMs from the pooler vm/#{hostname}. #{res_body}"
112
+ end
92
113
  end
93
114
 
94
115
  def self.disk(verbose, url, hostname, token, disk)
95
- if token.nil?
96
- raise TokenError, "Token provided was nil. Request cannot be made to modify vm"
97
- end
116
+ raise TokenError, 'Token provided was nil. Request cannot be made to modify vm' if token.nil?
98
117
 
99
118
  conn = Http.get_conn(verbose, url)
100
119
  conn.headers['X-AUTH-TOKEN'] = token
@@ -105,16 +124,12 @@ class Pooler
105
124
  res_body
106
125
  end
107
126
 
108
- def self.delete(verbose, url, hosts, token)
109
- if token.nil?
110
- raise TokenError, "Token provided was nil. Request cannot be made to delete vm"
111
- end
127
+ def self.delete(verbose, url, hosts, token, _user)
128
+ raise TokenError, 'Token provided was nil. Request cannot be made to delete vm' if token.nil?
112
129
 
113
130
  conn = Http.get_conn(verbose, url)
114
131
 
115
- if token
116
- conn.headers['X-AUTH-TOKEN'] = token
117
- end
132
+ conn.headers['X-AUTH-TOKEN'] = token if token
118
133
 
119
134
  response_body = {}
120
135
 
@@ -153,9 +168,7 @@ class Pooler
153
168
  end
154
169
 
155
170
  def self.snapshot(verbose, url, hostname, token)
156
- if token.nil?
157
- raise TokenError, "Token provided was nil. Request cannot be made to snapshot vm"
158
- end
171
+ raise TokenError, 'Token provided was nil. Request cannot be made to snapshot vm' if token.nil?
159
172
 
160
173
  conn = Http.get_conn(verbose, url)
161
174
  conn.headers['X-AUTH-TOKEN'] = token
@@ -166,16 +179,12 @@ class Pooler
166
179
  end
167
180
 
168
181
  def self.revert(verbose, url, hostname, token, snapshot_sha)
169
- if token.nil?
170
- raise TokenError, "Token provided was nil. Request cannot be made to revert vm"
171
- end
182
+ raise TokenError, 'Token provided was nil. Request cannot be made to revert vm' if token.nil?
172
183
 
173
184
  conn = Http.get_conn(verbose, url)
174
185
  conn.headers['X-AUTH-TOKEN'] = token
175
186
 
176
- if snapshot_sha.nil?
177
- raise "Snapshot SHA provided was nil, could not revert #{hostname}"
178
- end
187
+ raise "Snapshot SHA provided was nil, could not revert #{hostname}" if snapshot_sha.nil?
179
188
 
180
189
  response = conn.post "vm/#{hostname}/snapshot/#{snapshot_sha}"
181
190
  res_body = JSON.parse(response.body)
@@ -1,10 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'commander/user_interaction'
2
4
  require 'commander/command'
3
5
  require 'vmfloaty/utils'
4
6
  require 'vmfloaty/ssh'
5
7
 
6
8
  class Service
7
-
8
9
  attr_reader :config
9
10
 
10
11
  def initialize(options, config_hash = {})
@@ -13,14 +14,18 @@ class Service
13
14
  @service_object = Utils.get_service_object @config['type']
14
15
  end
15
16
 
16
- def method_missing(m, *args, &block)
17
- if @service_object.respond_to? m
18
- @service_object.send(m, *args, &block)
17
+ def method_missing(method_name, *args, &block)
18
+ if @service_object.respond_to?(method_name)
19
+ @service_object.send(method_name, *args, &block)
19
20
  else
20
21
  super
21
22
  end
22
23
  end
23
24
 
25
+ def respond_to_missing?(method_name, *)
26
+ @service_object.respond_to?(method_name) || super
27
+ end
28
+
24
29
  def url
25
30
  @config['url']
26
31
  end
@@ -31,7 +36,7 @@ class Service
31
36
 
32
37
  def user
33
38
  unless @config['user']
34
- puts "Enter your pooler service username:"
39
+ puts "Enter your #{@config['url']} service username:"
35
40
  @config['user'] = STDIN.gets.chomp
36
41
  end
37
42
  @config['user']
@@ -39,7 +44,7 @@ class Service
39
44
 
40
45
  def token
41
46
  unless @config['token']
42
- puts "No token found. Retrieving a token..."
47
+ puts 'No token found. Retrieving a token...'
43
48
  @config['token'] = get_new_token(nil)
44
49
  end
45
50
  @config['token']
@@ -47,13 +52,13 @@ class Service
47
52
 
48
53
  def get_new_token(verbose)
49
54
  username = user
50
- pass = Commander::UI::password "Enter your pooler service password:", '*'
55
+ pass = Commander::UI.password "Enter your #{@config['url']} service password:", '*'
51
56
  Auth.get_token(verbose, url, username, pass)
52
57
  end
53
58
 
54
59
  def delete_token(verbose, token_value = @config['token'])
55
60
  username = user
56
- pass = Commander::UI::password "Enter your pooler service password:", '*'
61
+ pass = Commander::UI.password "Enter your #{@config['url']} service password:", '*'
57
62
  Auth.delete_token(verbose, url, username, pass, token_value)
58
63
  end
59
64
 
@@ -67,13 +72,17 @@ class Service
67
72
  end
68
73
 
69
74
  def list_active(verbose)
70
- @service_object.list_active verbose, url, token
75
+ @service_object.list_active verbose, url, token, user
71
76
  end
72
77
 
73
- def retrieve(verbose, os_types, use_token = true)
78
+ def retrieve(verbose, os_types, use_token = true, ondemand = nil)
74
79
  puts 'Requesting a vm without a token...' unless use_token
75
80
  token_value = use_token ? token : nil
76
- @service_object.retrieve verbose, os_types, token_value, url
81
+ @service_object.retrieve verbose, os_types, token_value, url, user, @config, ondemand
82
+ end
83
+
84
+ def wait_for_request(verbose, requestid)
85
+ @service_object.wait_for_request verbose, requestid, url
77
86
  end
78
87
 
79
88
  def ssh(verbose, host_os, use_token = true)
@@ -86,14 +95,14 @@ class Service
86
95
  STDERR.puts 'Could not get token... requesting vm without a token anyway...'
87
96
  end
88
97
  end
89
- Ssh.ssh(verbose, host_os, token_value, url)
98
+ Ssh.ssh(verbose, self, host_os, token_value)
90
99
  end
91
100
 
92
101
  def pretty_print_running(verbose, hostnames = [])
93
102
  if hostnames.empty?
94
- puts "You have no running VMs."
103
+ puts 'You have no running VMs.'
95
104
  else
96
- puts "Running VMs:"
105
+ puts 'Running VMs:'
97
106
  @service_object.pretty_print_hosts(verbose, hostnames, url)
98
107
  end
99
108
  end
@@ -107,7 +116,7 @@ class Service
107
116
  end
108
117
 
109
118
  def delete(verbose, hosts)
110
- @service_object.delete verbose, url, hosts, token
119
+ @service_object.delete verbose, url, hosts, token, user
111
120
  end
112
121
 
113
122
  def status(verbose)
@@ -129,5 +138,4 @@ class Service
129
138
  def disk(verbose, hostname, disk)
130
139
  @service_object.disk(verbose, url, hostname, token, disk)
131
140
  end
132
-
133
- end
141
+ end
@@ -1,43 +1,43 @@
1
- class Ssh
1
+ # frozen_string_literal: true
2
2
 
3
+ class Ssh
3
4
  def self.which(cmd)
4
5
  # Gets path of executable for given command
5
6
 
6
7
  exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
7
8
  ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
8
- exts.each { |ext|
9
+ exts.each do |ext|
9
10
  exe = File.join(path, "#{cmd}#{ext}")
10
11
  return exe if File.executable?(exe) && !File.directory?(exe)
11
- }
12
+ end
12
13
  end
13
- return nil
14
+ nil
14
15
  end
15
16
 
16
- def self.ssh(verbose, host_os, token, url)
17
- ssh_path = which("ssh")
18
- if !ssh_path
19
- raise "Could not determine path to ssh"
20
- end
17
+ def self.command_string(verbose, service, host_os, use_token)
18
+ ssh_path = which('ssh')
19
+ raise 'Could not determine path to ssh' unless ssh_path
20
+
21
21
  os_types = {}
22
22
  os_types[host_os] = 1
23
23
 
24
- response = Pooler.retrieve(verbose, os_types, token, url)
25
- if response["ok"] == true
26
- if host_os =~ /win/
27
- user = "Administrator"
28
- else
29
- user = "root"
30
- end
24
+ response = service.retrieve(verbose, os_types, use_token)
25
+ raise "Could not get vm from #{service.type}:\n #{response}" unless response['ok']
31
26
 
32
- hostname = "#{response[host_os]["hostname"]}.#{response["domain"]}"
33
- cmd = "#{ssh_path} #{user}@#{hostname}"
27
+ user = /win/.match?(host_os) ? 'Administrator' : 'root'
34
28
 
35
- # TODO: Should this respect more ssh settings? Can it be configured
36
- # by users ssh config and does this respect those settings?
37
- Kernel.exec(cmd)
38
- else
39
- raise "Could not get vm from vmpooler:\n #{response}"
40
- end
41
- return
29
+ hostname = response[host_os]['hostname']
30
+ hostname = response[host_os]['hostname'][0] if response[host_os]['hostname'].is_a?(Array)
31
+ hostname = "#{hostname}.#{response['domain']}" unless hostname.end_with?('puppetlabs.net')
32
+
33
+ "#{ssh_path} #{user}@#{hostname}"
34
+ end
35
+
36
+ def self.ssh(verbose, service, host_os, use_token)
37
+ cmd = command_string(verbose, service, host_os, use_token)
38
+ # TODO: Should this respect more ssh settings? Can it be configured
39
+ # by users ssh config and does this respect those settings?
40
+ Kernel.exec(cmd)
41
+ nil
42
42
  end
43
43
  end