1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
|
module BeakerHostGenerator
# Defines an Interface for the implementation of a hypervisor, and provides
# a static module function `create(node_info, options)` for instantiating
# the appropriate hypervisor implementation.
#
# New hypervisor implementations must define the methods in the Interface
# class, and add a new element to the `builtin_hypervisors` map.
#
# Any number of hypervisors are used by a single Generator during host
# generation in the `BeakerHostGenerator::Generator#generate` method.
# Whenever a host specifies a specific hypervisor implementation, the
# Generator will instantiate the appropriate hypervisor via
# `BeakerHostGenerator::Hypervisor.create`.
module Hypervisor
# Static factory method to instantiate the appropriate hypervisor for the
# given node. If no hypervisor is specified in the node info, then the
# hypervisor specified in the options will be created. If the hypervisor is
# not a built-in implementation, then an `Unknown` instance will be used.
#
# @param node_info [Hash{String=>Object}] Node data parsed from the input
# spec string.
#
# @option options [String] :hypervisor The string name of the hypervisor to
# create.
def self.create(node_info, options)
name = node_info['host_settings']['hypervisor'] || options[:hypervisor]
hypervisor = builtin_hypervisors[name] || BeakerHostGenerator::Hypervisor::Unknown
hypervisor.new(name)
end
# Returns a map of all built-in hypervisor implementations, where the keys
# are the string names and the values are the implementation classes.
#
# The string names are part of the beaker-hostgenerator API as they are
# used for specifying the default or per-host hypervisor in the layout
# specification input string.
#
# @returns [Hash{String=>Hypervisor::Interface}] A map of hypervisor names
# and their implementations.
def self.builtin_hypervisors()
{
'vmpooler' => BeakerHostGenerator::Hypervisor::Vmpooler,
'vagrant' => BeakerHostGenerator::Hypervisor::Vagrant,
'vagrant_libvirt' => BeakerHostGenerator::Hypervisor::Vagrant,
'docker' => BeakerHostGenerator::Hypervisor::Docker,
'abs' => BeakerHostGenerator::Hypervisor::ABS
}
end
class Interface
def initialize(name)
@name = name
end
# Returns a map containing any general configuration required by this
# hypervisor. This map will be merged into the 'CONFIG' section of the
# final hosts configuration output.
#
# This will only be called if the hypervisor is used for a node, in which
# case the returned map will be merged in with global configuration from
# other hypervisors.
def global_config()
{}
end
# Returns a map of host configuration for a single node.
#
# This will be called for each individual node requested in the hosts
# specification input.
#
# Any configuration that is required by this hypervisor but is not
# specific to each node can be put in the `global_config` map.
#
# @param [Hash{String=>String}] node_info General info about the given
# node, such as the ostype, nodeid, and
# bits.
#
# @param [Hash{String=>Object}] base_config The node definition so far,
# which serves a starting point for this
# hypervisor to build upon. It is expected
# that this map will be merged into the map
# returned by this method.
#
# @param [Integer] bhg_version The version of OS info to use when building
# up the node definition.
def generate_node(node_info, base_config, bhg_version)
raise "Method 'generate_node' not implemented!"
end
private
def base_generate_node(node_info, base_config, bhg_version, *hypervisors)
platform = node_info['platform']
hypervisors.map do |hypervisor|
base_config.deeper_merge! get_platform_info(bhg_version, platform, hypervisor)
end
base_config['hypervisor'] = @name
return base_config
end
end
end
end
# Require the hypervisor implementations so they can be referenced/instantiated
# in the `create` factory method. We need to put these require statements at the
# bottom of this file to avoid circular references between this file and the
# hypervisor implementation files.
require 'beaker-hostgenerator/hypervisor/unknown'
require 'beaker-hostgenerator/hypervisor/vmpooler'
require 'beaker-hostgenerator/hypervisor/vagrant'
require 'beaker-hostgenerator/hypervisor/docker'
require 'beaker-hostgenerator/hypervisor/abs'
|