mirror of
https://github.com/puppetlabs/vmpooler.git
synced 2026-01-26 18:08:42 -05:00
This change adds a capability to vmpooler to provision instances on demand. Without this change vmpooler only supports retrieving machines from pre-provisioned pools. Additionally, this change refactors redis interactions to reduce round trips to redis. Specifically, multi and pipelined redis commands are added where possible to reduce the number of times we are calling redis. To support the redis refactor the redis interaction has changed to leveraging a connection pool. In addition to offering multiple connections for pool manager to use, the redis interactions in pool manager are now thread safe. Ready TTL is now a global parameter that can be set as a default for all pools. A default of 0 has been removed, because this is an unreasonable default behavior, which would leave a provisioned instance in the pool indefinitely. Pool empty messages have been removed when the pool size is set to 0. Without this change, when a pool was set to a size of 0 the API and pool manager would both show that a pool is empty.
246 lines
9.2 KiB
Ruby
246 lines
9.2 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Vmpooler
|
|
class PoolManager
|
|
class Provider
|
|
class Base
|
|
# These defs must be overidden in child classes
|
|
|
|
# Helper Methods
|
|
# Global Logger object
|
|
attr_reader :logger
|
|
# Global Metrics object
|
|
attr_reader :metrics
|
|
# Provider options passed in during initialization
|
|
attr_reader :provider_options
|
|
|
|
def initialize(config, logger, metrics, redis_connection_pool, name, options)
|
|
@config = config
|
|
@logger = logger
|
|
@metrics = metrics
|
|
@redis = redis_connection_pool
|
|
@provider_name = name
|
|
|
|
# Ensure that there is not a nil provider configuration
|
|
@config[:providers] = {} if @config[:providers].nil?
|
|
@config[:providers][@provider_name] = {} if provider_config.nil?
|
|
|
|
# Ensure that there is not a nil pool configuration
|
|
@config[:pools] = {} if @config[:pools].nil?
|
|
|
|
@provider_options = options
|
|
logger.log('s', "[!] Creating provider '#{name}'")
|
|
end
|
|
|
|
# Helper Methods
|
|
|
|
# inputs
|
|
# [String] pool_name : Name of the pool to get the configuration
|
|
# returns
|
|
# [Hashtable] : The pools configuration from the config file. Returns nil if the pool does not exist
|
|
def pool_config(pool_name)
|
|
# Get the configuration of a specific pool
|
|
@config[:pools].each do |pool|
|
|
return pool if pool['name'] == pool_name
|
|
end
|
|
|
|
nil
|
|
end
|
|
|
|
# returns
|
|
# [Hashtable] : This provider's configuration from the config file. Returns nil if the provider does not exist
|
|
def provider_config
|
|
@config[:providers].each do |provider|
|
|
# Convert the symbol from the config into a string for comparison
|
|
return (provider[1].nil? ? {} : provider[1]) if provider[0].to_s == @provider_name
|
|
end
|
|
|
|
nil
|
|
end
|
|
|
|
# returns
|
|
# [Hashtable] : The entire VMPooler configuration
|
|
def global_config
|
|
# This entire VM Pooler config
|
|
@config
|
|
end
|
|
|
|
# returns
|
|
# [String] : Name of the provider service
|
|
def name
|
|
@provider_name
|
|
end
|
|
|
|
# returns
|
|
# Array[String] : Array of pool names this provider services
|
|
def provided_pools
|
|
list = []
|
|
@config[:pools].each do |pool|
|
|
list << pool['name'] if pool['provider'] == name
|
|
end
|
|
list
|
|
end
|
|
|
|
# Pool Manager Methods
|
|
|
|
# inputs
|
|
# [String] pool_name : Name of the pool
|
|
# returns
|
|
# Array[Hashtable]
|
|
# Hash contains:
|
|
# 'name' => [String] Name of VM
|
|
def vms_in_pool(_pool_name)
|
|
raise("#{self.class.name} does not implement vms_in_pool")
|
|
end
|
|
|
|
# inputs
|
|
# [String]pool_name : Name of the pool
|
|
# [String] vm_name : Name of the VM
|
|
# returns
|
|
# [String] : Name of the host computer running the vm. If this is not a Virtual Machine, it returns the vm_name
|
|
def get_vm_host(_pool_name, _vm_name)
|
|
raise("#{self.class.name} does not implement get_vm_host")
|
|
end
|
|
|
|
# inputs
|
|
# [String] pool_name : Name of the pool
|
|
# [String] vm_name : Name of the VM
|
|
# returns
|
|
# [String] : Name of the most appropriate host computer to run this VM. Useful for load balancing VMs in a cluster
|
|
# If this is not a Virtual Machine, it returns the vm_name
|
|
def find_least_used_compatible_host(_pool_name, _vm_name)
|
|
raise("#{self.class.name} does not implement find_least_used_compatible_host")
|
|
end
|
|
|
|
# inputs
|
|
# [String] pool_name : Name of the pool
|
|
# [String] vm_name : Name of the VM to migrate
|
|
# [String] dest_host_name : Name of the host to migrate `vm_name` to
|
|
# returns
|
|
# [Boolean] : true on success or false on failure
|
|
def migrate_vm_to_host(_pool_name, _vm_name, _dest_host_name)
|
|
raise("#{self.class.name} does not implement migrate_vm_to_host")
|
|
end
|
|
|
|
# inputs
|
|
# [String] pool_name : Name of the pool
|
|
# [String] vm_name : Name of the VM to migrate
|
|
# [Class] redis : Redis object
|
|
def migrate_vm(_pool_name, _vm_name, _redis)
|
|
raise("#{self.class.name} does not implement migrate_vm")
|
|
end
|
|
|
|
# inputs
|
|
# [String] pool_name : Name of the pool
|
|
# [String] vm_name : Name of the VM to find
|
|
# returns
|
|
# nil if VM doesn't exist
|
|
# [Hastable] of the VM
|
|
# [String] name : Name of the VM
|
|
# [String] hostname : Name reported by Vmware tools (host.summary.guest.hostName)
|
|
# [String] template : This is the name of template exposed by the API. It must _match_ the poolname
|
|
# [String] poolname : Name of the pool the VM is located
|
|
# [Time] boottime : Time when the VM was created/booted
|
|
# [String] powerstate : Current power state of a VM. Valid values (as per vCenter API)
|
|
# - 'PoweredOn','PoweredOff'
|
|
def get_vm(_pool_name, _vm_name)
|
|
raise("#{self.class.name} does not implement get_vm")
|
|
end
|
|
|
|
# inputs
|
|
# [String] pool : Name of the pool
|
|
# [String] new_vmname : Name to give the new VM
|
|
# returns
|
|
# [Hashtable] of the VM as per get_vm
|
|
# Raises RuntimeError if the pool_name is not supported by the Provider
|
|
def create_vm(_pool_name, _new_vmname)
|
|
raise("#{self.class.name} does not implement create_vm")
|
|
end
|
|
|
|
# inputs
|
|
# [String] pool_name : Name of the pool
|
|
# [String] vm_name : Name of the VM to create the disk on
|
|
# [Integer] disk_size : Size of the disk to create in Gigabytes (GB)
|
|
# returns
|
|
# [Boolean] : true if success, false if disk could not be created
|
|
# Raises RuntimeError if the Pool does not exist
|
|
# Raises RuntimeError if the VM does not exist
|
|
def create_disk(_pool_name, _vm_name, _disk_size)
|
|
raise("#{self.class.name} does not implement create_disk")
|
|
end
|
|
|
|
# inputs
|
|
# [String] pool_name : Name of the pool
|
|
# [String] new_vmname : Name of the VM to create the snapshot on
|
|
# [String] new_snapshot_name : Name of the new snapshot to create
|
|
# returns
|
|
# [Boolean] : true if success, false if snapshot could not be created
|
|
# Raises RuntimeError if the Pool does not exist
|
|
# Raises RuntimeError if the VM does not exist
|
|
def create_snapshot(_pool_name, _vm_name, _new_snapshot_name)
|
|
raise("#{self.class.name} does not implement create_snapshot")
|
|
end
|
|
|
|
# inputs
|
|
# [String] pool_name : Name of the pool
|
|
# [String] new_vmname : Name of the VM to restore
|
|
# [String] snapshot_name : Name of the snapshot to restore to
|
|
# returns
|
|
# [Boolean] : true if success, false if snapshot could not be revertted
|
|
# Raises RuntimeError if the Pool does not exist
|
|
# Raises RuntimeError if the VM does not exist
|
|
# Raises RuntimeError if the snapshot does not exist
|
|
def revert_snapshot(_pool_name, _vm_name, _snapshot_name)
|
|
raise("#{self.class.name} does not implement revert_snapshot")
|
|
end
|
|
|
|
# inputs
|
|
# [String] pool_name : Name of the pool
|
|
# [String] vm_name : Name of the VM to destroy
|
|
# returns
|
|
# [Boolean] : true if success, false on error. Should returns true if the VM is missing
|
|
def destroy_vm(_pool_name, _vm_name)
|
|
raise("#{self.class.name} does not implement destroy_vm")
|
|
end
|
|
|
|
# inputs
|
|
# [String] pool_name : Name of the pool
|
|
# [String] vm_name : Name of the VM to check if ready
|
|
# returns
|
|
# [Boolean] : true if ready, false if not
|
|
def vm_ready?(_pool_name, _vm_name)
|
|
raise("#{self.class.name} does not implement vm_ready?")
|
|
end
|
|
|
|
# inputs
|
|
# [String] pool_name : Name of the pool
|
|
# [String] vm_name : Name of the VM to check if it exists
|
|
# returns
|
|
# [Boolean] : true if it exists, false if not
|
|
def vm_exists?(pool_name, vm_name)
|
|
!get_vm(pool_name, vm_name).nil?
|
|
end
|
|
|
|
# inputs
|
|
# [Hash] pool : Configuration for the pool
|
|
# returns
|
|
# nil when successful. Raises error when encountered
|
|
def create_template_delta_disks(_pool)
|
|
raise("#{self.class.name} does not implement create_template_delta_disks")
|
|
end
|
|
|
|
# inputs
|
|
# [String] provider_name : Name of the provider
|
|
# returns
|
|
# Hash of folders
|
|
def get_target_datacenter_from_config(_provider_name)
|
|
raise("#{self.class.name} does not implement get_target_datacenter_from_config")
|
|
end
|
|
|
|
def purge_unconfigured_folders(_base_folders, _configured_folders, _whitelist)
|
|
raise("#{self.class.name} does not implement purge_unconfigured_folders")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|