Fix rubocops

This commit is contained in:
Jake Spain 2023-02-23 10:37:43 -05:00
parent da4015f5b3
commit eaa1104dd7
No known key found for this signature in database
GPG key ID: BC1C4DA0A085E113
5 changed files with 587 additions and 116 deletions

View file

@ -9,10 +9,50 @@ module Vmpooler
api_version = '2' api_version = '2'
api_prefix = "/api/v#{api_version}" api_prefix = "/api/v#{api_version}"
helpers do
include Vmpooler::API::Helpers
end
def backend
Vmpooler::API.settings.redis
end
def metrics
Vmpooler::API.settings.metrics
end
def config
Vmpooler::API.settings.config[:config]
end
def full_config def full_config
Vmpooler::API.settings.config Vmpooler::API.settings.config
end end
def pools
Vmpooler::API.settings.config[:pools]
end
def pools_at_startup
Vmpooler::API.settings.config[:pools_at_startup]
end
def pool_exists?(template)
Vmpooler::API.settings.config[:pool_names].include?(template)
end
def need_auth!
validate_auth(backend)
end
def need_token!
validate_token(backend)
end
def checkoutlock
Vmpooler::API.settings.checkoutlock
end
def get_template_aliases(template) def get_template_aliases(template)
tracer.in_span("Vmpooler::API::V2.#{__method__}") do tracer.in_span("Vmpooler::API::V2.#{__method__}") do
result = [] result = []
@ -25,6 +65,56 @@ module Vmpooler
end end
end end
def get_pool_weights(template_backends)
pool_index = pool_index(pools)
weighted_pools = {}
template_backends.each do |t|
next unless pool_index.key? t
index = pool_index[t]
clone_target = pools[index]['clone_target'] || config['clone_target']
next unless config.key?('backend_weight')
weight = config['backend_weight'][clone_target]
if weight
weighted_pools[t] = weight
end
end
weighted_pools
end
def count_selection(selection)
result = {}
selection.uniq.each do |poolname|
result[poolname] = selection.count(poolname)
end
result
end
def evaluate_template_aliases(template, count)
template_backends = []
template_backends << template if backend.sismember('vmpooler__pools', template)
selection = []
aliases = get_template_aliases(template)
if aliases
template_backends += aliases
weighted_pools = get_pool_weights(template_backends)
if weighted_pools.count > 1 && weighted_pools.count == template_backends.count
pickup = Pickup.new(weighted_pools)
count.to_i.times do
selection << pickup.pick
end
else
count.to_i.times do
selection << template_backends.sample
end
end
end
count_selection(selection)
end
# Fetch a single vm from a pool # Fetch a single vm from a pool
# #
# @param [String] template # @param [String] template
@ -84,6 +174,47 @@ module Vmpooler
end end
end end
def return_vm_to_ready_state(template, vm)
tracer.in_span("Vmpooler::API::V2.#{__method__}") do
backend.srem("vmpooler__migrating__#{template}", vm)
backend.hdel("vmpooler__active__#{template}", vm)
backend.hdel("vmpooler__vm__#{vm}", 'checkout', 'token:token', 'token:user')
backend.smove("vmpooler__running__#{template}", "vmpooler__ready__#{template}", vm)
end
end
def account_for_starting_vm(template, vm)
tracer.in_span("Vmpooler::API::V2.#{__method__}") do |span|
user = backend.hget("vmpooler__token__#{request.env['HTTP_X_AUTH_TOKEN']}", 'user')
span.set_attribute('enduser.id', user)
has_token_result = has_token?
backend.sadd("vmpooler__migrating__#{template}", vm)
backend.hset("vmpooler__active__#{template}", vm, Time.now)
backend.hset("vmpooler__vm__#{vm}", 'checkout', Time.now)
if Vmpooler::API.settings.config[:auth] and has_token_result
backend.hset("vmpooler__vm__#{vm}", 'token:token', request.env['HTTP_X_AUTH_TOKEN'])
backend.hset("vmpooler__vm__#{vm}", 'token:user', user)
if config['vm_lifetime_auth'].to_i > 0
backend.hset("vmpooler__vm__#{vm}", 'lifetime', config['vm_lifetime_auth'].to_i)
end
end
end
end
def update_result_hosts(result, template, vm)
tracer.in_span("Vmpooler::API::V2.#{__method__}") do
result[template] ||= {}
if result[template]['hostname']
result[template]['hostname'] = Array(result[template]['hostname'])
result[template]['hostname'].push(vm)
else
result[template]['hostname'] = vm
end
end
end
# The domain in the result body will be set to the one associated with the # The domain in the result body will be set to the one associated with the
# last vm added. The part of the response is only being retained for # last vm added. The part of the response is only being retained for
# backwards compatibility as the hostnames are now fqdn's instead of bare # backwards compatibility as the hostnames are now fqdn's instead of bare
@ -140,6 +271,254 @@ module Vmpooler
end end
end end
def component_to_test(match, labels_string)
tracer.in_span("Vmpooler::API::V2.#{__method__}") do
return if labels_string.nil?
labels_string_parts = labels_string.split(',')
labels_string_parts.each do |part|
key, value = part.split('=')
next if value.nil?
return value if key == match
end
'none'
end
end
def update_user_metrics(operation, vmname)
tracer.in_span("Vmpooler::API::V2.#{__method__}") do |span|
begin
backend.multi
backend.hget("vmpooler__vm__#{vmname}", 'tag:jenkins_build_url')
backend.hget("vmpooler__vm__#{vmname}", 'token:user')
backend.hget("vmpooler__vm__#{vmname}", 'template')
jenkins_build_url, user, poolname = backend.exec
poolname = poolname.gsub('.', '_')
if user
user = user.gsub('.', '_')
else
user = 'unauthenticated'
end
metrics.increment("user.#{user}.#{operation}.#{poolname}")
if jenkins_build_url
if jenkins_build_url.include? 'litmus'
# Very simple filter for Litmus jobs - just count them coming through for the moment.
metrics.increment("usage_litmus.#{user}.#{operation}.#{poolname}")
else
url_parts = jenkins_build_url.split('/')[2..-1]
jenkins_instance = url_parts[0].gsub('.', '_')
value_stream_parts = url_parts[2].split('_')
value_stream_parts = value_stream_parts.map { |s| s.gsub('.', '_') }
value_stream = value_stream_parts.shift
branch = value_stream_parts.pop
project = value_stream_parts.shift
job_name = value_stream_parts.join('_')
build_metadata_parts = url_parts[3]
component_to_test = component_to_test('RMM_COMPONENT_TO_TEST_NAME', build_metadata_parts)
metrics.increment("usage_jenkins_instance.#{jenkins_instance}.#{value_stream}.#{operation}.#{poolname}")
metrics.increment("usage_branch_project.#{branch}.#{project}.#{operation}.#{poolname}")
metrics.increment("usage_job_component.#{job_name}.#{component_to_test}.#{operation}.#{poolname}")
end
end
rescue StandardError => e
puts 'd', "[!] [#{poolname}] failed while evaluating usage labels on '#{vmname}' with an error: #{e}"
span.record_exception(e)
span.status = OpenTelemetry::Trace::Status.error(e.to_s)
span.add_event('log', attributes: {
'log.severity' => 'debug',
'log.message' => "[#{poolname}] failed while evaluating usage labels on '#{vmname}' with an error: #{e}"
})
end
end
end
def reset_pool_size(poolname)
tracer.in_span("Vmpooler::API::V2.#{__method__}") do
result = { 'ok' => false }
pool_index = pool_index(pools)
pools_updated = 0
sync_pool_sizes
pool_size_now = pools[pool_index[poolname]]['size'].to_i
pool_size_original = pools_at_startup[pool_index[poolname]]['size'].to_i
result['pool_size_before_reset'] = pool_size_now
result['pool_size_before_overrides'] = pool_size_original
unless pool_size_now == pool_size_original
pools[pool_index[poolname]]['size'] = pool_size_original
backend.hdel('vmpooler__config__poolsize', poolname)
backend.sadd('vmpooler__pool__undo_size_override', poolname)
pools_updated += 1
status 201
end
status 200 unless pools_updated > 0
result['ok'] = true
result
end
end
def update_pool_size(payload)
tracer.in_span("Vmpooler::API::V2.#{__method__}") do
result = { 'ok' => false }
pool_index = pool_index(pools)
pools_updated = 0
sync_pool_sizes
payload.each do |poolname, size|
unless pools[pool_index[poolname]]['size'] == size.to_i
pools[pool_index[poolname]]['size'] = size.to_i
backend.hset('vmpooler__config__poolsize', poolname, size)
pools_updated += 1
status 201
end
end
status 200 unless pools_updated > 0
result['ok'] = true
result
end
end
def reset_pool_template(poolname)
tracer.in_span("Vmpooler::API::V2.#{__method__}") do
result = { 'ok' => false }
pool_index_live = pool_index(pools)
pool_index_original = pool_index(pools_at_startup)
pools_updated = 0
sync_pool_templates
template_now = pools[pool_index_live[poolname]]['template']
template_original = pools_at_startup[pool_index_original[poolname]]['template']
result['template_before_reset'] = template_now
result['template_before_overrides'] = template_original
unless template_now == template_original
pools[pool_index_live[poolname]]['template'] = template_original
backend.hdel('vmpooler__config__template', poolname)
backend.sadd('vmpooler__pool__undo_template_override', poolname)
pools_updated += 1
status 201
end
status 200 unless pools_updated > 0
result['ok'] = true
result
end
end
def update_pool_template(payload)
tracer.in_span("Vmpooler::API::V2.#{__method__}") do
result = { 'ok' => false }
pool_index = pool_index(pools)
pools_updated = 0
sync_pool_templates
payload.each do |poolname, template|
unless pools[pool_index[poolname]]['template'] == template
pools[pool_index[poolname]]['template'] = template
backend.hset('vmpooler__config__template', poolname, template)
pools_updated += 1
status 201
end
end
status 200 unless pools_updated > 0
result['ok'] = true
result
end
end
def reset_pool(payload)
tracer.in_span("Vmpooler::API::V2.#{__method__}") do
result = { 'ok' => false }
payload.each do |poolname, _count|
backend.sadd('vmpooler__poolreset', poolname)
end
status 201
result['ok'] = true
result
end
end
def update_clone_target(payload)
tracer.in_span("Vmpooler::API::V2.#{__method__}") do
result = { 'ok' => false }
pool_index = pool_index(pools)
pools_updated = 0
sync_clone_targets
payload.each do |poolname, clone_target|
unless pools[pool_index[poolname]]['clone_target'] == clone_target
pools[pool_index[poolname]]['clone_target'] = clone_target
backend.hset('vmpooler__config__clone_target', poolname, clone_target)
pools_updated += 1
status 201
end
end
status 200 unless pools_updated > 0
result['ok'] = true
result
end
end
def sync_pool_templates
tracer.in_span("Vmpooler::API::V2.#{__method__}") do
pool_index = pool_index(pools)
template_configs = backend.hgetall('vmpooler__config__template')
template_configs&.each do |poolname, template|
next unless pool_index.include? poolname
pools[pool_index[poolname]]['template'] = template
end
end
end
def sync_pool_sizes
tracer.in_span("Vmpooler::API::V2.#{__method__}") do
pool_index = pool_index(pools)
poolsize_configs = backend.hgetall('vmpooler__config__poolsize')
poolsize_configs&.each do |poolname, size|
next unless pool_index.include? poolname
pools[pool_index[poolname]]['size'] = size.to_i
end
end
end
def sync_clone_targets
tracer.in_span("Vmpooler::API::V2.#{__method__}") do
pool_index = pool_index(pools)
clone_target_configs = backend.hgetall('vmpooler__config__clone_target')
clone_target_configs&.each do |poolname, clone_target|
next unless pool_index.include? poolname
pools[pool_index[poolname]]['clone_target'] = clone_target
end
end
end
def too_many_requested?(payload)
tracer.in_span("Vmpooler::API::V2.#{__method__}") do
payload&.each do |poolname, count|
next unless count.to_i > config['max_ondemand_instances_per_request']
metrics.increment("ondemandrequest_fail.toomanyrequests.#{poolname}")
return true
end
false
end
end
def generate_ondemand_request(payload) def generate_ondemand_request(payload)
tracer.in_span("Vmpooler::API::V2.#{__method__}") do |span| tracer.in_span("Vmpooler::API::V2.#{__method__}") do |span|
result = { 'ok': false } result = { 'ok': false }
@ -200,7 +579,14 @@ module Vmpooler
end end
end end
# Endpoints that use overridden methods def generate_request_id
SecureRandom.uuid
end
get '/' do
sync_pool_sizes
redirect to('/dashboard/')
end
post "#{api_prefix}/vm/?" do post "#{api_prefix}/vm/?" do
content_type :json content_type :json
@ -227,6 +613,102 @@ module Vmpooler
JSON.pretty_generate(result) JSON.pretty_generate(result)
end end
def extract_templates_from_query_params(params)
tracer.in_span("Vmpooler::API::V2.#{__method__}") do
payload = {}
params.split('+').each do |template|
payload[template] ||= 0
payload[template] += 1
end
payload
end
end
def invalid_templates(payload)
tracer.in_span("Vmpooler::API::V2.#{__method__}") do
invalid = []
payload.keys.each do |template|
invalid << template unless pool_exists?(template)
end
invalid
end
end
def invalid_template_or_size(payload)
tracer.in_span("Vmpooler::API::V2.#{__method__}") do
invalid = []
payload.each do |pool, size|
invalid << pool unless pool_exists?(pool)
unless is_integer?(size)
invalid << pool
next
end
invalid << pool unless Integer(size) >= 0
end
invalid
end
end
def invalid_template_or_path(payload)
tracer.in_span("Vmpooler::API::V2.#{__method__}") do
invalid = []
payload.each do |pool, template|
invalid << pool unless pool_exists?(pool)
invalid << pool unless template.include? '/'
invalid << pool if template[0] == '/'
invalid << pool if template[-1] == '/'
end
invalid
end
end
def invalid_pool(payload)
tracer.in_span("Vmpooler::API::V2.#{__method__}") do
invalid = []
payload.each do |pool, _clone_target|
invalid << pool unless pool_exists?(pool)
end
invalid
end
end
def delete_ondemand_request(request_id)
tracer.in_span("Vmpooler::API::V2.#{__method__}") do |span|
span.set_attribute('vmpooler.request_id', request_id)
result = { 'ok' => false }
platforms = backend.hget("vmpooler__odrequest__#{request_id}", 'requested')
unless platforms
e_message = "no request found for request_id '#{request_id}'"
result['message'] = e_message
span.add_event('error', attributes: {
'error.type' => 'Vmpooler::API::V2.delete_ondemand_request',
'error.message' => e_message
})
return result
end
if backend.hget("vmpooler__odrequest__#{request_id}", 'status') == 'deleted'
result['message'] = 'the request has already been deleted'
else
backend.hset("vmpooler__odrequest__#{request_id}", 'status', 'deleted')
Parsing.get_platform_pool_count(platforms) do |platform_alias, pool, _count|
backend.smembers("vmpooler__#{request_id}__#{platform_alias}__#{pool}")&.each do |vm|
backend.smove("vmpooler__running__#{pool}", "vmpooler__completed__#{pool}", vm)
end
backend.del("vmpooler__#{request_id}__#{platform_alias}__#{pool}")
end
backend.expire("vmpooler__odrequest__#{request_id}", 129_600_0)
end
status 200
result['ok'] = true
result
end
end
post "#{api_prefix}/vm/:template/?" do post "#{api_prefix}/vm/:template/?" do
content_type :json content_type :json
result = { 'ok' => false } result = { 'ok' => false }

View file

@ -1,8 +1,9 @@
# frozen_string_literal: true
require 'pathname' require 'pathname'
module Vmpooler module Vmpooler
class Dns class Dns
# Load one or more VMPooler DNS plugin gems by name # Load one or more VMPooler DNS plugin gems by name
# #
# @param names [Array<String>] The list of gem names to load # @param names [Array<String>] The list of gem names to load
@ -22,9 +23,7 @@ module Vmpooler
plugin_class = '' plugin_class = ''
dns_configs.map do |dns_config_name| dns_configs.map do |dns_config_name|
if dns_config_name.to_s == name plugin_class = config[:dns_configs][dns_config_name]['dns_class'] if dns_config_name.to_s == name
plugin_class = config[:dns_configs][dns_config_name]['dns_class']
end
end end
plugin_class plugin_class
@ -42,9 +41,7 @@ module Vmpooler
pool_domain = '' pool_domain = ''
dns_configs.map do |dns_config_name| dns_configs.map do |dns_config_name|
if dns_config_name.to_s == pool_dns_config pool_domain = config[:dns_configs][dns_config_name]['domain'] if dns_config_name.to_s == pool_dns_config
pool_domain = config[:dns_configs][dns_config_name]['domain']
end
end end
pool_domain pool_domain
@ -60,9 +57,7 @@ module Vmpooler
plugin_domain = '' plugin_domain = ''
dns_configs.map do |dns_config_name| dns_configs.map do |dns_config_name|
if dns_config_name.to_s == name plugin_domain = config[:dns_configs][dns_config_name]['domain'] if dns_config_name.to_s == name
plugin_domain = config[:dns_configs][dns_config_name]['domain']
end
end end
plugin_domain plugin_domain
@ -96,7 +91,7 @@ module Vmpooler
# @param name [String] The name of the DNS plugin gem to load # @param name [String] The name of the DNS plugin gem to load
# @return [String] The full require path to the specified gem # @return [String] The full require path to the specified gem
def load_from_gems(name = nil) def load_from_gems(name = nil)
require_path = 'vmpooler/dns/' + name.gsub('-', '/') require_path = "vmpooler/dns/#{name.gsub('-', '/')}"
require require_path require require_path
$logger.log('d', "[*] [dns_manager] Loading DNS plugins from dns_configs: #{name}") $logger.log('d', "[*] [dns_manager] Loading DNS plugins from dns_configs: #{name}")
require_path require_path

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
module Vmpooler module Vmpooler
class PoolManager class PoolManager
class Dns class Dns
@ -22,7 +24,6 @@ module Vmpooler
@dns_options = options @dns_options = options
logger.log('s', "[!] Creating dns plugin '#{name}'") logger.log('s', "[!] Creating dns plugin '#{name}'")
# Your code goes here...
end end
def pool_config(pool_name) def pool_config(pool_name)
@ -57,27 +58,22 @@ module Vmpooler
def get_ip(vm_name) def get_ip(vm_name)
@redis.with_metrics do |redis| @redis.with_metrics do |redis|
ip = redis.hget("vmpooler__vm__#{vm_name}", 'ip') redis.hget("vmpooler__vm__#{vm_name}", 'ip')
return ip
end end
end end
# returns # returns
# Array[String] : Array of pool names this provider services # Array[String] : Array of pool names this provider services
def provided_pools def provided_pools
list = [] @config[:pools].select { |pool| pool['dns_config'] == name }.map { |pool| pool['name'] }
@config[:pools].each do |pool|
list << pool['name'] if pool['dns_config'] == name
end
list
end end
def create_or_replace_record(hostname) def create_or_replace_record(hostname)
raise("#{self.class.name} does not implement create_or_replace_record") raise("#{self.class.name} does not implement create_or_replace_record #{hostname}")
end end
def delete_record(hostname) def delete_record(hostname)
raise("#{self.class.name} does not implement delete_record") raise("#{self.class.name} does not implement delete_record for #{hostname}")
end end
end end
end end

View file

@ -116,7 +116,7 @@ module Vmpooler
dns_plugin = get_dns_plugin_class_for_pool(pool) dns_plugin = get_dns_plugin_class_for_pool(pool)
dns_plugin_class_name = get_dns_plugin_class_name_for_pool(pool) dns_plugin_class_name = get_dns_plugin_class_name_for_pool(pool)
domain = get_dns_plugin_domain_for_pool(pool) domain = get_dns_plugin_domain_for_pool(pool)
fqdn = vm + '.' + domain fqdn = "#{vm}.#{domain}"
dns_plugin.delete_record(fqdn) unless dns_plugin_class_name == 'dynamic-dns' dns_plugin.delete_record(fqdn) unless dns_plugin_class_name == 'dynamic-dns'
$logger.log('d', "[!] [#{pool}] '#{vm}' no longer exists. Removing from pending.") $logger.log('d', "[!] [#{pool}] '#{vm}' no longer exists. Removing from pending.")
end end
@ -512,7 +512,7 @@ module Vmpooler
provider.destroy_vm(pool, vm) provider.destroy_vm(pool, vm)
domain = get_dns_plugin_domain_for_pool(pool) domain = get_dns_plugin_domain_for_pool(pool)
fqdn = vm + '.' + domain fqdn = "#{vm}.#{domain}"
dns_plugin_class_name = get_dns_plugin_class_name_for_pool(pool) dns_plugin_class_name = get_dns_plugin_class_name_for_pool(pool)
dns_plugin.delete_record(fqdn) unless dns_plugin_class_name == 'dynamic-dns' dns_plugin.delete_record(fqdn) unless dns_plugin_class_name == 'dynamic-dns'
@ -712,8 +712,7 @@ module Vmpooler
return nil unless pool return nil unless pool
plugin_name = pool.fetch('dns_plugin') plugin_name = pool.fetch('dns_plugin')
plugin_class = Vmpooler::Dns.get_dns_plugin_class_by_name(config, plugin_name) Vmpooler::Dns.get_dns_plugin_class_by_name(config, plugin_name)
plugin_class
end end
def get_dns_plugin_class_for_pool(pool_name) def get_dns_plugin_class_for_pool(pool_name)
@ -730,8 +729,7 @@ module Vmpooler
return nil unless pool return nil unless pool
plugin_name = pool.fetch('dns_plugin') plugin_name = pool.fetch('dns_plugin')
plugin_domain = Vmpooler::Dns.get_dns_plugin_domain_by_name(config, plugin_name) Vmpooler::Dns.get_dns_plugin_domain_by_name(config, plugin_name)
plugin_domain
end end
def check_disk_queue(maxloop = 0, loop_delay = 5) def check_disk_queue(maxloop = 0, loop_delay = 5)

View file

@ -59,7 +59,7 @@ module Vmpooler
end end
def dns_config(dns_config_name) def dns_config(dns_config_name)
return Vmpooler::Dns.get_dns_plugin_domain_by_name(@config, dns_config_name) Vmpooler::Dns.get_dns_plugin_domain_by_name(@config, dns_config_name)
end end
# returns # returns
@ -262,7 +262,7 @@ module Vmpooler
end end
def get_vm_ip_address(vm_name, pool_name) def get_vm_ip_address(vm_name, pool_name)
raise("#{self.class.name} does not implement get_vm_ip_address") raise("#{self.class.name} does not implement get_vm_ip_address for vm #{vm_name} in pool #{pool_name}")
end end
# DEPRECATED if a provider does not implement the new method, it will hit this base class method # DEPRECATED if a provider does not implement the new method, it will hit this base class method