mirror of
https://github.com/inspec/inspec
synced 2024-11-10 07:04:15 +00:00
migrate backend to Train project
This commit is contained in:
parent
54b17fa8e1
commit
be614e9056
32 changed files with 35 additions and 2151 deletions
|
@ -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'
|
||||
|
|
|
@ -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'
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -5,6 +5,5 @@
|
|||
module Vulcano
|
||||
module Plugins
|
||||
autoload :Resource, 'vulcano/plugins/resource'
|
||||
autoload :Backend, 'vulcano/plugins/backend'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -2,7 +2,6 @@
|
|||
# author: Dominik Richter
|
||||
# author: Christoph Hartmann
|
||||
|
||||
require 'vulcano/backend'
|
||||
require 'vulcano/rule'
|
||||
require 'vulcano/dsl'
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue