pax_global_header00006660000000000000000000000064122574644050014523gustar00rootroot0000000000000052 comment=4267d22923c15a2c960d17a08d118a431b001085 specinfra-0.1.1/000077500000000000000000000000001225746440500134745ustar00rootroot00000000000000specinfra-0.1.1/.gitignore000066400000000000000000000002321225746440500154610ustar00rootroot00000000000000*.gem *.rbc .bundle .config .yardoc Gemfile.lock InstalledFiles _yardoc coverage doc/ lib/bundler/man pkg rdoc spec/reports test/tmp test/version_tmp tmp specinfra-0.1.1/.travis.yml000066400000000000000000000002531225746440500156050ustar00rootroot00000000000000language: ruby rvm: - 1.8.7 - 1.9.3 - 2.0.0 before_install: - gem update bundler script: - bundle exec rake spec matrix: allow_failures: - rvm: 2.0.0 specinfra-0.1.1/Gemfile000066400000000000000000000001361225746440500147670ustar00rootroot00000000000000source 'https://rubygems.org' # Specify your gem's dependencies in specinfra.gemspec gemspec specinfra-0.1.1/LICENSE.txt000066400000000000000000000020611225746440500153160ustar00rootroot00000000000000Copyright (c) 2013 Gosuke Miyashita MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. specinfra-0.1.1/README.md000066400000000000000000000007671225746440500147650ustar00rootroot00000000000000# Specinfra TODO: Write a gem description ## Installation Add this line to your application's Gemfile: gem 'specinfra' And then execute: $ bundle Or install it yourself as: $ gem install specinfra ## Usage TODO: Write usage instructions here ## Contributing 1. Fork it 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Add some feature'`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create new Pull Request specinfra-0.1.1/Rakefile000066400000000000000000000007041225746440500151420ustar00rootroot00000000000000require "bundler/gem_tasks" require 'rspec/core/rake_task' task :spec => 'spec:all' namespace :spec do task :all => [ :helper, :backend, :configuration ] RSpec::Core::RakeTask.new(:helper) do |t| t.pattern = "spec/helper/*_spec.rb" end RSpec::Core::RakeTask.new(:backend) do |t| t.pattern = "spec/backend/*/*_spec.rb" end RSpec::Core::RakeTask.new(:configuration) do |t| t.pattern = "spec/configuration_spec.rb" end end specinfra-0.1.1/lib/000077500000000000000000000000001225746440500142425ustar00rootroot00000000000000specinfra-0.1.1/lib/specinfra.rb000066400000000000000000000015231225746440500165420ustar00rootroot00000000000000require "specinfra/version" require "specinfra/helper" require "specinfra/backend" require "specinfra/command" require "specinfra/configuration" include SpecInfra module SpecInfra class << self def configuration SpecInfra::Configuration end end end if defined?(RSpec) RSpec.configure do |c| c.include(SpecInfra::Helper::Configuration) c.add_setting :os, :default => nil c.add_setting :host, :default => nil c.add_setting :ssh, :default => nil c.add_setting :sudo_password, :default => nil c.add_setting :winrm, :default => nil SpecInfra.configuration.defaults.each { |k, v| c.add_setting k, :default => v } c.before :each do if respond_to?(:backend) && backend.respond_to?(:set_example) backend.set_example(example) end end end end specinfra-0.1.1/lib/specinfra/000077500000000000000000000000001225746440500162145ustar00rootroot00000000000000specinfra-0.1.1/lib/specinfra/backend.rb000066400000000000000000000005271225746440500201340ustar00rootroot00000000000000require 'specinfra/backend/base' require 'specinfra/backend/exec' require 'specinfra/backend/ssh' require 'specinfra/backend/powershell/script_helper' require 'specinfra/backend/powershell/command' require 'specinfra/backend/cmd' require 'specinfra/backend/winrm' require 'specinfra/backend/shellscript' require 'specinfra/backend/dockerfile' specinfra-0.1.1/lib/specinfra/backend/000077500000000000000000000000001225746440500176035ustar00rootroot00000000000000specinfra-0.1.1/lib/specinfra/backend/base.rb000066400000000000000000000010521225746440500210400ustar00rootroot00000000000000require 'singleton' module SpecInfra module Backend class Base include Singleton def set_commands(c) @commands = c end def set_example(e) @example = e end def commands @commands end def check_zero(cmd, *args) ret = run_command(commands.send(cmd, *args)) ret[:exit_status] == 0 end # Default action is to call check_zero with args def method_missing(meth, *args, &block) check_zero(meth, *args) end end end end specinfra-0.1.1/lib/specinfra/backend/cmd.rb000066400000000000000000000023751225746440500207020ustar00rootroot00000000000000require 'open3' module SpecInfra module Backend class Cmd < Base include PowerShell::ScriptHelper def run_command(cmd, opts={}) script = create_script(cmd) result = execute_script %Q{powershell -encodedCommand #{encode_script(script)}} if @example @example.metadata[:command] = script @example.metadata[:stdout] = result[:stdout] + result[:stderr] end { :stdout => result[:stdout], :stderr => result[:stderr], :exit_status => result[:status], :exit_signal => nil } end def execute_script script if Open3.respond_to? :capture3 stdout, stderr, status = Open3.capture3(script) # powershell still exits with 0 even if there are syntax errors, although it spits the error out into stderr # so we have to resort to return an error exit code if there is anything in the standard error status = 1 if status == 0 and !stderr.empty? { :stdout => stdout, :stderr => stderr, :status => status } else stdout = `#{script} 2>&1` { :stdout => stdout, :stderr => nil, :status => $? } end end def check_os # Dirty hack for specs 'Windows' end end end end specinfra-0.1.1/lib/specinfra/backend/dockerfile.rb000066400000000000000000000007601225746440500222420ustar00rootroot00000000000000module SpecInfra module Backend class Dockerfile < SpecInfra::Backend::Base def initialize @lines = [] ObjectSpace.define_finalizer(self) { File.write("Dockerfile", @lines.join("\n")) } end def run_command(cmd, opts={}) @lines << "RUN #{cmd}" { :stdout => nil, :stderr => nil, :exit_status => 0, :exit_signal => nil } end def from(base) @lines << "FROM #{base}" end end end end specinfra-0.1.1/lib/specinfra/backend/exec.rb000066400000000000000000000170571225746440500210660ustar00rootroot00000000000000require 'singleton' module SpecInfra module Backend class Exec < Base def run_command(cmd, opts={}) cmd = build_command(cmd) cmd = add_pre_command(cmd) stdout = run_with_no_ruby_environment do `#{build_command(cmd)} 2>&1` end # In ruby 1.9, it is possible to use Open3.capture3, but not in 1.8 #stdout, stderr, status = Open3.capture3(cmd) if @example @example.metadata[:command] = cmd @example.metadata[:stdout] = stdout end { :stdout => stdout, :stderr => nil, :exit_status => $?.exitstatus, :exit_signal => nil } end def run_with_no_ruby_environment keys = %w[BUNDLER_EDITOR BUNDLE_BIN_PATH BUNDLE_GEMFILE RUBYOPT GEM_HOME GEM_PATH GEM_CACHE] keys.each { |key| ENV["_SPECINFRA_#{key}"] = ENV[key] ; ENV.delete(key) } yield ensure keys.each { |key| ENV[key] = ENV.delete("_SPECINFRA_#{key}") } end def build_command(cmd) path = SpecInfra.configuration.path if path cmd = "env PATH=#{path}:$PATH #{cmd}" cmd.gsub!(/(\&\&\s*!?\(?\s*)/, "\\1env PATH=#{path}:$PATH ") cmd.gsub!(/(\|\|\s*!?\(?\s*)/, "\\1env PATH=#{path}:$PATH ") end cmd end def add_pre_command(cmd) path = SpecInfra.configuration.path if SpecInfra.configuration.pre_command cmd = "#{SpecInfra.configuration.pre_command} && #{cmd}" cmd = "env PATH=#{path}:$PATH #{cmd}" if path end cmd end def check_running(process) ret = run_command(commands.check_running(process)) # In Ubuntu, some services are under upstart and "service foo status" returns # exit status 0 even though they are stopped. # So return false if stdout contains "stopped/waiting". return false if ret[:stdout] =~ /stopped\/waiting/ # If the service is not registered, check by ps command if ret[:exit_status] == 1 ret = run_command(commands.check_process(process)) end ret[:exit_status] == 0 end def check_monitored_by_monit(process) ret = run_command(commands.check_monitored_by_monit(process)) return false unless ret[:stdout] != nil && ret[:exit_status] == 0 retlines = ret[:stdout].split(/[\r\n]+/).map(&:strip) proc_index = retlines.index("Process '#{process}'") return false unless proc_index retlines[proc_index+2].match(/\Amonitoring status\s+monitored\Z/i) != nil end def check_readable(file, by_whom) mode = sprintf('%04s',run_command(commands.get_mode(file))[:stdout].strip) mode = mode.split('') mode_octal = mode[0].to_i * 512 + mode[1].to_i * 64 + mode[2].to_i * 8 + mode[3].to_i * 1 case by_whom when nil mode_octal & 0444 != 0 when 'owner' mode_octal & 0400 != 0 when 'group' mode_octal & 0040 != 0 when 'others' mode_octal & 0004 != 0 end end def check_writable(file, by_whom) mode = sprintf('%04s',run_command(commands.get_mode(file))[:stdout].strip) mode = mode.split('') mode_octal = mode[0].to_i * 512 + mode[1].to_i * 64 + mode[2].to_i * 8 + mode[3].to_i * 1 case by_whom when nil mode_octal & 0222 != 0 when 'owner' mode_octal & 0200 != 0 when 'group' mode_octal & 0020 != 0 when 'others' mode_octal & 0002 != 0 end end def check_executable(file, by_whom) mode = sprintf('%04s',run_command(commands.get_mode(file))[:stdout].strip) mode = mode.split('') mode_octal = mode[0].to_i * 512 + mode[1].to_i * 64 + mode[2].to_i * 8 + mode[3].to_i * 1 case by_whom when nil mode_octal & 0111 != 0 when 'owner' mode_octal & 0100 != 0 when 'group' mode_octal & 0010 != 0 when 'others' mode_octal & 0001 != 0 end end def check_mounted(path, expected_attr, only_with) ret = run_command(commands.check_mounted(path)) if expected_attr.nil? || ret[:exit_status] != 0 return ret[:exit_status] == 0 end mount = ret[:stdout].scan(/\S+/) actual_attr = { :device => mount[0], :type => mount[4] } mount[5].gsub(/\(|\)/, '').split(',').each do |option| name, val = option.split('=') if val.nil? actual_attr[name.to_sym] = true else val = val.to_i if val.match(/^\d+$/) actual_attr[name.to_sym] = val end end if ! expected_attr[:options].nil? expected_attr.merge!(expected_attr[:options]) expected_attr.delete(:options) end if only_with actual_attr == expected_attr else expected_attr.each do |key, val| return false if actual_attr[key] != val end true end end def check_routing_table(expected_attr) return false if ! expected_attr[:destination] ret = run_command(commands.check_routing_table(expected_attr[:destination])) return false if ret[:exit_status] != 0 ret[:stdout].gsub!(/\r\n/, "\n") ret[:stdout] =~ /^(\S+)(?: via (\S+))? dev (\S+).+\n(?:default via (\S+))?/ actual_attr = { :destination => $1, :gateway => $2 ? $2 : $4, :interface => expected_attr[:interface] ? $3 : nil } expected_attr.each do |key, val| return false if actual_attr[key] != val end true end def check_os return SpecInfra.configuration.os if SpecInfra.configuration.os if run_command('ls /etc/redhat-release')[:exit_status] == 0 line = run_command('cat /etc/redhat-release')[:stdout] if line =~ /release (\d[\d.]*)/ release = $1 end { :family => 'RedHat', :release => release } elsif run_command('ls /etc/system-release')[:exit_status] == 0 { :family => 'RedHat', :release => nil } # Amazon Linux elsif run_command('ls /etc/debian_version')[:exit_status] == 0 distro = run_command("lsb_release -i | grep 'Distributor ID:' | awk '{print $3}'")[:stdout] { :family => distro.strip, :release => nil } elsif run_command('ls /etc/gentoo-release')[:exit_status] == 0 { :family => 'Gentoo', :release => nil } elsif run_command('ls /usr/lib/setup/Plamo-*')[:exit_status] == 0 { :family => 'Plamo', :release => nil } elsif run_command('uname -s')[:stdout] =~ /AIX/i { :family => 'AIX', :release => nil } elsif (os = run_command('uname -sr')[:stdout]) && os =~ /SunOS/i if os =~ /5.10/ { :family => 'Solaris10', :release => nil } elsif run_command('grep -q "Oracle Solaris 11" /etc/release')[:exit_status] == 0 { :family => 'Solaris11', :release => nil } elsif run_command('grep -q SmartOS /etc/release')[:exit_status] == 0 { :family => 'SmartOS', :release => nil } else { :family => 'Solaris', :release => nil } end elsif run_command('uname -s')[:stdout] =~ /Darwin/i { :family => 'Darwin', :release => nil } elsif run_command('uname -s')[:stdout] =~ /FreeBSD/i { :family => 'FreeBSD', :release => nil } else { :family => 'Base', :release => nil } end end end end end specinfra-0.1.1/lib/specinfra/backend/powershell/000077500000000000000000000000001225746440500217675ustar00rootroot00000000000000specinfra-0.1.1/lib/specinfra/backend/powershell/command.rb000066400000000000000000000015351225746440500237360ustar00rootroot00000000000000module SpecInfra module Backend module PowerShell class Command attr_reader :import_functions, :script def initialize &block @import_functions = [] @script = "" instance_eval &block if block_given? end def using *functions functions.each { |f| import_functions << f } end def exec code @script = code end def convert_regexp(target) case target when Regexp target.source else target.to_s.gsub '/', '' end end def get_identity id raise "You must provide a specific Windows user/group" if id =~ /(owner|group|others)/ identity = id || 'Everyone' end def to_s @script end end end end end specinfra-0.1.1/lib/specinfra/backend/powershell/script_helper.rb000066400000000000000000000042021225746440500251550ustar00rootroot00000000000000require 'base64' module SpecInfra module Backend module PowerShell module ScriptHelper def build_command(cmd) path = SpecInfra.configuration.path if path cmd.strip! cmd = <<-EOF $env:path = "#{path};$env:path" #{cmd} EOF end cmd end def add_pre_command(cmd) path = SpecInfra.configuration.path if SpecInfra.configuration.pre_command cmd.strip! cmd = <<-EOF if (#{SpecInfra.configuration.pre_command}) { #{cmd} } EOF cmd = "$env:path = \"#{path};$env:path\"\n#{cmd}" if path end cmd end def encode_script script script_text = script.chars.to_a.join("\x00").chomp script_text << "\x00" unless script_text[-1].eql? "\x00" if script_text.respond_to?(:encode) script_text = script_text.encode('ASCII-8BIT') end if Base64.respond_to?(:strict_encode64) Base64.strict_encode64(script_text) else [ script_text ].pack("m").strip end end def create_script command if command.is_a? Command ps_functions = command.import_functions.map { |f| File.read(File.join(File.dirname(__FILE__), 'support', f)) } script = build_command(command.script) script = add_pre_command(script) <<-EOF $exitCode = 1 try { #{ps_functions.join("\n")} $success = (#{script}) if ($success -is [Boolean] -and $success) { $exitCode = 0 } } catch { Write-Output $_.Exception.Message } Write-Output "Exiting with code: $exitCode" exit $exitCode EOF else script = build_command(command.to_s) add_pre_command(script) end end def check_running(process) ret = run_command(commands.check_running(process)) # If the service is not registered, check the process if ret[:exit_status] == 1 ret = run_command(commands.check_process(process)) end ret[:exit_status] == 0 end end end end end specinfra-0.1.1/lib/specinfra/backend/powershell/support/000077500000000000000000000000001225746440500235035ustar00rootroot00000000000000specinfra-0.1.1/lib/specinfra/backend/powershell/support/check_file_access_rules.ps1000066400000000000000000000005561225746440500307450ustar00rootroot00000000000000function CheckFileAccessRules { param($path, $identity, $rules) $accessRules = @((Get-Acl $path).access | Where-Object {$_.AccessControlType -eq 'Allow' -and $_.IdentityReference -eq $identity }) $match = @($accessRules | Where-Object {($_.FileSystemRights.ToString().Split(',') | % {$_.trim()} | ? {$rules -contains $_}) -ne $null}) $match.count -gt 0 } specinfra-0.1.1/lib/specinfra/backend/powershell/support/crop_text.ps1000066400000000000000000000004711225746440500261410ustar00rootroot00000000000000function CropText { param($text, $fromPattern, $toPattern) $from, $to = ([regex]::matches($text, $fromPattern)), ([regex]::matches($text, $toPattern)) if ($from.count -gt 0 -and $to.count -gt 0) { $text.substring($from[0].index, $to[0].index + $to[0].length - $from[0].index) } else { "" } } specinfra-0.1.1/lib/specinfra/backend/powershell/support/find_group.ps1000066400000000000000000000004041225746440500262620ustar00rootroot00000000000000function FindGroup { param($groupName, $domain) if ($domain -eq $null) {$selectionCriteria = " and LocalAccount = true"} else {$selectionCriteria = " and Domain = '$domain'"} Get-WmiObject Win32_Group -filter "Name = '$groupName' $selectionCriteria" }specinfra-0.1.1/lib/specinfra/backend/powershell/support/find_installed_application.ps1000066400000000000000000000004661225746440500315000ustar00rootroot00000000000000function FindInstalledApplication { param($appName, $appVersion) $selectionCriteria = "(Name like '$appName' or PackageName like '$appName') and InstallState = 5" if ($appVersion -ne $null) { $selectionCriteria += " and version = '$appVersion'"} Get-WmiObject Win32_Product -filter $selectionCriteria }specinfra-0.1.1/lib/specinfra/backend/powershell/support/find_service.ps1000066400000000000000000000002051225746440500265650ustar00rootroot00000000000000function FindService { param($name) Get-WmiObject Win32_Service | Where-Object {$_.Name -eq $name -or $_.DisplayName -eq $name} }specinfra-0.1.1/lib/specinfra/backend/powershell/support/find_user.ps1000066400000000000000000000004101225746440500261010ustar00rootroot00000000000000function FindUser { param($userName, $domain) if ($domain -eq $null) {$selectionCriteria = " and LocalAccount = true"} else {$selectionCriteria = " and Domain = '$domain'"} Get-WmiObject Win32_UserAccount -filter "Name = '$userName' $selectionCriteria" } specinfra-0.1.1/lib/specinfra/backend/powershell/support/find_usergroup.ps1000066400000000000000000000007351225746440500271700ustar00rootroot00000000000000function FindUserGroup { param($userName, $groupName, $userDomain, $groupDomain) $user = FindUser -userName $userName -domain $userDomain $group = FindGroup -groupName $groupName -domain $groupDomain if ($user -and $group) { Get-WmiObject Win32_GroupUser -filter ("GroupComponent = 'Win32_Group.Domain=`"" + $group.domain + "`",Name=`"" + $group.name + "`"' and PartComponent = 'Win32_UserAccount.Domain=`"" + $user.domain + "`",Name=`"" + $user.name + "`"'") } }specinfra-0.1.1/lib/specinfra/backend/powershell/support/is_port_listening.ps1000066400000000000000000000007361225746440500276710ustar00rootroot00000000000000function IsPortListening { param($portNumber, $protocol) $netstatOutput = netstat -an | Out-String $networkIPs = (Get-WmiObject Win32_NetworkAdapterConfiguration | ? {$_.IPEnabled}) | %{ $_.IPAddress[0] } foreach ($ipaddress in $networkIPs) { $matchExpression = ("$ipaddress" + ":" + $portNumber) if ($protocol) { $matchExpression = ($protocol.toUpper() + "\s+$matchExpression") } if ($netstatOutput -match $matchExpression) { return $true } } $false }specinfra-0.1.1/lib/specinfra/backend/shellscript.rb000066400000000000000000000011501225746440500224610ustar00rootroot00000000000000require 'singleton' module SpecInfra module Backend class ShellScript < Base def initialize @lines = [ "#!/bin/sh", "" ] ObjectSpace.define_finalizer(self, Writer.new("spec.sh", @lines)) end def run_command(cmd, opts={}) @lines << cmd { :stdout => nil, :stderr => nil, :exit_status => 0, :exit_signal => nil } end class Writer def initialize(file, lines) @file = file @lines = lines end def call(*args) File.write(@file, @lines.join("\n")) end end end end end specinfra-0.1.1/lib/specinfra/backend/ssh.rb000066400000000000000000000054471225746440500207370ustar00rootroot00000000000000require 'specinfra/backend/exec' module SpecInfra module Backend class Ssh < Exec def run_command(cmd, opt={}) cmd = build_command(cmd) cmd = add_pre_command(cmd) ret = ssh_exec!(cmd) ret[:stdout].gsub!(/\r\n/, "\n") if @example @example.metadata[:command] = cmd @example.metadata[:stdout] = ret[:stdout] end ret end def build_command(cmd) cmd = super(cmd) user = SpecInfra.configuration.ssh.options[:user] disable_sudo = SpecInfra.configuration.disable_sudo if user != 'root' && !disable_sudo cmd = "#{sudo} #{cmd}" cmd.gsub!(/(\&\&\s*!?\(?\s*)/, "\\1#{sudo} ") cmd.gsub!(/(\|\|\s*!?\(?\s*)/, "\\1#{sudo} ") end cmd end def add_pre_command(cmd) cmd = super(cmd) user = SpecInfra.configuration.ssh.options[:user] pre_command = SpecInfra.configuration.pre_command disable_sudo = SpecInfra.configuration.disable_sudo if pre_command && user != 'root' && !disable_sudo cmd = "#{sudo} #{cmd}" end cmd end private def ssh_exec!(command) stdout_data = '' stderr_data = '' exit_status = nil exit_signal = nil pass_prompt = SpecInfra.configuration.pass_prompt || /^\[sudo\] password for/ ssh = SpecInfra.configuration.ssh ssh.open_channel do |channel| channel.request_pty do |ch, success| abort "Could not obtain pty " if !success end channel.exec("#{command}") do |ch, success| abort "FAILED: couldn't execute command (ssh.channel.exec)" if !success channel.on_data do |ch, data| if data.match pass_prompt abort "Please set sudo password by using SUDO_PASSWORD or ASK_SUDO_PASSWORD environment variable" if SpecInfra.configuration.sudo_password.nil? channel.send_data "#{SpecInfra.configuration.sudo_password}\n" else stdout_data += data end end channel.on_extended_data do |ch, type, data| stderr_data += data end channel.on_request("exit-status") do |ch, data| exit_status = data.read_long end channel.on_request("exit-signal") do |ch, data| exit_signal = data.read_long end end end ssh.loop { :stdout => stdout_data, :stderr => stderr_data, :exit_status => exit_status, :exit_signal => exit_signal } end def sudo sudo_path = SpecInfra.configuration.sudo_path if sudo_path "#{sudo_path}/sudo" else 'sudo' end end end end end specinfra-0.1.1/lib/specinfra/backend/winrm.rb000066400000000000000000000013661225746440500212720ustar00rootroot00000000000000module SpecInfra module Backend class WinRM < Base include PowerShell::ScriptHelper def run_command(cmd, opts={}) script = create_script(cmd) winrm = SpecInfra.configuration.winrm result = winrm.powershell(script) stdout, stderr = [:stdout, :stderr].map do |s| result[:data].select {|item| item.key? s}.map {|item| item[s]}.join end result[:exitcode] = 1 if result[:exitcode] == 0 and !stderr.empty? if @example @example.metadata[:command] = script @example.metadata[:stdout] = stdout + stderr end { :stdout => stdout, :stderr => stderr, :exit_status => result[:exitcode], :exit_signal => nil } end end end end specinfra-0.1.1/lib/specinfra/command.rb000066400000000000000000000010571225746440500201620ustar00rootroot00000000000000require "specinfra/command/base" # Linux require "specinfra/command/linux" require "specinfra/command/debian" require "specinfra/command/ubuntu" require "specinfra/command/gentoo" require "specinfra/command/plamo" require "specinfra/command/redhat" # Solaris require "specinfra/command/solaris" require "specinfra/command/solaris10" require "specinfra/command/solaris11" require "specinfra/command/smartos" # Others require "specinfra/command/aix" require "specinfra/command/darwin" require "specinfra/command/freebsd" require "specinfra/command/windows" specinfra-0.1.1/lib/specinfra/command/000077500000000000000000000000001225746440500176325ustar00rootroot00000000000000specinfra-0.1.1/lib/specinfra/command/aix.rb000066400000000000000000000036661225746440500207530ustar00rootroot00000000000000module SpecInfra module Command class AIX < Base class NotImplementedError < Exception; end def check_access_by_user(file, user, access) "su -s sh -c \"test -#{access} #{file}\" #{user}" end def check_enabled(service,level=nil) "lssrc -s #{escape(service)} | grep active" end def check_running(service) "ps -ef | grep -v grep | grep #{escape(service)}" end def check_installed(package,version) if version "lslpp -L #{escape(package)} | awk '{print $2}' | grep -w -- #{version}" else "lslpp -L #{escape(package)}" end end def check_listening(port) regexp = "*.#{port} " "netstat -an -f inet | awk '{print $4}' | grep -- #{regexp}" #"netstat -an -f inet | awk '{print $4}' | grep -- #{escape(regexp)}" end def check_belonging_group(user, group) "lsuser -a groups #{escape(user)} | awk -F'=' '{print $2}'| sed -e 's/,/ /g' |grep -w -- #{escape(group)}" end def check_gid(group, gid) regexp = "^#{group}" "cat etc/group | grep -w -- #{escape(regexp)} | cut -f 3 -d ':' | grep -w -- #{escape(gid)}" end def check_login_shell(user, path_to_shell) "lsuser -a shell #{escape(user)} |awk -F'=' '{print $2}' | grep -w -- #{escape(path_to_shell)}" end def check_home_directory(user, path_to_home) "lsuser -a home #{escape(user)} | awk -F'=' '{print $2}' | grep -w -- #{escape(path_to_home)}" end def check_mode(file, mode) raise NotImplementedError.new end def check_owner(file, owner) regexp = "^#{owner}$" "ls -al #{escape(file)} | awk '{print $3}' | grep -- #{escape(regexp)}" end def check_grouped(file, group) regexp = "^#{group}$" "ls -al #{escape(file)} | awk '{print $4}' | grep -- #{escape(regexp)}" end end end end specinfra-0.1.1/lib/specinfra/command/base.rb000066400000000000000000000211071225746440500210720ustar00rootroot00000000000000require 'shellwords' module SpecInfra module Command class Base class NotImplementedError < Exception; end def escape(target) str = case target when Regexp target.source else target.to_s end Shellwords.shellescape(str) end def check_enabled(service, level=3) raise NotImplementedError.new end def check_yumrepo(repository) raise NotImplementedError.new end def check_yumrepo_enabled(repository) raise NotImplementedError.new end def check_mounted(path) regexp = "on #{path}" "mount | grep -w -- #{escape(regexp)}" end def check_routing_table(destination) "ip route | grep -E '^#{destination} |^default '" end def check_reachable(host, port, proto, timeout) if port.nil? "ping -n #{escape(host)} -w #{escape(timeout)} -c 2" else "nc -vvvvz#{escape(proto[0].chr)} #{escape(host)} #{escape(port)} -w #{escape(timeout)}" end end def check_resolvable(name, type) if type == "dns" "nslookup -timeout=1 #{escape(name)}" elsif type == "hosts" "grep -w -- #{escape(name)} /etc/hosts" else "getent hosts #{escape(name)}" end end def check_file(file) "test -f #{escape(file)}" end def check_socket(file) "test -S #{escape(file)}" end def check_directory(directory) "test -d #{escape(directory)}" end def check_user(user) "id #{escape(user)}" end def check_group(group) "getent group | grep -wq -- #{escape(group)}" end def check_installed(package, version=nil) raise NotImplementedError.new end def check_listening(port) regexp = ":#{port} " "netstat -tunl | grep -- #{escape(regexp)}" end def check_listening_with_protocol(port, protocol) regexp = "^#{protocol} .*:#{port} " "netstat -tunl | grep -- #{escape(regexp)}" end def check_running(service) "service #{escape(service)} status" end def check_running_under_supervisor(service) "supervisorctl status #{escape(service)} | grep RUNNING" end def check_running_under_upstart(service) "initctl status #{escape(service)} | grep running" end def check_monitored_by_monit(service) "monit status" end def check_monitored_by_god(service) "god status #{escape(service)}" end def check_process(process) "ps aux | grep -w -- #{escape(process)} | grep -qv grep" end def get_process(process, opts) "ps -C #{escape(process)} -o #{opts[:format]} | head -1" end def check_file_contain(file, expected_pattern) "#{check_file_contain_with_regexp(file, expected_pattern)} || #{check_file_contain_with_fixed_strings(file, expected_pattern)}" end def check_file_contain_with_regexp(file, expected_pattern) "grep -q -- #{escape(expected_pattern)} #{escape(file)}" end def check_file_contain_with_fixed_strings(file, expected_pattern) "grep -qF -- #{escape(expected_pattern)} #{escape(file)}" end def check_file_md5checksum(file, expected) regexp = "^#{expected}" "md5sum #{escape(file)} | grep -iw -- #{escape(regexp)}" end def check_file_sha256checksum(file, expected) regexp = "^#{expected}" "sha256sum #{escape(file)} | grep -iw -- #{escape(regexp)}" end def check_file_contain_within(file, expected_pattern, from=nil, to=nil) from ||= '1' to ||= '$' sed = "sed -n #{escape(from)},#{escape(to)}p #{escape(file)}" checker_with_regexp = check_file_contain_with_regexp("-", expected_pattern) checker_with_fixed = check_file_contain_with_fixed_strings("-", expected_pattern) "#{sed} | #{checker_with_regexp} || #{sed} | #{checker_with_fixed}" end def check_mode(file, mode) regexp = "^#{mode}$" "stat -c %a #{escape(file)} | grep -- #{escape(regexp)}" end def check_owner(file, owner) regexp = "^#{owner}$" "stat -c %U #{escape(file)} | grep -- #{escape(regexp)}" end def check_grouped(file, group) regexp = "^#{group}$" "stat -c %G #{escape(file)} | grep -- #{escape(regexp)}" end def check_cron_entry(user, entry) entry_escaped = entry.gsub(/\*/, '\\*') if user.nil? "crontab -l | grep -- #{escape(entry_escaped)}" else "crontab -u #{escape(user)} -l | grep -- #{escape(entry_escaped)}" end end def check_link(link, target) "stat -c %N #{escape(link)} | grep -- #{escape(target)}" end def check_installed_by_gem(name, version=nil) regexp = "^#{name}" cmd = "gem list --local | grep -w -- #{escape(regexp)}" cmd = "#{cmd} | grep -w -- #{escape(version)}" if version cmd end def check_installed_by_npm(name, version=nil) cmd = "npm ls #{escape(name)} -g" cmd = "#{cmd} | grep -w -- #{escape(version)}" if version cmd end def check_installed_by_pecl(name, version=nil) regexp = "^#{name}" cmd = "pecl list | grep -w -- #{escape(regexp)}" cmd = "#{cmd} | grep -w -- #{escape(version)}" if version cmd end def check_installed_by_pear(name, version=nil) regexp = "^#{name}" cmd = "pear list | grep -w -- #{escape(regexp)}" cmd = "#{cmd} | grep -w -- #{escape(version)}" if version cmd end def check_installed_by_pip(name, version=nil) regexp = "^#{name}" cmd = "pip list | grep -w -- #{escape(regexp)}" cmd = "#{cmd} | grep -w -- #{escape(version)}" if version cmd end def check_installed_by_cpan(name, version=nil) regexp = "^#{name}" cmd = "cpan -l | grep -w -- #{escape(regexp)}" cmd = "#{cmd} | grep -w -- #{escape(version)}" if version cmd end def check_belonging_group(user, group) "id #{escape(user)} | awk '{print $3}' | grep -- #{escape(group)}" end def check_gid(group, gid) regexp = "^#{group}" "getent group | grep -w -- #{escape(regexp)} | cut -f 3 -d ':' | grep -w -- #{escape(gid)}" end def check_uid(user, uid) regexp = "^uid=#{uid}(" "id #{escape(user)} | grep -- #{escape(regexp)}" end def check_login_shell(user, path_to_shell) "getent passwd #{escape(user)} | cut -f 7 -d ':' | grep -w -- #{escape(path_to_shell)}" end def check_home_directory(user, path_to_home) "getent passwd #{escape(user)} | cut -f 6 -d ':' | grep -w -- #{escape(path_to_home)}" end def check_authorized_key(user, key) key.sub!(/\s+\S*$/, '') if key.match(/^\S+\s+\S+\s+\S*$/) "grep -w -- #{escape(key)} ~#{escape(user)}/.ssh/authorized_keys" end def check_iptables_rule(rule, table=nil, chain=nil) raise NotImplementedError.new end def check_zfs(zfs, property=nil, value=nil) raise NotImplementedError.new end def get_mode(file) "stat -c %a #{escape(file)}" end def check_ipfilter_rule(rule) raise NotImplementedError.new end def check_ipnat_rule(rule) raise NotImplementedError.new end def check_svcprop(svc, property, value) raise NotImplementedError.new end def check_svcprops(svc, property) raise NotImplementedError.new end def check_selinux(mode) raise NotImplementedError.new end def check_access_by_user(file, user, access) raise NotImplementedError.new end def check_kernel_module_loaded(name) raise NotImplementedError.new end def check_ipv4_address(interface, ip_address) raise NotImplementedError.new end def check_mail_alias(recipient, target) target = "[[:space:]]#{target}" "getent aliases #{escape(recipient)} | grep -- #{escape(target)}$" end def get_file_content(file) "cat #{file} 2> /dev/null || echo -n" end def check_container(container) raise NotImplementedError.new end def check_cotainer_running(container) raise NotImplementedError.new end def get_package_version(package, opts=nil) raise NotImplementedError.new end end end end specinfra-0.1.1/lib/specinfra/command/darwin.rb000066400000000000000000000022651225746440500214500ustar00rootroot00000000000000module SpecInfra module Command class Darwin < Base def check_file_md5checksum(file, expected) "openssl md5 #{escape(file)} | cut -d'=' -f2 | cut -c 2- | grep -E ^#{escape(expected)}$" end def check_file_sha256checksum(file, expected) "openssl sha256 #{escape(file)} | cut -d'=' -f2 | cut -c 2- | grep -E ^#{escape(expected)}$" end def check_link(link, target) "stat -f %Y #{escape(link)} | grep -- #{escape(target)}" end def check_mode(file, mode) regexp = "^#{mode}$" "stat -f%Lp #{escape(file)} | grep -- #{escape(regexp)}" end def check_owner(file, owner) regexp = "^#{owner}$" "stat -f %Su #{escape(file)} | grep -- #{escape(regexp)}" end def check_grouped(file, group) regexp = "^#{group}$" "stat -f %Sg #{escape(file)} | grep -- #{escape(regexp)}" end def get_mode(file) "stat -f%Lp #{escape(file)}" end def check_access_by_user(file, user, access) "sudo -u #{user} -s /bin/test -#{access} #{file}" end def install(package) cmd = "brew install '#{package}'" end end end end specinfra-0.1.1/lib/specinfra/command/debian.rb000066400000000000000000000017331225746440500214050ustar00rootroot00000000000000module SpecInfra module Command class Debian < Linux def check_enabled(service, level=3) # Until everything uses Upstart, this needs an OR. "ls /etc/rc#{level}.d/ | grep -- '^S..#{escape(service)}' || grep 'start on' /etc/init/#{escape(service)}.conf" end def check_installed(package, version=nil) escaped_package = escape(package) if version cmd = "dpkg-query -f '${Status} ${Version}' -W #{escaped_package} | grep -E '^install ok installed #{escape(version)}$'" else cmd = "dpkg-query -f '${Status}' -W #{escaped_package} | grep '^install ok installed$'" end cmd end alias :check_installed_by_apt :check_installed def install(package) "apt-get -y install #{package}" end def get_package_version(package, opts=nil) "dpkg-query -f '${Status} ${Version}' -W #{package} | sed -n 's/^install ok installed //p'" end end end end specinfra-0.1.1/lib/specinfra/command/freebsd.rb000066400000000000000000000011621225746440500215710ustar00rootroot00000000000000module SpecInfra module Command class FreeBSD < Base def check_enabled(service, level=3) "service -e | grep -- #{escape(service)}" end def check_installed(package, version=nil) "pkg_info -Ix #{escape(package)}" end def check_listening(port) regexp = ":#{port} " "sockstat -46l -p #{port} | grep -- #{escape(regexp)}" end def check_mode(file, mode) regexp = "^#{mode}$" "stat -f%Lp #{escape(file)} | grep -- #{escape(regexp)}" end def get_mode(file) "stat -f%Lp #{escape(file)}" end end end end specinfra-0.1.1/lib/specinfra/command/gentoo.rb000066400000000000000000000006721225746440500214570ustar00rootroot00000000000000module SpecInfra module Command class Gentoo < Linux def check_enabled(service, level=3) regexp = "^\\s*#{service}\\s*|\\s*\\(boot\\|default\\)" "rc-update show | grep -- #{escape(regexp)}" end def check_installed(package, version=nil) "eix #{escape(package)} --installed" end def check_running(service) "/etc/init.d/#{escape(service)} status" end end end end specinfra-0.1.1/lib/specinfra/command/linux.rb000066400000000000000000000036241225746440500213230ustar00rootroot00000000000000module SpecInfra module Command class Linux < Base def check_access_by_user(file, user, access) "su -s /bin/sh -c \"test -#{access} #{file}\" #{user}" end def check_iptables_rule(rule, table=nil, chain=nil) cmd = "iptables" cmd += " -t #{escape(table)}" if table cmd += " -S" cmd += " #{escape(chain)}" if chain cmd += " | grep -- #{escape(rule)}" cmd end def check_selinux(mode) cmd = "" cmd += "test ! -f /etc/selinux/config || (" if mode == "disabled" cmd += "getenforce | grep -i -- #{escape(mode)} " cmd += "&& grep -i -- ^SELINUX=#{escape(mode)}$ /etc/selinux/config" cmd += ")" if mode == "disabled" cmd end def check_kernel_module_loaded(name) "lsmod | grep ^#{name}" end def get_interface_speed_of(name) "ethtool #{name} | grep Speed | gawk '{print gensub(/Speed: ([0-9]+)Mb\\\/s/,\"\\\\1\",\"\")}'" end def check_ipv4_address(interface, ip_address) ip_address = ip_address.dup if ip_address =~ /\/\d+$/ ip_address << " " else ip_address << "/" end ip_address.gsub!(".", "\\.") "ip addr show #{interface} | grep 'inet #{ip_address}'" end def check_zfs(zfs, property=nil) if property.nil? "zfs list -H #{escape(zfs)}" else commands = [] property.sort.each do |key, value| regexp = "^#{value}$" commands << "zfs list -H -o #{escape(key)} #{escape(zfs)} | grep -- #{escape(regexp)}" end commands.join(' && ') end end def check_container(container) "lxc-ls -1 | grep -w #{escape(container)}" end def check_container_running(container) "lxc-info -n #{escape(container)} -t RUNNING" end end end end specinfra-0.1.1/lib/specinfra/command/plamo.rb000066400000000000000000000011311225746440500212630ustar00rootroot00000000000000module SpecInfra module Command class Plamo < Linux def check_enabled(service, level=3) # This check is not necessarily detected whether service is enabled or not # TODO: check rc.inet2 $SERV variable "test -x /etc/rc.d/init.d/#{escape(service)}" end def check_installed(package, version=nil) cmd = "ls /var/log/packages/#{escape(package)}" if version cmd = "#{cmd} && grep -E \"PACKAGE NAME:.+#{escape(package)}-#{escape(version)}\" /var/log/packages/#{escape(package)}" end cmd end end end end specinfra-0.1.1/lib/specinfra/command/redhat.rb000066400000000000000000000020241225746440500214240ustar00rootroot00000000000000module SpecInfra module Command class RedHat < Linux def check_access_by_user(file, user, access) # Redhat-specific "runuser -s /bin/sh -c \"test -#{access} #{file}\" #{user}" end def check_enabled(service, level=3) "chkconfig --list #{escape(service)} | grep #{level}:on" end def check_yumrepo(repository) "yum repolist all -C | grep ^#{escape(repository)}" end def check_yumrepo_enabled(repository) "yum repolist all -C | grep ^#{escape(repository)} | grep enabled" end def check_installed(package,version=nil) cmd = "rpm -q #{escape(package)}" if version cmd = "#{cmd} | grep -w -- #{escape(version)}" end cmd end alias :check_installed_by_rpm :check_installed def install(package) cmd = "yum -y install #{package}" end def get_package_version(package, opts=nil) "rpm -qi #{package} | grep Version | awk '{print $3}'" end end end end specinfra-0.1.1/lib/specinfra/command/smartos.rb000066400000000000000000000010741225746440500216510ustar00rootroot00000000000000module SpecInfra module Command class SmartOS < Solaris def check_installed(package, version=nil) cmd = "/opt/local/bin/pkgin list 2> /dev/null | grep -qw ^#{escape(package)}" if version cmd = "#{cmd}-#{escape(version)}" end cmd end def check_enabled(service, level=3) "svcs -l #{escape(service)} 2> /dev/null | grep -wx '^enabled.*true$'" end def check_running(service) "svcs -l #{escape(service)} status 2> /dev/null |grep -wx '^state.*online$'" end end end end specinfra-0.1.1/lib/specinfra/command/solaris.rb000066400000000000000000000075501225746440500216420ustar00rootroot00000000000000module SpecInfra module Command class Solaris < Base def check_enabled(service, level=3) "svcs -l #{escape(service)} 2> /dev/null | egrep '^enabled *true$'" end def check_installed(package, version=nil) cmd = "pkg list -H #{escape(package)} 2> /dev/null" if version cmd = "#{cmd} | grep -qw -- #{escape(version)}" end cmd end def check_listening(port) regexp = "\\.#{port} " "netstat -an 2> /dev/null | grep -- LISTEN | grep -- #{escape(regexp)}" end def check_listening_with_protocol(port, protocol) regexp = ".*\\.#{port} " "netstat -an -P #{escape(protocol)} 2> /dev/null | grep -- LISTEN | grep -- #{escape(regexp)}" end def check_running(service) "svcs -l #{escape(service)} status 2> /dev/null | egrep '^state *online$'" end def check_cron_entry(user, entry) entry_escaped = entry.gsub(/\*/, '\\*') if user.nil? "crontab -l | grep -- #{escape(entry_escaped)}" else "crontab -l #{escape(user)} | grep -- #{escape(entry_escaped)}" end end def check_zfs(zfs, property=nil) if property.nil? "zfs list -H #{escape(zfs)}" else commands = [] property.sort.each do |key, value| regexp = "^#{value}$" commands << "zfs list -H -o #{escape(key)} #{escape(zfs)} | grep -- #{escape(regexp)}" end commands.join(' && ') end end def check_ipfilter_rule(rule) "ipfstat -io 2> /dev/null | grep -- #{escape(rule)}" end def check_ipnat_rule(rule) regexp = "^#{rule}$" "ipnat -l 2> /dev/null | grep -- #{escape(regexp)}" end def check_svcprop(svc, property, value) regexp = "^#{value}$" "svcprop -p #{escape(property)} #{escape(svc)} | grep -- #{escape(regexp)}" end def check_svcprops(svc, property) commands = [] property.sort.each do |key, value| regexp = "^#{value}$" commands << "svcprop -p #{escape(key)} #{escape(svc)} | grep -- #{escape(regexp)}" end commands.join(' && ') end def check_file_contain_within(file, expected_pattern, from=nil, to=nil) from ||= '1' to ||= '$' sed = "sed -n #{escape(from)},#{escape(to)}p #{escape(file)}" checker_with_regexp = check_file_contain_with_regexp("/dev/stdin", expected_pattern) checker_with_fixed = check_file_contain_with_fixed_strings("/dev/stdin", expected_pattern) "#{sed} | #{checker_with_regexp} || #{sed} | #{checker_with_fixed}" end def check_belonging_group(user, group) "id -Gn #{escape(user)} | grep -- #{escape(group)}" end def check_gid(group, gid) regexp = "^#{group}:" "getent group | grep -- #{escape(regexp)} | cut -f 3 -d ':' | grep -w -- #{escape(gid)}" end def check_home_directory(user, path_to_home) "getent passwd #{escape(user)} | cut -f 6 -d ':' | grep -w -- #{escape(path_to_home)}" end def check_login_shell(user, path_to_shell) "getent passwd #{escape(user)} | cut -f 7 -d ':' | grep -w -- #{escape(path_to_shell)}" end def check_access_by_user(file, user, access) # http://docs.oracle.com/cd/E23823_01/html/816-5166/su-1m.html ## No need for login shell as it seems that behavior as superuser is favorable for us, but needs ## to be better tested under real solaris env "su #{user} -c \"test -#{access} #{file}\"" end def check_reachable(host, port, proto, timeout) if port.nil? "ping -n #{escape(host)} #{escape(timeout)}" else "nc -vvvvz#{escape(proto[0].chr)} -w #{escape(timeout)} #{escape(host)} #{escape(port)}" end end end end end specinfra-0.1.1/lib/specinfra/command/solaris10.rb000066400000000000000000000050611225746440500217760ustar00rootroot00000000000000module SpecInfra module Command class Solaris10 < Solaris # Please implement Solaris 10 specific commands # reference: http://perldoc.perl.org/functions/stat.html def check_mode(file, mode) regexp = "^#{mode}$" "perl -e 'printf \"%o\", (stat shift)[2]&07777' #{escape(file)} | grep -- #{escape(regexp)}" end # reference: http://perldoc.perl.org/functions/stat.html # http://www.tutorialspoint.com/perl/perl_getpwuid.htm def check_owner(file, owner) regexp = "^#{owner}$" "perl -e 'printf \"%s\", getpwuid((stat(\"#{escape(file)}\"))[4])' | grep -- #{escape(regexp)}" end def check_group(group) "getent group | grep -w -- #{escape(group)}" end # reference: http://perldoc.perl.org/functions/stat.html # http://www.tutorialspoint.com/perl/perl_getgrgid.htm def check_grouped(file, group) regexp = "^#{group}$" "perl -e 'printf \"%s\", getgrgid((stat(\"#{escape(file)}\"))[5])' | grep -- #{escape(regexp)}" end # reference: http://www.tutorialspoint.com/perl/perl_readlink.htm def check_link(link, target) regexp = "^#{target}$" "perl -e 'printf \"%s\", readlink(\"#{escape(link)}\")' | grep -- #{escape(regexp)}" end # reference: http://perldoc.perl.org/functions/stat.html def get_mode(file) "perl -e 'printf \"%o\", (stat shift)[2]&07777' #{escape(file)}" end def check_file_contain(file, expected_pattern) "grep -- #{escape(expected_pattern)} #{escape(file)}" end def check_reachable(host, port, proto, timeout) if port.nil? "ping -n #{escape(host)} #{escape(timeout)}" elsif proto == 'tcp' "echo 'quit' | mconnect -p #{escape(port)} #{escape(host)} > /dev/null 2>&1" else raise NotImplementedError.new end end def check_installed(package, version=nil) cmd = "pkginfo -q #{escape(package)}" if version cmd = "#{cmd} | grep -- #{escape(version)}" end cmd end def check_file_md5checksum(file, expected) "digest -a md5 -v #{escape(file)} | grep -iw -- #{escape(expected)}" end def check_belonging_group(user, group) "id -ap #{escape(user)} | grep -- #{escape(group)}" end def check_authorized_key(user, key) key.sub!(/\s+\S*$/, '') if key.match(/^\S+\s+\S+\s+\S*$/) "grep -- #{escape(key)} ~#{escape(user)}/.ssh/authorized_keys" end end end end specinfra-0.1.1/lib/specinfra/command/solaris11.rb000066400000000000000000000002101225746440500217660ustar00rootroot00000000000000module SpecInfra module Command class Solaris11 < Solaris # Please implement Solaris 11 specific commands end end end specinfra-0.1.1/lib/specinfra/command/ubuntu.rb000066400000000000000000000003331225746440500215000ustar00rootroot00000000000000module SpecInfra module Command class Ubuntu < Debian def check_running(service) "service #{escape(service)} status && service #{escape(service)} status | grep 'running'" end end end end specinfra-0.1.1/lib/specinfra/command/windows.rb000066400000000000000000000157711225746440500216640ustar00rootroot00000000000000module SpecInfra module Command class Windows class NotSupportedError < Exception; end REGISTRY_KEY_TYPES = { :type_string => 'String', :type_binary => 'Binary', :type_dword => 'DWord', :type_qword => 'QWord', :type_multistring => 'MultiString', :type_expandstring => 'ExpandString' } def method_missing method, *args raise NotSupportedError.new "#{method} currently not supported in Windows os" if method.to_s =~ /^check_.+/ super(method, *args) end def check_file(file) cmd = item_has_attribute file, 'Archive' Backend::PowerShell::Command.new do exec cmd end end def check_file_hidden(file) cmd = item_has_attribute file, 'Hidden' Backend::PowerShell::Command.new do exec cmd end end def check_file_readonly(file) cmd = item_has_attribute file, 'ReadOnly' Backend::PowerShell::Command.new do exec cmd end end def check_file_system(file) cmd = item_has_attribute file, 'System' Backend::PowerShell::Command.new do exec cmd end end def check_directory(dir) cmd = item_has_attribute dir, 'Directory' Backend::PowerShell::Command.new do exec cmd end end def check_file_contain(file, pattern) Backend::PowerShell::Command.new do exec "[Io.File]::ReadAllText('#{file}') -match '#{convert_regexp(pattern)}'" end end def check_file_contain_within file, pattern, from=nil, to=nil from ||= '^' to ||= '$' Backend::PowerShell::Command.new do using 'crop_text.ps1' exec %Q[(CropText -text ([Io.File]::ReadAllText('#{file}')) -fromPattern '#{convert_regexp(from)}' -toPattern '#{convert_regexp(to)}') -match '#{pattern}'] end end def check_access_by_user(file, user, access) case access when 'r' check_readable(file, user) when 'w' check_writable(file, user) when 'x' check_executable(file, user) end end def check_readable(file, by_whom) Backend::PowerShell::Command.new do using 'check_file_access_rules.ps1' exec "CheckFileAccessRules -path '#{file}' -identity '#{get_identity by_whom}' -rules @('FullControl', 'Modify', 'ReadAndExecute', 'Read', 'ListDirectory')" end end def check_writable(file, by_whom) Backend::PowerShell::Command.new do using 'check_file_access_rules.ps1' exec "CheckFileAccessRules -path '#{file}' -identity '#{get_identity by_whom}' -rules @('FullControl', 'Modify', 'Write')" end end def check_executable(file, by_whom) Backend::PowerShell::Command.new do using 'check_file_access_rules.ps1' exec "CheckFileAccessRules -path '#{file}' -identity '#{get_identity by_whom}' -rules @('FullControl', 'Modify', 'ReadAndExecute', 'ExecuteFile')" end end def check_installed(package, version=nil) version_selection = version.nil? ? "" : "-appVersion '#{version}'" Backend::PowerShell::Command.new do using 'find_installed_application.ps1' exec "(FindInstalledApplication -appName '#{package}' #{version_selection}) -ne $null" end end def check_enabled(service, level=nil) Backend::PowerShell::Command.new do using 'find_service.ps1' exec "(FindService -name '#{service}').StartMode -eq 'Auto'" end end def check_running(service) Backend::PowerShell::Command.new do using 'find_service.ps1' exec "(FindService -name '#{service}').State -eq 'Running'" end end def check_process(process) Backend::PowerShell::Command.new do exec "(Get-Process '#{process}') -ne $null" end end def check_listening(port) Backend::PowerShell::Command.new do using 'is_port_listening.ps1' exec "IsPortListening -portNumber #{port}" end end def check_listening_with_protocol(port, protocol) Backend::PowerShell::Command.new do using 'is_port_listening.ps1' exec "IsPortListening -portNumber #{port} -protocol '#{protocol}'" end end def check_user(user) user_id, domain = windows_account user Backend::PowerShell::Command.new do using 'find_user.ps1' exec "(FindUser -userName '#{user_id}'#{domain.nil? ? "" : " -domain '#{domain}'"}) -ne $null" end end def check_group(group) group_id, domain = windows_account group Backend::PowerShell::Command.new do using 'find_group.ps1' exec "(FindGroup -groupName '#{group_id}'#{domain.nil? ? "" : " -domain '#{domain}'"}) -ne $null" end end def check_belonging_group(user, group) user_id, user_domain = windows_account user group_id, group_domain = windows_account group Backend::PowerShell::Command.new do using 'find_user.ps1' using 'find_group.ps1' using 'find_usergroup.ps1' exec "(FindUserGroup -userName '#{user_id}'#{user_domain.nil? ? "" : " -userDomain '#{user_domain}'"} -groupName '#{group_id}'#{group_domain.nil? ? "" : " -groupDomain '#{group_domain}'"}) -ne $null" end end def check_registry_key(key_name, key_property = {}) if key_property.empty? cmd = "(Get-Item 'Registry::#{key_name}') -ne $null" else if key_property.key? :value value = convert_key_property_value key_property cmd = "(Compare-Object (Get-Item 'Registry::#{key_name}').GetValue('#{key_property[:name]}') #{value}) -eq $null" else cmd = "(Get-Item 'Registry::#{key_name}').GetValueKind('#{key_property[:name]}') -eq '#{REGISTRY_KEY_TYPES[key_property[:type]]}'" end end Backend::PowerShell::Command.new { exec cmd } end private def item_has_attribute item, attribute "((Get-Item -Path '#{item}' -Force).attributes.ToString() -Split ', ') -contains '#{attribute}'" end def convert_key_property_value property case property[:type] when :type_binary byte_array = [property[:value]].pack('H*').bytes.to_a "([byte[]] #{byte_array.join(',')})" when :type_dword [property[:value].scan(/[0-9a-f]{2}/i).reverse.join].pack("H*").unpack("l").first when :type_qword property[:value].hex else string_array = property[:value].split("\n").map {|s| "'#{s}'"}.reduce {|acc, s| "#{acc},#{s}"} "@(#{string_array})" end end def windows_account account match = /((.+)\\)?(.+)/.match account domain = match[2] name = match[3] [name, domain] end end end end specinfra-0.1.1/lib/specinfra/configuration.rb000066400000000000000000000013431225746440500214110ustar00rootroot00000000000000module SpecInfra module Configuration class << self VALID_OPTIONS_KEYS = [:path, :pre_command, :stdout, :stderr, :sudo_path, :disable_sudo, :pass_prompt].freeze def defaults VALID_OPTIONS_KEYS.inject({}) { |o, k| o.merge!(k => send(k)) } end def method_missing(meth, val=nil) key = meth.to_s key.gsub!(/=$/, '') if val instance_variable_set("@#{key}", val) RSpec.configuration.send(:"#{key}=", val) if defined?(RSpec) end ret = instance_variable_get("@#{key}") if ret.nil? && defined?(RSpec) && RSpec.configuration.respond_to?(key) ret = RSpec.configuration.send(key) end ret end end end end specinfra-0.1.1/lib/specinfra/helper.rb000066400000000000000000000004011225746440500200130ustar00rootroot00000000000000require 'specinfra/helper/os' require 'specinfra/helper/detect_os' require 'specinfra/helper/backend' include SpecInfra::Helper::Backend require 'specinfra/helper/configuration' require 'specinfra/helper/properties' include SpecInfra::Helper::Properties specinfra-0.1.1/lib/specinfra/helper/000077500000000000000000000000001225746440500174735ustar00rootroot00000000000000specinfra-0.1.1/lib/specinfra/helper/backend.rb000066400000000000000000000015421225746440500214110ustar00rootroot00000000000000module SpecInfra module Helper ['Exec', 'Ssh', 'Cmd', 'WinRM', 'ShellScript', 'Dockerfile'].each do |type| eval <<-EOF module #{type} def backend(commands_object=nil) if ! respond_to?(:commands) commands_object = SpecInfra::Command::Base.new end instance = SpecInfra::Backend::#{type}.instance instance.set_commands(commands_object || commands) instance end end EOF end module Backend def backend_for(type) instance = self.class.const_get('SpecInfra').const_get('Backend').const_get(type.to_s.capitalize).instance commands = self.class.const_get('SpecInfra').const_get('Command').const_get(instance.check_os[:family]).new instance.set_commands(commands) instance end end end end specinfra-0.1.1/lib/specinfra/helper/configuration.rb000066400000000000000000000022371225746440500226730ustar00rootroot00000000000000module SpecInfra module Helper module Configuration def subject example.metadata[:subject] = described_class build_configurations super end # You can create a set of configurations provided to all specs in your spec_helper: # # RSpec.configure { |c| c.pre_command = "source ~/.zshrc" } # # Any configurations you provide with `let(:option_name)` in a spec will # automatically be merged on top of the configurations. # # @example # # describe 'Gem' do # let(:pre_command) { "source ~/.zshrc" } # # %w(pry awesome_print bundler).each do |p| # describe package(p) do # it { should be_installed.by('gem') } # end # end # end def build_configurations SpecInfra::Configuration.defaults.keys.each do |c| if self.respond_to?(c.to_sym) value = self.send(c) else value = RSpec.configuration.send(c) if defined?(RSpec) end SpecInfra::Configuration.instance_variable_set("@#{c}", value) end end end end end specinfra-0.1.1/lib/specinfra/helper/detect_os.rb000066400000000000000000000011611225746440500217700ustar00rootroot00000000000000module SpecInfra module Helper module DetectOS def commands property[:os_by_host] = {} if ! property[:os_by_host] host = SpecInfra.configuration.ssh ? SpecInfra.configuration.ssh.host : 'localhost' if property[:os_by_host][host] os = property[:os_by_host][host] else # Set command object explicitly to avoid `stack too deep` os = backend(SpecInfra::Command::Base.new).check_os property[:os_by_host][host] = os end self.class.const_get('SpecInfra').const_get('Command').const_get(os[:family]).new end end end end specinfra-0.1.1/lib/specinfra/helper/os.rb000066400000000000000000000006561225746440500204500ustar00rootroot00000000000000module SpecInfra module Helper [ 'Base', 'AIX', 'Darwin', 'Debian', 'FreeBSD', 'Gentoo', 'Plamo', 'RedHat', 'SmartOS', 'Solaris', 'Solaris10', 'Solaris11', 'Ubuntu', 'Windows', ].each do |os| eval <<-EOF module #{os} def commands SpecInfra::Command::#{os}.new end end EOF end end end specinfra-0.1.1/lib/specinfra/helper/properties.rb000066400000000000000000000004271225746440500222170ustar00rootroot00000000000000require 'specinfra/properties' module SpecInfra module Helper module Properties def property SpecInfra::Properties.instance.properties end def set_property(prop) SpecInfra::Properties.instance.properties(prop) end end end end specinfra-0.1.1/lib/specinfra/properties.rb000066400000000000000000000003531225746440500207360ustar00rootroot00000000000000require 'singleton' module SpecInfra class Properties include Singleton def initialize @prop = {} end def properties(prop=nil) if ! prop.nil? @prop = prop end @prop end end end specinfra-0.1.1/lib/specinfra/version.rb000066400000000000000000000000511225746440500202220ustar00rootroot00000000000000module Specinfra VERSION = "0.1.1" end specinfra-0.1.1/spec/000077500000000000000000000000001225746440500144265ustar00rootroot00000000000000specinfra-0.1.1/spec/backend/000077500000000000000000000000001225746440500160155ustar00rootroot00000000000000specinfra-0.1.1/spec/backend/ssh/000077500000000000000000000000001225746440500166125ustar00rootroot00000000000000specinfra-0.1.1/spec/backend/ssh/build_command_spec.rb000066400000000000000000000063451225746440500227560ustar00rootroot00000000000000require 'spec_helper' include SpecInfra::Helper::Ssh ssh = double describe 'build command with sudo' do before :each do RSpec.configure do |c| ssh.stub(:options) { { :user => 'foo' } } c.ssh = ssh c.sudo_path = nil end end context 'command pattern 1' do subject { backend.build_command('test -f /etc/passwd') } it { should eq 'sudo test -f /etc/passwd' } end context 'command pattern 2' do subject { backend.build_command('test ! -f /etc/selinux/config || (getenforce | grep -i -- disabled && grep -i -- ^SELINUX=disabled$ /etc/selinux/config)') } it { should eq 'sudo test ! -f /etc/selinux/config || (sudo getenforce | grep -i -- disabled && sudo grep -i -- ^SELINUX=disabled$ /etc/selinux/config)' } end context 'command pattern 3' do subject { backend.build_command("dpkg -s apache2 && ! dpkg -s apache2 | grep -E '^Status: .+ not-installed$'") } it { should eq "sudo dpkg -s apache2 && ! sudo dpkg -s apache2 | grep -E '^Status: .+ not-installed$'" } end end # Alternate path for sudo command: sudo_path = '/usr/local/bin' describe 'build command with sudo on alternate path' do before :each do RSpec.configure do |c| ssh.stub(:options) { { :user => 'foo' } } c.ssh = ssh c.sudo_path = "#{sudo_path}" end end context 'command pattern 1a' do subject { backend.build_command('test -f /etc/passwd') } it { should eq "#{sudo_path}/sudo test -f /etc/passwd" } end context 'command pattern 2a' do subject { backend.build_command('test ! -f /etc/selinux/config || (getenforce | grep -i -- disabled && grep -i -- ^SELINUX=disabled$ /etc/selinux/config)') } it { should eq "#{sudo_path}/sudo test ! -f /etc/selinux/config || (#{sudo_path}/sudo getenforce | grep -i -- disabled && #{sudo_path}/sudo grep -i -- ^SELINUX=disabled$ /etc/selinux/config)" } end context 'command pattern 3a' do subject { backend.build_command("dpkg -s apache2 && ! dpkg -s apache2 | grep -E '^Status: .+ not-installed$'") } it { should eq "#{sudo_path}/sudo dpkg -s apache2 && ! #{sudo_path}/sudo dpkg -s apache2 | grep -E '^Status: .+ not-installed$'" } end after :each do RSpec.configure do |c| c.sudo_path = nil end end end describe 'build command without sudo' do before :each do RSpec.configure do |c| ssh.stub(:options) { { :user => 'foo' } } c.ssh = ssh c.disable_sudo = true end end context 'command pattern 1b' do subject { backend.build_command('test -f /etc/passwd') } it { should eq 'test -f /etc/passwd' } end context 'command pattern 2b' do subject { backend.build_command('test ! -f /etc/selinux/config || (getenforce | grep -i -- disabled && grep -i -- ^SELINUX=disabled$ /etc/selinux/config)') } it { should eq 'test ! -f /etc/selinux/config || (getenforce | grep -i -- disabled && grep -i -- ^SELINUX=disabled$ /etc/selinux/config)' } end context 'command pattern 3b' do subject { backend.build_command("dpkg -s apache2 && ! dpkg -s apache2 | grep -E '^Status: .+ not-installed$'") } it { should eq "dpkg -s apache2 && ! dpkg -s apache2 | grep -E '^Status: .+ not-installed$'" } end after :each do RSpec.configure do |c| c.disable_sudo = false end end end specinfra-0.1.1/spec/configuration_spec.rb000066400000000000000000000002351225746440500206340ustar00rootroot00000000000000require 'spec_helper' RSpec.configure do |c| c.path = 'foo' end describe RSpec.configuration.path do it { should eq SpecInfra.configuration.path } end specinfra-0.1.1/spec/helper/000077500000000000000000000000001225746440500157055ustar00rootroot00000000000000specinfra-0.1.1/spec/helper/backend_spec.rb000066400000000000000000000005721225746440500206370ustar00rootroot00000000000000require 'spec_helper' describe 'backend_for(:type) returns correct backend object' do it 'backend_for(:exec) returns SpecInfra::Backend::Exec' do expect(backend_for(:exec)).to be_an_instance_of SpecInfra::Backend::Exec end it 'backend_for(:ssh) returns SpecInfra::Backend::Ssh' do expect(backend_for(:ssh)).to be_an_instance_of SpecInfra::Backend::Ssh end end specinfra-0.1.1/spec/helper/properties_spec.rb000066400000000000000000000003331225746440500214370ustar00rootroot00000000000000require 'spec_helper' include SpecInfra::Helper::Properties describe 'Properties Helper' do before :all do set_property :role => 'proxy' end subject { property } it { should include :role => 'proxy' } end specinfra-0.1.1/spec/spec_helper.rb000066400000000000000000000004441225746440500172460ustar00rootroot00000000000000require 'specinfra' require 'rspec/mocks/standalone' include SpecInfra::Helper::Exec module SpecInfra module Backend class Ssh def run_command(cmd, opts={}) { :stdout => nil, :stderr => nil, :exit_status => 0, :exit_signal => nil } end end end end specinfra-0.1.1/specinfra.gemspec000066400000000000000000000016121225746440500170130ustar00rootroot00000000000000# coding: utf-8 lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'specinfra/version' Gem::Specification.new do |spec| spec.name = "specinfra" spec.version = Specinfra::VERSION spec.authors = ["Gosuke Miyashita"] spec.email = ["gosukenator@gmail.com"] spec.description = %q{Common layer for serverspec and configspec} spec.summary = %q{Common layer for serverspec and configspec} spec.homepage = "" spec.license = "MIT" spec.files = `git ls-files`.split($/) spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = ["lib"] spec.add_development_dependency "bundler", "~> 1.3" spec.add_development_dependency "rake" spec.add_development_dependency "rspec" end