migrate backend to Train project

This commit is contained in:
Dominik Richter 2015-10-14 23:13:49 +02:00
parent 54b17fa8e1
commit be614e9056
32 changed files with 35 additions and 2151 deletions

View file

@ -11,7 +11,6 @@ libdir = File.dirname(__FILE__)
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
require 'vulcano/version'
require 'vulcano/backend'
require 'vulcano/resource'
require 'vulcano/rspec_json_formatter'
require 'vulcano/rule'

View file

@ -1,80 +0,0 @@
# encoding: utf-8
# author: Dominik Richter
# author: Christoph Hartmann
require 'uri'
require 'vulcano/plugins'
require 'vulcano/resource'
module Vulcano
class Backend
# Expose all registered backends
def self.registry
@registry ||= {}
end
# Resolve target configuration in URI-scheme into
# all respective fields and merge with existing configuration.
# e.g. ssh://bob@remote => backend: ssh, user: bob, host: remote
def self.target_config(config = nil) # rubocop:disable Metrics/AbcSize
conf = config.nil? ? {} : config.dup
# in case the user specified a key-file, register it that way
key = conf['key']
if !key.nil? and File.file?(key)
conf['key_file'] = key
end
return conf if conf['target'].to_s.empty?
uri = URI.parse(conf['target'].to_s)
unless uri.host.nil? and uri.scheme.nil?
conf['backend'] ||= uri.scheme
conf['host'] ||= uri.host
conf['port'] ||= uri.port
conf['user'] ||= uri.user
conf['password'] ||= uri.password
conf['path'] ||= uri.path
end
# ensure path is nil, if its empty; e.g. required to reset defaults for winrm
conf['path'] = nil if !conf['path'].nil? && conf['path'].to_s.empty?
# return the updated config
conf
end
def self.create(name, conf)
backend_class = @registry[name]
return nil if backend_class.nil?
backend_instance = backend_class.new(conf)
# Create wrapper class with all resources
cls = Class.new do
define_method :backend do
backend_instance
end
Vulcano::Resource.registry.each do |id, r|
define_method id.to_sym do |*args|
r.new(self, id.to_s, *args)
end
end
end
cls.new
end
end
def self.backend(version = 1)
if version != 1
fail 'Only backend version 1 is supported!'
end
Vulcano::Plugins::Backend
end
end
require 'vulcano/backend/docker'
require 'vulcano/backend/local'
require 'vulcano/backend/mock'
require 'vulcano/backend/specinfra'
require 'vulcano/backend/ssh'

View file

@ -1,46 +0,0 @@
# encoding: utf-8
# author: Dominik Richter
# author: Christoph Hartmann
require 'docker'
module Vulcano::Backends
class Docker < Vulcano.backend(1)
name 'docker'
attr_reader :os
def initialize(conf)
@conf = conf
@files = {}
id = @conf['host'] ||
fail('You must specify a docker container ID.')
@container = ::Docker::Container.get(id) ||
fail("Can't find Docker container #{id}")
@os = OS.new(self)
end
def file(path)
@files[path] ||= LinuxFile.new(self, path)
end
def run_command(cmd)
stdout, stderr, exit_status = @container.exec([
'/bin/sh', '-c', cmd
])
CommandResult.new(stdout.join, stderr.join, exit_status)
rescue ::Docker::Error::DockerError => _
raise
rescue => _
# @TODO: differentiate any other error
raise
end
class OS < OSCommon
def initialize(backend)
# hardcoded to unix/linux for now, until other operating systems
# are supported
super(backend, { family: 'unix' })
end
end
end
end

View file

@ -1,155 +0,0 @@
# encoding: utf-8
# author: Dominik Richter
# author: Christoph Hartmann
require 'etc'
require 'rbconfig'
require 'mixlib/shellout'
module Vulcano::Backends
class Local < Vulcano.backend(1)
name 'local'
attr_reader :os
def initialize(conf)
@conf = conf
@files = {}
@os = OS.new(self)
end
def file(path)
@files[path] ||= File.new(self, path)
end
def run_command(cmd)
Command.new(cmd)
end
def to_s
'Local Command Runner'
end
class OS < OSCommon
def initialize(backend)
super(backend, { family: detect_local_os })
end
private
def detect_local_os
case ::RbConfig::CONFIG['host_os']
when /aix(.+)$/
return 'aix'
when /darwin(.+)$/
return 'darwin'
when /hpux(.+)$/
return 'hpux'
when /linux/
return 'linux'
when /freebsd(.+)$/
return 'freebsd'
when /openbsd(.+)$/
return 'openbsd'
when /netbsd(.*)$/
return 'netbsd'
when /solaris2/
return 'solaris2'
when /mswin|mingw32|windows/
# After long discussion in IRC the "powers that be" have come to a consensus
# that no Windows platform exists that was not based on the
# Windows_NT kernel, so we herby decree that "windows" will refer to all
# platforms built upon the Windows_NT kernel and have access to win32 or win64
# subsystems.
return 'windows'
else
return ::RbConfig::CONFIG['host_os']
end
end
end
class Command
attr_reader :stdout, :stderr, :exit_status
def initialize(cmd)
@cmd = cmd
shellout = Mixlib::ShellOut.new(cmd)
shellout.run_command
@stdout = shellout.stdout
@stderr = shellout.stderr
@exit_status = shellout.exitstatus
rescue Errno::ENOENT => _
@exit_status ||= 1
end
end
class File < LinuxFile
def content
@content ||= ::File.read(@path, encoding: 'UTF-8')
rescue StandardError => _
nil
end
%w{
exist? file? socket? directory? symlink? pipe?
}.each do |m|
define_method m.to_sym do
::File.method(m.to_sym).call(@path)
end
end
def link_path
return nil unless symlink?
@link_path ||= ::File.readlink(@path)
end
def block_device?
::File.blockdev?(@path)
end
def character_device?
::File.chardev?(@path)
end
private
def pw_username(uid)
Etc.getpwuid(uid).name
rescue ArgumentError => _
nil
end
def pw_groupname(gid)
Etc.getgrgid(gid).name
rescue ArgumentError => _
nil
end
def stat
return @stat unless @stat.nil?
begin
file_stat = ::File.lstat(@path)
rescue StandardError => _err
return @stat = {}
end
@stat = {
type: Stat.find_type(file_stat.mode),
mode: file_stat.mode & 00777,
mtime: file_stat.mtime.to_i,
size: file_stat.size,
owner: pw_username(file_stat.uid),
group: pw_groupname(file_stat.gid),
}
res = @backend.run_command("stat #{@spath} 2>/dev/null --printf '%C'")
if res.exit_status == 0 && !res.stdout.empty? && res.stdout != '?'
@stat[:selinux_label] = res.stdout.strip
end
@stat
end
end
end
end

View file

@ -1,113 +0,0 @@
# encoding: utf-8
# author: Dominik Richter
# author: Christoph Hartmann
module Vulcano::Backends
Struct.new('MockCommand', :stdout, :stderr, :exit_status)
class Mock < Vulcano.backend(1)
name 'mock'
attr_accessor :files, :commands, :os
def initialize(conf = nil)
@conf = conf || {}
@files = {}
@os = {}
@commands = {}
trace_calls if @conf[:verbose]
end
def file(path)
@files[path] ||= File.new(self, path)
end
def run_command(cmd)
@commands[cmd] || @commands[Digest::SHA256.hexdigest cmd] || Command.new(self, cmd)
end
def mock_command(stdout, stderr, exit_status)
Struct::MockCommand.new(stdout, stderr, exit_status)
end
def to_s
'Mock Backend Runner'
end
def os=(value)
@os = OS.new(self, value)
end
class OS < OSCommon
def initialize(backend, desc)
super(backend, desc)
end
def detect_family
# no op, we do not need to detect the os
end
end
private
def trace_calls
interface_methods = {
'Vulcano::Backends::Mock' => Vulcano::Backends::Mock.instance_methods(false),
'Vulcano::Backends::Mock::File' => FileCommon.instance_methods(false),
}
# rubocop:disable Metrics/ParameterLists
# rubocop:disable Lint/Eval
set_trace_func proc { |event, _file, _line, id, binding, classname|
unless classname.to_s.start_with?('Vulcano::Backends::Mock') and
event == 'call' and
interface_methods[classname.to_s].include?(id)
next
end
# kindly borrowed from the wonderful simple-tracer by matugm
arg_names = eval(
'method(__method__).parameters.map { |arg| arg[1].to_s }',
binding)
args = eval("#{arg_names}.map { |arg| eval(arg) }", binding).join(', ')
prefix = '-' * (classname.to_s.count(':') - 2) + '> '
puts("#{prefix}#{id} #{args}")
}
# rubocop:enable all
end
end
class Mock
class File < FileCommon
def initialize(_runtime, path)
@path = path
# mock dataset
@exist = (rand < 0.8) ? true : false
@is_file = (@exist && rand < 0.7) ? true : false
@size = 0
@content = ''
if @exist && @is_file
@size = (rand**3 * 1000).to_i
@size = 0 if rand < 0.2
end
if @size > 0
@content = (0...50).map { ('a'..'z').to_a[rand(26)] }.join
end
@content
end
%w{ size content file? exist? }.each do |m|
define_method m.to_sym do
instance_variable_get(m.sub('?', '').to_sym)
end
end
end
class Command
attr_accessor :stdout, :stderr, :exit_status
def initialize(_runtime, _cmd)
@exit_code = (rand < 0.7) ? 0 : (100 * rand).to_i
@stdout = (0...50).map { ('a'..'z').to_a[rand(26)] }.join
@stderr = (0...50).map { ('a'..'z').to_a[rand(26)] }.join
end
end
end
end

View file

@ -1,124 +0,0 @@
# encoding: utf-8
# author: Dominik Richter
# author: Christoph Hartmann
require 'shellwords'
require 'specinfra'
require 'specinfra/helper'
require 'specinfra/helper/set'
module Vulcano::Backends
class SpecinfraHelper < Vulcano.backend(1)
name 'specinfra'
autoload :Docker, 'vulcano/backend/specinfra_docker'
autoload :Exec, 'vulcano/backend/specinfra_exec'
autoload :Ssh, 'vulcano/backend/specinfra_ssh'
autoload :Winrm, 'vulcano/backend/specinfra_winrm'
autoload :File, 'vulcano/backend/specinfra_file'
autoload :OS, 'vulcano/backend/specinfra_os'
attr_reader :os
def initialize(conf)
@conf = conf
@files = {}
configure_shared_options
type = @conf['backend'].to_s
type = 'exec' if type.empty?
case type
when 'docker'
spec_backend = Specinfra::Backend::Docker
backend_helper = Docker
when 'exec'
spec_backend = Specinfra::Backend::Exec
backend_helper = Exec
when 'ssh'
spec_backend = Specinfra::Backend::Ssh
backend_helper = Ssh
when 'winrm', 'winrms'
@conf['ssl'] = true if type == 'winrms'
spec_backend = Specinfra::Backend::Winrm
backend_helper = Winrm
else
fail "Cannot configure Specinfra backend #{type}: it isn't supported yet."
end
reset_backend(spec_backend)
backend_helper.configure(@conf)
@os = OS.new
end
def file(path)
@files[path] ||= File.new(self, path)
end
def run_command(cmd)
Specinfra::Runner.run_command(cmd)
end
def to_s
'SpecInfra Backend Runner'
end
def configure_shared_options
Specinfra::Backend::Cmd.send(:include, Specinfra::Helper::Set)
# Force specinfra to disregard any locally detected backend and instead
# retry backend detection.
Specinfra::Properties.instance.properties({})
si = Specinfra.configuration
if @conf['disable_sudo']
si.disable_sudo = true
else
si.sudo_password = @conf['sudo_password']
si.sudo_options = @conf['sudo_options']
end
end
def reset_backend(x)
x.instance_variable_set(:@instance, nil)
end
end
end
# Patch Specinfra OS detection
# Without this section you run into:
# SystemStackError: stack level too deep
module Specinfra
module Helper
module Os
def os
property[:os] = {} if !property[:os]
if !property[:os].include?(:family)
property[:os] = detect_os
end
property[:os]
end
private
def detect_os
backend = Specinfra.configuration.backend
if backend == :cmd || backend == :winrm
return { family: 'windows', release: nil, arch: nil }
end
Specinfra::Helper::DetectOs.subclasses.each do |c|
res = c.detect
if res
res[:arch] ||= Specinfra.backend.run_command('uname -m').stdout.strip
return res
end
end
fail NotImplementedError, 'Specinfra failed os detection.'
end
end
end
end

View file

@ -1,13 +0,0 @@
# encoding: utf-8
# author: Dominik Richter
# author: Christoph Hartmann
class Vulcano::Backends::SpecinfraHelper
module Docker
def self.configure(_conf)
host = @conf['host'].to_s
Specinfra.configuration.backend = :docker
Specinfra.configuration.docker_container = host
end
end
end

View file

@ -1,11 +0,0 @@
# encoding: utf-8
# author: Dominik Richter
# author: Christoph Hartmann
class Vulcano::Backends::SpecinfraHelper
module Exec
def self.configure(_conf)
Specinfra.configuration.backend = :exec
end
end
end

View file

@ -1,123 +0,0 @@
# encoding: utf-8
# author: Dominik Richter
# author: Christoph Hartmann
class Vulcano::Backends::SpecinfraHelper
class File < LinuxFile
def initialize(backend, path)
super(backend, path)
end
def exist?
Specinfra::Runner.check_file_exists(@path)
end
def mode
return stat[:mode] if @backend.os.bsd?
m = Specinfra::Runner.get_file_mode(@path).stdout.strip
return nil if m.empty? || m.include?('cannot stat')
m.to_i(8)
end
def owner
return stat[:owner] if @backend.os.bsd?
o = Specinfra::Runner.get_file_owner_user(@path).stdout.strip
return nil if o.empty? || o.include?('cannot stat')
o
end
def group
return stat[:group] if @backend.os.bsd?
g = Specinfra::Runner.get_file_owner_group(@path).stdout.strip
return nil if g.empty? || g.include?('cannot stat')
g
end
def link_path
return nil unless symlink?
path = Shellwords.escape(@path)
Specinfra::Runner.run_command("readlink #{path}").stdout.strip
end
def content
s = Specinfra::Runner.get_file_content(@path).stdout
# if we get some content, return it
return s unless s.empty?
# if we didn't get any content, we have to decide if this is
# really an empty file (i.e. where content == empty string)
# or if something else is going on.
# in case it is a folder or the path doesn't exist, always
# return nil instead of empty content
return nil if directory? or !exist?
# in case we can't get the size, something is wrong, so return nil
# in case the size is non-zero, we couldn't read the file, so
# return nil to indicate that
i = size
return nil if i.nil? or i > 0
# return the empty string, as the file doesn't contain anything
s
end
def md5sum
s = Specinfra::Runner.get_file_md5sum(@path).stdout.strip
return nil if s.empty? or s.include?(' ')
s
end
def sha256sum
s = Specinfra::Runner.get_file_sha256sum(@path).stdout.strip
return nil if s.empty? or s.include?(' ')
s
end
def mtime
mt = Specinfra::Runner.get_file_mtime(@path).stdout.strip
return nil if mt.empty? || mt.include?(' ')
mt.to_i
end
def size
s = Specinfra::Runner.get_file_size(@path).stdout.strip
return nil if s.empty? || s.include?(' ')
s.to_i
end
def selinux_label
res = Specinfra::Runner.get_file_selinuxlabel(@path).stdout.strip
return nil if res.empty? or res == '?' or
res.include?('failed to get security context') or
res.include?('cannot stat')
res
rescue NotImplementedError => _
nil
end
def mounted?(opts = {}, only_with = nil)
Specinfra::Runner.check_file_is_mounted(@path, opts, only_with)
end
def immutable?
Specinfra::Runner.get_file_immutable(@path)
end
def product_version
return nil unless @backend.os[:family] == 'windows'
res = Specinfra::Runner.
run_command("(Get-Command '#{@path}').FileVersionInfo.ProductVersion").
stdout.strip
res.empty? ? nil : res
end
def file_version
return nil unless @backend.os[:family] == 'windows'
res = Specinfra::Runner.
run_command("(Get-Command '#{@path}').FileVersionInfo.FileVersion").
stdout.strip
res.empty? ? nil : res
end
end
end

View file

@ -1,11 +0,0 @@
# encoding: utf-8
# author: Dominik Richter
# author: Christoph Hartmann
class Vulcano::Backends::SpecinfraHelper
class OS < OSCommon
def initialize
@platform = Specinfra::Helper::Os.os
end
end
end

View file

@ -1,55 +0,0 @@
# encoding: utf-8
# author: Dominik Richter
# author: Christoph Hartmann
class Vulcano::Backends::SpecinfraHelper
module Ssh
def self.validate_options(ssh_opts)
unless ssh_opts[:port] > 0
fail "Port must be > 0 (not #{ssh_opts[:port]})"
end
if ssh_opts[:user].to_s.empty?
fail 'User must not be empty.'
end
unless ssh_opts[:keys].empty?
ssh_opts[:auth_methods].push('publickey')
ssh_opts[:keys_only] = true if ssh_opts[:password].nil?
end
unless ssh_opts[:password].nil?
ssh_opts[:auth_methods].push('password')
end
if ssh_opts[:keys].empty? and ssh_opts[:password].nil?
fail 'You must configure at least one authentication method' \
': Password or key.'
end
end
def self.configure(conf)
si = Specinfra.configuration
si.backend = :ssh
si.request_pty = true
host = conf['host'].to_s
fail 'You must configure a target host.' if host.empty?
si.host = host
ssh_opts = {
port: conf['port'] || 22,
auth_methods: ['none'],
user_known_hosts_file: '/dev/null',
global_known_hosts_file: '/dev/null',
number_of_password_prompts: 0,
user: conf['user'] || 'root',
password: conf['password'],
keys: [conf['key_file']].compact,
}
validate_options(ssh_opts)
si.ssh_options = ssh_opts
end
end
end

View file

@ -1,57 +0,0 @@
# encoding: utf-8
# author: Dominik Richter
# author: Christoph Hartmann
require 'winrm'
class Vulcano::Backends::SpecinfraHelper
module Winrm
def self.winrm_url(conf)
host = conf['host'].to_s
port = conf['port']
fail 'You must configure a target host.' if host.empty?
# SSL configuration
if conf['ssl']
scheme = 'https'
port ||= 5986
else
scheme = 'http'
port ||= 5985
end
path = conf['path'] || '/wsman'
path.prepend('/') unless path.start_with?('/')
"#{scheme}://#{host}:#{port}#{path}"
end
def self.configure(conf)
si = Specinfra.configuration
si.backend = :winrm
si.os = { family: 'windows' }
# validation
user = conf['user'].to_s
pass = conf['password'].to_s
if user.empty?
warn "We use default 'Administrator' as WinRM user for login."
user = 'Administrator'
end
fail 'You must configure a WinRM password.' if pass.empty?
# create the connection
endpoint = winrm_url(conf)
winrm = ::WinRM::WinRMWebService.new(
endpoint,
:ssl,
user: user,
pass: pass,
basic_auth_only: true,
no_ssl_peer_verification: conf['self_signed'],
)
si.winrm = winrm
end
end
end

View file

@ -1,106 +0,0 @@
# encoding: utf-8
# author: Dominik Richter
# author: Christoph Hartmann
module Vulcano::Backends
class SSH < Vulcano.backend(1)
name 'ssh'
attr_reader :os
def initialize(conf)
@conf = conf
@files = {}
@conf['host'] ||
fail('You must specify a SSH host.')
@ssh = start_ssh
@os = OS.new(self)
end
def file(path)
@files[path] ||= LinuxFile.new(self, path)
end
def run_command(cmd)
stdout = stderr = ''
exit_status = nil
cmd.force_encoding('binary') if cmd.respond_to?(:force_encoding)
@ssh.open_channel do |channel|
channel.exec(cmd) do |_, success|
unless success
abort 'Couldn\'t execute command on SSH.'
end
channel.on_data do |_, data|
stdout += data
end
channel.on_extended_data do |_, _type, data|
stderr += data
end
channel.on_request('exit-status') do |_, data|
exit_status = data.read_long
end
channel.on_request('exit-signal') do |_, data|
exit_status = data.read_long
end
end
end
@ssh.loop
CommandResult.new(stdout, stderr, exit_status)
end
private
def validate_options(options)
if options[:keys].empty? and options[:password].nil?
fail 'You must configure at least one authentication method for SSH:'\
' Password or key.'
end
unless options[:keys].empty?
options[:auth_methods].push('publickey')
options[:keys_only] = true if options[:password].nil?
end
# rubocop:disable Style/GuardClause
unless options[:password].nil?
options[:auth_methods].push('password')
end
# rubocop:enable Style/GuardClause
end
def start_ssh
host = @conf['host']
ssh_config = Net::SSH.configuration_for(host)
user = @conf['user'] || ssh_config[:user]
keys = [@conf['key_file'], ssh_config[:keys]].flatten.compact
options = {
port: @conf['port'] || ssh_config[:port] || 22,
auth_methods: ['none'],
user_known_hosts_file: '/dev/null',
global_known_hosts_file: '/dev/null',
number_of_password_prompts: 0,
keepalive: true,
keepalive_interval: 60,
compression: true,
compression_level: 6,
password: @conf['password'] || ssh_config[:password],
keys: keys,
}
validate_options(options)
Net::SSH.start(host, user, options)
end
class OS < OSCommon
def initialize(backend)
super(backend, { family: 'unix' })
end
end
end
end

View file

@ -5,6 +5,5 @@
module Vulcano
module Plugins
autoload :Resource, 'vulcano/plugins/resource'
autoload :Backend, 'vulcano/plugins/backend'
end
end

View file

@ -1,29 +0,0 @@
# encoding: utf-8
# author: Dominik Richter
# author: Christoph Hartmann
require 'digest'
module Vulcano::Plugins
class Backend
autoload :FileCommon, 'vulcano/plugins/backend_file_common'
autoload :LinuxFile, 'vulcano/plugins/backend_linux_file'
autoload :OSCommon, 'vulcano/plugins/backend_os_common'
CommandResult = Struct.new(:stdout, :stderr, :exit_status)
def self.name(name)
Vulcano::Plugins::Backend.__register(name, self)
end
# raise errors for all missing methods
%w{ file run_command os }.each do |m|
define_method(m.to_sym) do |*_|
fail NotImplementedError, "Backend must implement the #{m}() method."
end
end
def self.__register(id, obj)
Vulcano::Backend.registry[id] = obj
end
end
end

View file

@ -1,32 +0,0 @@
# encoding: utf-8
# author: Dominik Richter
# author: Christoph Hartmann
#
# This is heavily based on:
#
# OHAI https://github.com/chef/ohai
# by Adam Jacob, Chef Software Inc
#
class Vulcano::Plugins::Backend
module DetectDarwin
def detect_darwin
cmd = @backend.run_command('/usr/bin/sw_vers')
# TODO: print an error in this step of the detection,
# as it shouldnt happen
return false if cmd.exit_status != 0
# TODO: ditto on error
return false if cmd.stdout.empty?
name = cmd.stdout[/^ProductName:\s+(.+)$/, 1]
# TODO: ditto on error
return false if name.nil?
@platform[:name] = name.downcase.chomp.tr(' ', '_')
@platform[:release] = cmd.stdout[/^ProductVersion:\s+(.+)$/, 1]
@platform[:build] = cmd.stdout[/^BuildVersion:\s+(.+)$/, 1]
# TODO: keep for now due to backwards compatibility with serverspec
@platform[:family] = 'darwin'
true
end
end
end

View file

@ -1,126 +0,0 @@
# encoding: utf-8
# author: Dominik Richter
# author: Christoph Hartmann
#
# This is heavily based on:
#
# OHAI https://github.com/chef/ohai
# by Adam Jacob, Chef Software Inc
#
require 'vulcano/plugins/backend_linux_lsb'
class Vulcano::Plugins::Backend
module DetectLinux
include LinuxLSB
def detect_linux_via_config # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
if !(raw = get_config('oracle-release')).nil?
@platform[:family] = 'oracle'
@platform[:release] = redhatish_version(raw)
elsif !(raw = get_config('/etc/enterprise-release')).nil?
@platform[:family] = 'oracle'
@platform[:release] = redhatish_version(raw)
elsif !(_raw = get_config('/etc/debian_version')).nil?
case lsb[:id]
when /ubuntu/i
@platform[:family] = 'ubuntu'
@platform[:release] = lsb[:release]
when /linuxmint/i
@platform[:family] = 'linuxmint'
@platform[:release] = lsb[:release]
else
@platform[:family] = 'debian'
@platform[:family] = 'raspbian' if unix_file?('/usr/bin/raspi-config')
if !(rel = get_config('/etc/debian_version')).nil?
@platform[:release] = rel.chomp
end
end
elsif !(raw = get_config('/etc/parallels-release')).nil?
@platform[:family] = redhatish_platform(raw)
@platform[:release] = raw[/(\d\.\d\.\d)/, 1]
elsif !(raw = get_config('/etc/redhat-release')).nil?
# TODO: Cisco
# TODO: fully investigate os-release and integrate it;
# here we just use it for centos
if !(osrel = get_config('/etc/os-release')).nil? && osrel =~ /centos/i
@platform[:family] = 'centos'
else
@platform[:family] = redhatish_platform(raw)
end
@platform[:release] = redhatish_version(raw)
elsif !(raw = get_config('/etc/system-release')).nil?
# Amazon Linux
@platform[:family] = redhatish_platform(raw)
@platform[:release] = redhatish_version(raw)
elsif !(suse = get_config('/etc/SuSE-release')).nil?
version = suse.scan(/VERSION = (\d+)\nPATCHLEVEL = (\d+)/).flatten.join('.')
version = suse[/VERSION = ([\d\.]{2,})/, 1] if version == ''
@platform[:release] = version
@platform[:family] = 'suse'
@platform[:family] = 'opensuse' if suse =~ /^openSUSE/
elsif !(raw = get_config('/etc/arch-release')).nil?
@platform[:family] = 'arch'
# Because this is a rolling release distribution,
# use the kernel release, ex. 4.1.6-1-ARCH
@platform[:release] = uname_r
elsif !(raw = get_config('/etc/slackware-version')).nil?
@platform[:family] = 'slackware'
@platform[:release] = raw.scan(/(\d+|\.+)/).join
elsif !(raw = get_config('/etc/exherbo-release')).nil?
@platform[:family] = 'exherbo'
# Because this is a rolling release distribution,
# use the kernel release, ex. 4.1.6
@platform[:release] = uname_r
elsif !(raw = get_config('/etc/gentoo-release')).nil?
@platform[:family] = 'gentoo'
@platform[:release] = raw.scan(/(\d+|\.+)/).join
elsif !(raw = get_config('/etc/alpine-release')).nil?
@platform[:family] = 'alpine'
@platform[:release] = raw.strip
elsif !(raw = get_config('/etc/coreos/update.conf')).nil?
@platform[:family] = 'coreos'
meta = lsb_config(raw)
@platform[:release] = meta[:release]
else
# in all other cases we didn't detect it
return false
end
# when we get here the detection returned a result
true
end
def uname_s
@uname_s ||= @backend.run_command('uname -s').stdout
end
def uname_r
@uname_r ||= (
res = @backend.run_command('uname -r').stdout
res.strip! unless res.nil?
res
)
end
def redhatish_platform(conf)
conf[/^red hat/i] ? 'redhat' : conf[/(\w+)/i, 1].downcase
end
def redhatish_version(conf)
return conf[/((\d+) \(Rawhide\))/i, 1].downcase if conf[/rawhide/i]
return conf[/Linux ((\d+|\.)+)/i, 1] if conf[/derived from .*linux/i]
conf[/release ([\d\.]+)/, 1]
end
def detect_linux
# TODO: print an error in this step of the detection
return false if uname_s.nil? || uname_s.empty?
return false if uname_r.nil? || uname_r.empty?
return true if detect_linux_via_config
return true if detect_linux_via_lsb
# in all other cases we failed the detection
@platform[:family] = 'unknown'
end
end
end

View file

@ -1,77 +0,0 @@
# encoding: utf-8
# author: Dominik Richter
# author: Christoph Hartmann
#
# This is heavily based on:
#
# OHAI https://github.com/chef/ohai
# by Adam Jacob, Chef Software Inc
#
class Vulcano::Plugins::Backend
module DetectUnix
def detect_via_uname # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
case uname_s.downcase
when /aix/
@platform[:family] = 'aix'
out = @backend.run_command('uname -rvp').stdout
m = out.match(/(\d+)\s+(\d+)\s+(.*)/)
unless m.nil?
@platform[:release] = "#{m[2]}.#{m[1]}"
@platform[:arch] = m[3].to_s
end
when /freebsd/
@platform[:family] = 'freebsd'
@platform[:name] = uname_s.lines[0].chomp
@platform[:release] = uname_r.lines[0].chomp
when /netbsd/
@platform[:family] = 'netbsd'
@platform[:name] = uname_s.lines[0].chomp
@platform[:release] = uname_r.lines[0].chomp
when /openbsd/
@platform[:family] = 'openbsd'
@platform[:name] = uname_s.lines[0].chomp
@platform[:release] = uname_r.lines[0].chomp
when /sunos/
@platform[:family] = 'solaris'
if uname_r =~ /5\.10/
# TODO: should be string!
@platform[:release] = 10
else
rel = get_config('/etc/release')
case rel
when /^.*(SmartOS).*$/
@platform[:family] = 'smartos'
when !(m = /^\s*(OmniOS).*r(\d+).*$/).nil?
@platform[:family] = 'omnios'
@platform[:release] = m[2]
when !(m = /^\s*(OpenIndiana).*oi_(\d+).*$/).nil?
@platform[:family] = 'openindiana'
@platform[:release] = m[2]
when /^\s*(OpenSolaris).*snv_(\d+).*$/
@platform[:family] = 'opensolaris'
@platform[:release] = m[2]
when !(m = /Oracle Solaris (\d+)/).nil?
# TODO: should be string!
@platform[:release] = m[1].to_i
@platform[:family] = 'solaris2'
when /^\s*(Solaris)\s.*$/
@platform[:family] = 'solaris2'
when /^\s*(NexentaCore)\s.*$/
@platform[:family] = 'nexentacore'
end
end
else
# in all other cases we didn't detect it
return false
end
# when we get here the detection returned a result
true
end
end
end

View file

@ -1,72 +0,0 @@
# encoding: utf-8
# author: Dominik Richter
# author: Christoph Hartmann
#
# This is heavily based on:
#
# OHAI https://github.com/chef/ohai
# by Adam Jacob, Chef Software Inc
#
class Vulcano::Plugins::Backend
module DetectWindows
# See: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724832%28v=vs.85%29.aspx
# Product Type:
# Work Station (1)
# Domain Controller (2)
# Server (3)
WINDOWS_VERSIONS = {
'0' => '3.1',
'140' => '95',
'1410' => '98',
'1490' => 'ME',
'1351' => 'NT 3.51',
'3351' => 'NT 3.51 Server',
'1240' => 'NT 4.0',
'3240' => 'NT 4.0 Server',
'1250' => '2000',
'1251' => 'XP',
'3252' => 'Server 2003',
'1252' => 'Vista',
'3260' => 'Server 2008',
'1261' => '7',
'3261' => 'Server 2008 R2',
'1262' => '8',
'3262' => 'Server 2012',
'1263' => '8.1',
'3263' => 'Server 2012 R2',
'12100' => '10',
'32100' => 'Server 2016',
}
def windows_version(json)
producttype = json['OS']['ProductType'].to_s
# do not distigush between domain controller and server
producttype = '3' if producttype == '2'
platform = json['OSVersion']['Platform'].to_s
major = json['OSVersion']['Version']['Major'].to_s
minor = json['OSVersion']['Version']['Minor'].to_s
# construct it
producttype + platform + major + minor
end
def detect_windows
cmd = 'New-Object -Type PSObject | Add-Member -MemberType NoteProperty '\
'-Name OS -Value (Get-WmiObject -Class Win32_OperatingSystem) '\
'-PassThru | Add-Member -MemberType NoteProperty -Name OSVersion '\
'-Value ([Environment]::OSVersion) -PassThru | ConvertTo-Json'
res = @backend.run_command(cmd)
# TODO: error as this shouldnt be happening at this point
return false if res.exit_status != 0 or res.stdout.empty?
json = JSON.parse(res.stdout)
return false if json.nil? or json.empty?
version = windows_version(json)
@platform[:family] = 'windows'
@platform[:name] = WINDOWS_VERSIONS[version]
@platform[:release] = version
true
end
end
end

View file

@ -1,129 +0,0 @@
# encoding: utf-8
# author: Dominik Richter
# author: Christoph Hartmann
class Vulcano::Plugins::Backend
class FileCommon
autoload :Stat, 'vulcano/plugins/backend_stat'
# interface methods: these fields should be implemented by every
# backend File
%w{
exist? mode owner group link_target link_path content mtime size
selinux_label product_version file_version path
}.each do |m|
define_method m.to_sym do
fail NotImplementedError, "File must implement the #{m}() method."
end
end
def type
:unknown
end
# The following methods can be overwritten by a derived class
# if desired, to e.g. achieve optimizations.
def md5sum
res = Digest::MD5.new
res.update(content)
res.hexdigest
rescue TypeError => _
nil
end
def sha256sum
res = Digest::SHA256.new
res.update(content)
res.hexdigest
rescue TypeError => _
nil
end
# Additional methods for convenience
def file?
target_type == :file
end
def block_device?
target_type == :block_device
end
def character_device?
target_type == :character_device
end
def socket?
target_type == :socket
end
def directory?
target_type == :directory
end
def symlink?
type == :symlink
end
def pipe?
target_type == :pipe
end
def mode?(sth)
mode == sth
end
def owned_by?(sth)
owner == sth
end
def grouped_into?(sth)
group == sth
end
def linked_to?(dst)
link_path == dst
end
def version?(version)
product_version == version or
file_version == version
end
# helper methods provided to any implementing class
private
def target_type
# Just return the type unless this is a symlink
return type unless type == :symlink
# Get the link's target type, i.e. the real destination's type
return link_target.type unless link_target.nil?
# Return unknown if we don't know where this is pointing to
:unknown
end
UNIX_MODE_OWNERS = {
owner: 00700,
group: 00070,
other: 00007,
}
UNIX_MODE_TYPES = {
r: 00444,
w: 00222,
x: 00111,
}
def unix_mode_mask(owner, type)
o = UNIX_MODE_OWNERS[owner.to_sym]
return nil if o.nil?
t = UNIX_MODE_TYPES[type.to_sym]
return nil if t.nil?
t & o
end
end
end

View file

@ -1,77 +0,0 @@
# encoding: utf-8
# author: Dominik Richter
# author: Christoph Hartmann
require 'shellwords'
class Vulcano::Plugins::Backend
class LinuxFile < FileCommon
attr_reader :path
def initialize(backend, path)
@backend = backend
@path = path
@spath = Shellwords.escape(@path)
end
def content
return @content if @content_fetched
@content = @backend.run_command(
"cat #{@spath} || echo -n").stdout
@content_fetched = true
return @content unless @content.empty?
@content = nil if directory? or size.nil? or size > 0
@content
end
def exist?
@exist ||= (
@backend.
run_command("test -e #{@spath}").
exit_status == 0
)
end
def link_target
return @link_target unless @link_target.nil?
return @link_target = nil if link_path.nil?
@link_target = @backend.file(link_path)
end
def link_path
return nil unless symlink?
@link_path ||= (
@backend.
run_command("readlink #{@spath}").stdout.chomp
)
end
def mounted?
@mounted ||= (
!@backend.
run_command("mount | grep -- ' on #{@spath}'").
stdout.empty?
)
end
%w{
type mode owner group mtime size selinux_label
}.each do |field|
define_method field.to_sym do
stat[field.to_sym]
end
end
def product_version
nil
end
def file_version
nil
end
def stat
return @stat if defined?(@stat)
@stat = Stat.stat(@spath, @backend)
end
end
end

View file

@ -1,60 +0,0 @@
# encoding: utf-8
# author: Dominik Richter
# author: Christoph Hartmann
#
# This is heavily based on:
#
# OHAI https://github.com/chef/ohai
# by Adam Jacob, Chef Software Inc
#
class Vulcano::Plugins::Backend
module LinuxLSB
def lsb_config(content)
{
id: content[/^DISTRIB_ID=["']?(.+?)["']?$/, 1],
release: content[/^DISTRIB_RELEASE=["']?(.+?)["']?$/, 1],
codename: content[/^DISTRIB_CODENAME=["']?(.+?)["']?$/, 1],
}
end
def lsb_release
raw = @backend.run_command('lsb_release -a').stdout
{
id: raw[/^Distributor ID:\s+(.+)$/, 1],
release: raw[/^Release:\s+(.+)$/, 1],
codename: raw[/^Codename:\s+(.+)$/, 1],
}
end
def lsb
return @lsb if defined?(@lsb)
@lsb = {}
if !(raw = get_config('/etc/lsb-release')).nil?
@lsb = lsb_config(raw)
elsif unix_file?('/usr/bin/lsb_release')
@lsb = lsb_release
end
@lsb
end
def detect_linux_via_lsb
return false if lsb[:id].nil?
id = lsb[:id].downcase
case id
when /redhat/
@platform[:family] = 'redhat'
when /amazon/
@platform[:family] = 'amazon'
when /scientificsl/
@platform[:family] = 'scientific'
when /xenserver/
@platform[:family] = 'xenserver'
else
@platform[:family] = id
end
@platform[:release] = lsb[:release]
true
end
end
end

View file

@ -1,127 +0,0 @@
# encoding: utf-8
# author: Dominik Richter
# author: Christoph Hartmann
#
# This is heavily based on:
#
# OHAI https://github.com/chef/ohai
# by Adam Jacob, Chef Software Inc
#
require 'vulcano/plugins/backend_detect_darwin'
require 'vulcano/plugins/backend_detect_linux'
require 'vulcano/plugins/backend_detect_unix'
require 'vulcano/plugins/backend_detect_windows'
class Vulcano::Plugins::Backend
class OSCommon
include DetectDarwin
include DetectLinux
include DetectUnix
include DetectWindows
def initialize(backend, platform = nil)
@backend = backend
@platform = platform || {}
detect_family
end
def [](key)
@platform[key]
end
OS = {
'redhat' => %w{
redhat oracle centos fedora amazon scientific xenserver
},
'debian' => %w{
debian ubuntu linuxmint raspbian
},
'suse' => %w{
suse opensuse
},
'bsd' => %w{
freebsd netbsd openbsd darwin
},
'solaris' => %w{
solaris smartos openindiana opensolaris solaris2 nexentacore
},
'windows' => %w{
windows
},
}
OS['linux'] = %w{alpine arch coreos exherbo gentoo slackware} +
OS['redhat'] + OS['debian'] + OS['suse']
OS['unix'] = %w{unix aix} + OS['linux'] + OS['solaris'] + OS['bsd']
# Helper methods to check the OS type
# Provides methods in the form of: linux?, unix?, solaris? ...
OS.keys.each do |os_family|
define_method((os_family+'?').to_sym) do
OS[os_family].include?(@platform[:family])
end
end
private
def detect_family
# if some information is already defined, try to verify it
# with the remaining detection
unless @platform[:family].nil?
# return ok if the preconfigured family yielded a good result
return true if detect_family_type
# if not, reset the platform to presets and run the full detection
# TODO: print an error message in this case, as the instantiating
# backend is doing something wrong
@platform = {}
end
# TODO: extend base implementation for detecting the family type
# to Windows and others
case uname_s
when /linux/i
@platform[:family] = 'linux'
when /./
@platform[:family] = 'unix'
else
# Don't know what this is
@platform[:family] = nil
end
# try to detect the platform
return nil unless @platform[:family].nil?
detect_family_type
end
def detect_family_type
pf = @platform[:family]
return detect_windows if pf == 'windows'
return detect_darwin if pf == 'darwin'
if %w{freebsd netbsd openbsd aix solaris2}.include?(pf)
return detect_via_uname
end
# unix based systems combine the above
return true if pf == 'unix' and detect_darwin
return true if pf == 'unix' and detect_via_uname
# if we arrive here, we most likey have a regular linux
detect_linux
end
def get_config(path)
res = @backend.run_command("test -f #{path} && cat #{path}")
# ignore files that can't be read
return nil if res.exit_status != 0
res.stdout
end
def unix_file?(path)
@backend.run_command("test -f #{path}").exit_status == 0
end
end
end

View file

@ -1,92 +0,0 @@
# encoding: utf-8
# author: Dominik Richter
# author: Christoph Hartmann
class Vulcano::Plugins::Backend::FileCommon
class Stat
TYPES = {
socket: 00140000,
symlink: 00120000,
file: 00100000,
block_device: 00060000,
directory: 00040000,
character_device: 00020000,
pipe: 00010000,
}
def self.find_type(mode)
res = TYPES.find { |_, mask| mask & mode == mask }
res.nil? ? :unknown : res[0]
end
def self.stat(shell_escaped_path, backend)
return bsd_stat(shell_escaped_path, backend) if backend.os.bsd?
return linux_stat(shell_escaped_path, backend) if backend.os.unix?
# all other cases we don't handle
# TODO: print an error if we get here, as it shouldn't be invoked
# on non-unix
{}
end
def self.linux_stat(shell_escaped_path, backend)
res = backend.run_command("stat #{shell_escaped_path} 2>/dev/null --printf '%s\n%f\n%U\n%u\n%G\n%g\n%X\n%Y\n%C'")
# ignore the exit_code: it is != 0 if selinux labels are not supported
# on the system.
fields = res.stdout.split("\n")
return {} if fields.length != 9
tmask = fields[1].to_i(16)
selinux = fields[8]
selinux = nil if selinux == '?' or selinux == '(null)'
{
type: find_type(tmask),
mode: tmask & 00777,
owner: fields[2],
group: fields[4],
mtime: fields[7].to_i,
size: fields[0].to_i,
selinux_label: selinux,
}
end
def self.bsd_stat(shell_escaped_path, backend)
# From stat man page on FreeBSD:
# z The size of file in bytes (st_size).
# p File type and permissions (st_mode).
# u, g User ID and group ID of file's owner (st_uid, st_gid).
# a, m, c, B
# The time file was last accessed or modified, or when the
# inode was last changed, or the birth time of the inode
# (st_atime, st_mtime, st_ctime, st_birthtime).
#
# The special output specifier S may be used to indicate that the
# output, if applicable, should be in string format. May be used
# in combination with:
# ...
# gu Display group or user name.
res = backend.run_command(
"stat -f '%z\n%p\n%Su\n%u\n%Sg\n%g\n%a\n%m' "\
"#{shell_escaped_path}")
return {} if res.exit_status != 0
fields = res.stdout.split("\n")
return {} if fields.length != 8
tmask = fields[1].to_i(8)
{
type: find_type(tmask),
mode: tmask & 00777,
owner: fields[2],
group: fields[4],
mtime: fields[7].to_i,
size: fields[0].to_i,
selinux_label: fields[8],
}
end
end
end

View file

@ -2,7 +2,6 @@
# author: Dominik Richter
# author: Christoph Hartmann
require 'vulcano/backend'
require 'vulcano/rule'
require 'vulcano/dsl'

View file

@ -5,7 +5,7 @@
# author: Christoph Hartmann
require 'uri'
require 'vulcano/backend'
require 'train'
require 'vulcano/targets'
require 'vulcano/profile_context'
# spec requirements
@ -19,11 +19,11 @@ module Vulcano
def initialize(conf = {})
@rules = []
@profile_id = conf[:id]
@conf = Vulcano::Backend.target_config(normalize_map(conf))
@conf = conf.dup
@tests = RSpec::Core::World.new
configure_output
configure_backend
configure_transport
end
def normalize_map(hm)
@ -38,19 +38,35 @@ module Vulcano
RSpec.configuration.add_formatter(@conf['format'] || 'progress')
end
def configure_backend
backend_name = (@conf['backend'] ||= 'local')
bname, next_backend = backend_name.split('+')
@conf['backend'] = next_backend if bname == 'specinfra'
# @TODO all backends except for mock revert to specinfra for now
@backend = Vulcano::Backend.create(bname, @conf)
# Return on failure
if @backend.nil?
fail "Can't find command backend '#{backend_name}'."
def self.create_backend(config)
conf = Train.target_config(config)
name = conf[:backend] || :local
transport = Train.create(name, conf)
if transport.nil?
fail "Can't find transport backend '#{name}'."
end
@backend
connection = transport.connection
if connection.nil?
fail "Can't connect to transport backend '#{name}'."
end
cls = Class.new do
define_method :backend do
connection
end
Vulcano::Resource.registry.each do |id, r|
define_method id.to_sym do |*args|
r.new(self, id.to_s, *args)
end
end
end
cls.new
end
def configure_transport
@backend = self.class.create_backend(@conf)
end
def add_tests(tests)

View file

@ -13,8 +13,8 @@ SimpleCov.start do
add_group 'Backends', 'lib/vulcano/backend'
end
require 'vulcano/backend'
require 'vulcano/resource'
require 'train'
class MockLoader
# pass the os identifier to emulate a specific operating system
@ -47,11 +47,11 @@ class MockLoader
scriptpath = ::File.realpath(::File.dirname(__FILE__))
# create mock backend
@backend = Vulcano::Backend.create('mock', {})
mock = @backend.backend
@backend = Train.create('mock')
mock = @backend.connection
# create all mock files
local = Vulcano::Backend.registry['local'].new({})
local = Train.create('local').connection
mockfile = lambda { |x|
path = ::File.join(scriptpath, '/unit/mock/files', x)
local.file(path)

View file

@ -1,87 +0,0 @@
# encoding: utf-8
# author: Dominik Richter
# author: Christoph Hartmann
require 'helper'
describe 'Vulcano::Backend' do
it 'should have a populated registry' do
reg = Vulcano::Backend.registry
reg.must_be_kind_of Hash
reg.keys.must_include 'local'
reg.keys.must_include 'mock'
reg.keys.must_include 'specinfra'
end
describe 'target config helper' do
it 'configures resolves target' do
org = {
'target' => 'ssh://user:pass@host.com:123/path',
}
res = Vulcano::Backend.target_config(org)
res['backend'].must_equal 'ssh'
res['host'].must_equal 'host.com'
res['user'].must_equal 'user'
res['password'].must_equal 'pass'
res['port'].must_equal 123
res['target'].must_equal org['target']
res['path'].must_equal '/path'
org.keys.must_equal ['target']
end
it 'resolves a target while keeping existing fields' do
org = {
'target' => 'ssh://user:pass@host.com:123/path',
'backend' => rand,
'host' => rand,
'user' => rand,
'password' => rand,
'port' => rand,
'path' => rand
}
res = Vulcano::Backend.target_config(org)
res.must_equal org
end
it 'resolves a winrm target' do
org = {
'target' => 'winrm://Administrator@192.168.10.140',
'backend' => 'winrm',
'host' => '192.168.10.140',
'user' => 'Administrator',
'password' => nil,
'port' => nil,
'path' => nil
}
res = Vulcano::Backend.target_config(org)
res.must_equal org
end
it 'keeps the configuration when incorrect target is supplied' do
org = {
'target' => 'wrong',
}
res = Vulcano::Backend.target_config(org)
res['backend'].must_be_nil
res['host'].must_be_nil
res['user'].must_be_nil
res['password'].must_be_nil
res['port'].must_be_nil
res['path'].must_be_nil
res['target'].must_equal org['target']
end
end
describe 'helper method for creating backends' do
it 'creates v1 backends by default' do
Vulcano.backend.must_equal Vulcano::Plugins::Backend
end
it 'creates v1 backends' do
Vulcano.backend(1).must_equal Vulcano::Plugins::Backend
end
end
end

View file

@ -1,35 +0,0 @@
# encoding: utf-8
# author: Dominik Richter
# author: Christoph Hartmann
require 'helper'
describe 'Vulcano::Plugins::Backend::FileCommon' do
let(:cls) { Vulcano::Plugins::Backend::FileCommon }
let(:backend) { cls.new }
it 'default type is :unkown' do
backend.type.must_equal :unknown
end
describe 'with non-empty content' do
let(:backend) {
Class.new(cls) do
def content; 'Hello World'; end
end.new
}
it 'must return raw content' do
backend.content.must_equal 'Hello World'
end
it 'must calculate the md5sum of content' do
backend.md5sum.must_equal 'b10a8db164e0754105b7a99be72e3fe5'
end
it 'must calculate the sha256sum of content' do
backend.sha256sum.must_equal 'a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e'
end
end
end

View file

@ -1,241 +0,0 @@
# encoding: utf-8
# author: Dominik Richter
# author: Christoph Hartmann
require 'helper'
describe 'Vulcano::Plugins::Backend::OSCommon' do
let(:osc) {
cls = Vulcano::Plugins::Backend::OSCommon
mock = Vulcano::Backend.registry['mock']
cls.new(mock.new)
}
def set_platform(os, x)
pf = { family: x }
os.instance_variable_set(:@platform, pf)
end
describe 'with platform set to redhat' do
before { set_platform(osc, 'redhat') }
it { osc.redhat?.must_equal(true) }
it { osc.debian?.must_equal(false) }
it { osc.suse?.must_equal(false) }
it { osc.linux?.must_equal(true) }
it { osc.unix?.must_equal(true) }
end
describe 'with platform set to oracle' do
before { set_platform(osc, 'oracle') }
it { osc.redhat?.must_equal(true) }
it { osc.debian?.must_equal(false) }
it { osc.suse?.must_equal(false) }
it { osc.linux?.must_equal(true) }
it { osc.unix?.must_equal(true) }
end
describe 'with platform set to centos' do
before { set_platform(osc, 'centos') }
it { osc.redhat?.must_equal(true) }
it { osc.debian?.must_equal(false) }
it { osc.suse?.must_equal(false) }
it { osc.linux?.must_equal(true) }
it { osc.unix?.must_equal(true) }
end
describe 'with platform set to fedora' do
before { set_platform(osc, 'fedora') }
it { osc.redhat?.must_equal(true) }
it { osc.debian?.must_equal(false) }
it { osc.suse?.must_equal(false) }
it { osc.linux?.must_equal(true) }
it { osc.unix?.must_equal(true) }
end
describe 'with platform set to debian' do
before { set_platform(osc, 'debian') }
it { osc.redhat?.must_equal(false) }
it { osc.debian?.must_equal(true) }
it { osc.suse?.must_equal(false) }
it { osc.linux?.must_equal(true) }
it { osc.unix?.must_equal(true) }
end
describe 'with platform set to ubuntu' do
before { set_platform(osc, 'ubuntu') }
it { osc.redhat?.must_equal(false) }
it { osc.debian?.must_equal(true) }
it { osc.suse?.must_equal(false) }
it { osc.linux?.must_equal(true) }
it { osc.unix?.must_equal(true) }
end
describe 'with platform set to linuxmint' do
before { set_platform(osc, 'linuxmint') }
it { osc.redhat?.must_equal(false) }
it { osc.debian?.must_equal(true) }
it { osc.suse?.must_equal(false) }
it { osc.linux?.must_equal(true) }
it { osc.unix?.must_equal(true) }
end
describe 'with platform set to raspbian' do
before { set_platform(osc, 'raspbian') }
it { osc.redhat?.must_equal(false) }
it { osc.debian?.must_equal(true) }
it { osc.suse?.must_equal(false) }
it { osc.linux?.must_equal(true) }
it { osc.unix?.must_equal(true) }
end
describe 'with platform set to suse' do
before { set_platform(osc, 'suse') }
it { osc.redhat?.must_equal(false) }
it { osc.debian?.must_equal(false) }
it { osc.suse?.must_equal(true) }
it { osc.linux?.must_equal(true) }
it { osc.unix?.must_equal(true) }
end
describe 'with platform set to opensuse' do
before { set_platform(osc, 'opensuse') }
it { osc.redhat?.must_equal(false) }
it { osc.debian?.must_equal(false) }
it { osc.suse?.must_equal(true) }
it { osc.linux?.must_equal(true) }
it { osc.unix?.must_equal(true) }
end
describe 'with platform set to alpine' do
before { set_platform(osc, 'alpine') }
it { osc.redhat?.must_equal(false) }
it { osc.debian?.must_equal(false) }
it { osc.suse?.must_equal(false) }
it { osc.linux?.must_equal(true) }
it { osc.unix?.must_equal(true) }
end
describe 'with platform set to arch' do
before { set_platform(osc, 'arch') }
it { osc.redhat?.must_equal(false) }
it { osc.debian?.must_equal(false) }
it { osc.suse?.must_equal(false) }
it { osc.linux?.must_equal(true) }
it { osc.unix?.must_equal(true) }
end
describe 'with platform set to coreos' do
before { set_platform(osc, 'coreos') }
it { osc.redhat?.must_equal(false) }
it { osc.debian?.must_equal(false) }
it { osc.suse?.must_equal(false) }
it { osc.linux?.must_equal(true) }
it { osc.unix?.must_equal(true) }
end
describe 'with platform set to exherbo' do
before { set_platform(osc, 'exherbo') }
it { osc.redhat?.must_equal(false) }
it { osc.debian?.must_equal(false) }
it { osc.suse?.must_equal(false) }
it { osc.linux?.must_equal(true) }
it { osc.unix?.must_equal(true) }
end
describe 'with platform set to gentoo' do
before { set_platform(osc, 'gentoo') }
it { osc.redhat?.must_equal(false) }
it { osc.debian?.must_equal(false) }
it { osc.suse?.must_equal(false) }
it { osc.linux?.must_equal(true) }
it { osc.unix?.must_equal(true) }
end
describe 'with platform set to slackware' do
before { set_platform(osc, 'slackware') }
it { osc.redhat?.must_equal(false) }
it { osc.debian?.must_equal(false) }
it { osc.suse?.must_equal(false) }
it { osc.linux?.must_equal(true) }
it { osc.unix?.must_equal(true) }
end
describe 'with platform set to freebsd' do
before { set_platform(osc, 'freebsd') }
it { osc.bsd?.must_equal(true) }
it { osc.linux?.must_equal(false) }
it { osc.unix?.must_equal(true) }
end
describe 'with platform set to netbsd' do
before { set_platform(osc, 'netbsd') }
it { osc.bsd?.must_equal(true) }
it { osc.linux?.must_equal(false) }
it { osc.unix?.must_equal(true) }
end
describe 'with platform set to openbsd' do
before { set_platform(osc, 'openbsd') }
it { osc.bsd?.must_equal(true) }
it { osc.linux?.must_equal(false) }
it { osc.unix?.must_equal(true) }
end
describe 'with platform set to darwin' do
before { set_platform(osc, 'darwin') }
it { osc.bsd?.must_equal(true) }
it { osc.linux?.must_equal(false) }
it { osc.unix?.must_equal(true) }
end
describe 'with platform set to solaris' do
before { set_platform(osc, 'solaris') }
it { osc.solaris?.must_equal(true) }
it { osc.linux?.must_equal(false) }
it { osc.unix?.must_equal(true) }
end
describe 'with platform set to smartos' do
before { set_platform(osc, 'smartos') }
it { osc.solaris?.must_equal(true) }
it { osc.linux?.must_equal(false) }
it { osc.unix?.must_equal(true) }
end
describe 'with platform set to openindiana' do
before { set_platform(osc, 'openindiana') }
it { osc.solaris?.must_equal(true) }
it { osc.linux?.must_equal(false) }
it { osc.unix?.must_equal(true) }
end
describe 'with platform set to opensolaris' do
before { set_platform(osc, 'opensolaris') }
it { osc.solaris?.must_equal(true) }
it { osc.linux?.must_equal(false) }
it { osc.unix?.must_equal(true) }
end
describe 'with platform set to solaris2' do
before { set_platform(osc, 'solaris2') }
it { osc.solaris?.must_equal(true) }
it { osc.linux?.must_equal(false) }
it { osc.unix?.must_equal(true) }
end
describe 'with platform set to nexentacore' do
before { set_platform(osc, 'nexentacore') }
it { osc.solaris?.must_equal(true) }
it { osc.linux?.must_equal(false) }
it { osc.unix?.must_equal(true) }
end
describe 'with platform set to windows' do
before { set_platform(osc, 'windows') }
it { osc.solaris?.must_equal(false) }
it { osc.bsd?.must_equal(false) }
it { osc.linux?.must_equal(false) }
it { osc.unix?.must_equal(false) }
end
end

View file

@ -1,47 +0,0 @@
# encoding: utf-8
# author: Dominik Richter
# author: Christoph Hartmann
require 'helper'
describe 'Vulcano::Plugins::Backend' do
let(:cls) { Vulcano::Plugins::Backend }
let(:child) { Class.new(cls) }
it 'provides a name method for registering' do
child.must_respond_to :name
end
describe 'when registering a plugin' do
let(:registry) { Vulcano::Backend.registry }
before do
child.name 'test'
end
after do
registry.delete('test')
end
it 'must have the backend registered' do
registry.keys.must_include 'test'
registry['test'].must_equal child
end
it 'must raise an error if file is not implemented' do
t = registry['test'].new
proc { t.run_command }.must_raise NotImplementedError
end
it 'must raise an error if run_command is not implemented' do
t = registry['test'].new
proc { t.file }.must_raise NotImplementedError
end
it 'must raise an error if os is not implemented' do
t = registry['test'].new
proc { t.os }.must_raise NotImplementedError
end
end
end

View file

@ -25,9 +25,5 @@ Gem::Specification.new do |spec|
spec.add_dependency 'rubyzip', '~> 1.1'
spec.add_dependency 'rspec', '~> 3.3'
spec.add_dependency 'rspec-its', '~> 1.2'
spec.add_dependency 'winrm', '~> 1.3'
spec.add_dependency 'mixlib-shellout', '~> 2'
spec.add_dependency 'specinfra', '~> 2.40'
spec.add_dependency 'docker-api', '~> 1.22'
spec.add_dependency 'pry', '~> 0.10'
end