host_range 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/Gemfile +15 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +26 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/bin/hr +72 -0
- data/examples/hr.yaml +7 -0
- data/lib/host_range.rb +38 -0
- data/test/helper.rb +18 -0
- data/test/test_host_range.rb +7 -0
- metadata +111 -0
data/.document
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
source "http://rubygems.org"
|
3
|
+
# Add dependencies required to use your gem here.
|
4
|
+
# Example:
|
5
|
+
# gem "activesupport", ">= 2.3.5"
|
6
|
+
|
7
|
+
# Add dependencies to develop your gem here.
|
8
|
+
# Include everything needed to run rake, tests, features, etc.
|
9
|
+
group :development do
|
10
|
+
gem "shoulda", ">= 0"
|
11
|
+
gem "bundler", "~> 1.0.0"
|
12
|
+
gem "jeweler", "~> 1.6.4"
|
13
|
+
gem "rcov", ">= 0"
|
14
|
+
require "./lib/host_range"
|
15
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Richard Lister
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
= host_range
|
2
|
+
|
3
|
+
Make lists of hosts using ranges like:
|
4
|
+
|
5
|
+
* foo-[01-09].domain.com
|
6
|
+
* bar-[ab][1-3,6-9].domain.com
|
7
|
+
|
8
|
+
== Library Usage
|
9
|
+
|
10
|
+
require 'host_range'
|
11
|
+
hosts = HostRange.parse('foo-[01-09].domain.com')
|
12
|
+
|
13
|
+
== Command-line Usage
|
14
|
+
|
15
|
+
Commandline tool lists hosts, or execs commands on them in a loop:
|
16
|
+
|
17
|
+
* hr -h
|
18
|
+
* hr foo-[01-09].domain.com
|
19
|
+
* hr foo-[01-09].domain.com -e ssh root@{} hostname
|
20
|
+
|
21
|
+
Can provide a config file (~/.hr.yaml) with predefined patterns called by name.
|
22
|
+
|
23
|
+
== Copyright
|
24
|
+
|
25
|
+
Copyright (c) 2011 Richard Lister. See LICENSE.txt for
|
26
|
+
further details.
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "host_range"
|
18
|
+
gem.homepage = "http://github.com/rlister/host_range"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{Convert hostname range pattern into array of hostnames.}
|
21
|
+
gem.description = %Q{Allows specification of hostname ranges such as foo-[01-09].}
|
22
|
+
gem.email = "rlister+gh@gmail.com"
|
23
|
+
gem.authors = ["Richard Lister"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rake/testtask'
|
29
|
+
Rake::TestTask.new(:test) do |test|
|
30
|
+
test.libs << 'lib' << 'test'
|
31
|
+
test.pattern = 'test/**/test_*.rb'
|
32
|
+
test.verbose = true
|
33
|
+
end
|
34
|
+
|
35
|
+
require 'rcov/rcovtask'
|
36
|
+
Rcov::RcovTask.new do |test|
|
37
|
+
test.libs << 'test'
|
38
|
+
test.pattern = 'test/**/test_*.rb'
|
39
|
+
test.verbose = true
|
40
|
+
test.rcov_opts << '--exclude "gems/*"'
|
41
|
+
end
|
42
|
+
|
43
|
+
task :default => :test
|
44
|
+
|
45
|
+
require 'rake/rdoctask'
|
46
|
+
Rake::RDocTask.new do |rdoc|
|
47
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
48
|
+
|
49
|
+
rdoc.rdoc_dir = 'rdoc'
|
50
|
+
rdoc.title = "host_range #{version}"
|
51
|
+
rdoc.rdoc_files.include('README*')
|
52
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
53
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.0
|
data/bin/hr
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
## expand hostname patterns
|
3
|
+
|
4
|
+
require 'yaml'
|
5
|
+
require 'optparse'
|
6
|
+
require 'host_range'
|
7
|
+
|
8
|
+
options = {
|
9
|
+
:separator => nil, # separates hostname in output
|
10
|
+
:grep => false, # grep hostnames for this regex
|
11
|
+
:config => "#{ENV['HOME']}/.#{File.basename($0)}.yaml", # config file with host lists
|
12
|
+
:exec => nil, # command to exec on each hostname
|
13
|
+
}
|
14
|
+
|
15
|
+
OptionParser.new do |opt|
|
16
|
+
opt.banner = "Usage: #{$0} [-h] [-a] [-l] [-c cfg] [-g regex] [-x] [-s char] [patterns] [-e cmd {}]"
|
17
|
+
|
18
|
+
opt.on("-a", "--all", "List all hosts from config.") { |a| options[:all] = a }
|
19
|
+
opt.on("-c", "--config FILE", "Config file to load.") { |c| options[:config] = c }
|
20
|
+
opt.on("-g", "--grep PATTERN", "Grep host list for regex.") { |g| options[:grep] = Regexp.new(g) }
|
21
|
+
opt.on("-l", "--list", "List projects from config.") { |l| options[:list] = l }
|
22
|
+
opt.on("-s", "--separator CHAR", "Set separator for output.") { |s| options[:separator] = s }
|
23
|
+
opt.on("-x", "--xargs", "Output hosts on one line.") { |x| options[:separator] = ' ' }
|
24
|
+
opt.on("-e", "--exec COMMAND", "Exec COMMAND on each hostname; must be last arg.") do |e|
|
25
|
+
options[:exec] = ARGV.shift(ARGV.length).unshift(e).join(' ') # slurp up rest of ARGV as cmd to exec
|
26
|
+
end
|
27
|
+
opt.on_tail("-h", "--help", "Show this message.") do
|
28
|
+
puts opt
|
29
|
+
puts "Example patterns: host-[abc][01,03,08-12].domain.com"
|
30
|
+
exit
|
31
|
+
end
|
32
|
+
|
33
|
+
end.parse!
|
34
|
+
|
35
|
+
## load config file
|
36
|
+
yaml = File.exists?(options[:config]) ? YAML.load_file(options[:config]) : {}
|
37
|
+
|
38
|
+
## -l option: list projects
|
39
|
+
if options[:list]
|
40
|
+
projects = yaml.keys.sort
|
41
|
+
puts(options[:separator] ? projects.join(options[:separator]) : projects)
|
42
|
+
exit
|
43
|
+
end
|
44
|
+
|
45
|
+
## -a option: list hosts for all projects
|
46
|
+
if options[:all]
|
47
|
+
ARGV.replace yaml.keys
|
48
|
+
end
|
49
|
+
|
50
|
+
## args are either a key in config file, or a hostname pattern to expand
|
51
|
+
patterns = ARGV.map { |arg| yaml[arg] ? yaml[arg] : arg }.flatten
|
52
|
+
|
53
|
+
## convert each pattern to list of hosts
|
54
|
+
hosts = patterns.map { |p| HostRange.parse(p) }.flatten
|
55
|
+
|
56
|
+
## -g option
|
57
|
+
hosts = hosts.grep(options[:grep]) if options[:grep]
|
58
|
+
|
59
|
+
## -s or -x option
|
60
|
+
hosts.replace [hosts.join(options[:separator])] if options[:separator]
|
61
|
+
|
62
|
+
## -e option, loop hosts and run command
|
63
|
+
if options[:exec]
|
64
|
+
hosts.each do |host|
|
65
|
+
command = options[:exec].dup
|
66
|
+
command.sub!(/\{\}/, host) || command.insert(-1, " #{host}") # put hostname at {} or end
|
67
|
+
system command
|
68
|
+
end
|
69
|
+
## default, just list hosts
|
70
|
+
else
|
71
|
+
puts hosts
|
72
|
+
end
|
data/examples/hr.yaml
ADDED
data/lib/host_range.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'pp'
|
2
|
+
class HostRange
|
3
|
+
|
4
|
+
## wrapper returns flattened array
|
5
|
+
def self.parse(pattern)
|
6
|
+
parseRange(pattern).flatten
|
7
|
+
end
|
8
|
+
|
9
|
+
## parse lists [123] or ranges [1-3],
|
10
|
+
## recurses until all [...] patterns have been subbed (left to right)
|
11
|
+
def self.parseRange(pattern)
|
12
|
+
string = pattern.dup # arg is immutable
|
13
|
+
|
14
|
+
## list like [123] is split into atoms 1,2,3
|
15
|
+
if string.sub!(/\[(\w+)\]/, "%s")
|
16
|
+
$1.split(//).map { |n| parseRange(sprintf(string, n)) }
|
17
|
+
|
18
|
+
## comma-separated list like [01, 03, 09-12]
|
19
|
+
elsif string.sub!(/\[([\s\w,-]+)\]/, "%s")
|
20
|
+
$1.split(/\s*,\s*/).map do |n|
|
21
|
+
|
22
|
+
## range like 09-12
|
23
|
+
if n.sub!(/(\w+)-(\w+)/, "%s")
|
24
|
+
($1..$2).map { |o| parseRange(sprintf(string, o)) }
|
25
|
+
|
26
|
+
## simple string like 01
|
27
|
+
else
|
28
|
+
parseRange(sprintf(string, n))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
## simple string with no more patterns to sub
|
33
|
+
else
|
34
|
+
[string]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'test/unit'
|
11
|
+
require 'shoulda'
|
12
|
+
|
13
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
14
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
15
|
+
require 'host_range'
|
16
|
+
|
17
|
+
class Test::Unit::TestCase
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: host_range
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.0
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Richard Lister
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-09-15 00:00:00 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: shoulda
|
17
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: "0"
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *id001
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: bundler
|
28
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.0.0
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *id002
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: jeweler
|
39
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ~>
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: 1.6.4
|
45
|
+
type: :development
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: *id003
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: rcov
|
50
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: "0"
|
56
|
+
type: :development
|
57
|
+
prerelease: false
|
58
|
+
version_requirements: *id004
|
59
|
+
description: Allows specification of hostname ranges such as foo-[01-09].
|
60
|
+
email: rlister+gh@gmail.com
|
61
|
+
executables:
|
62
|
+
- hr
|
63
|
+
extensions: []
|
64
|
+
|
65
|
+
extra_rdoc_files:
|
66
|
+
- LICENSE.txt
|
67
|
+
- README.rdoc
|
68
|
+
files:
|
69
|
+
- .document
|
70
|
+
- Gemfile
|
71
|
+
- LICENSE.txt
|
72
|
+
- README.rdoc
|
73
|
+
- Rakefile
|
74
|
+
- VERSION
|
75
|
+
- bin/hr
|
76
|
+
- examples/hr.yaml
|
77
|
+
- lib/host_range.rb
|
78
|
+
- test/helper.rb
|
79
|
+
- test/test_host_range.rb
|
80
|
+
homepage: http://github.com/rlister/host_range
|
81
|
+
licenses:
|
82
|
+
- MIT
|
83
|
+
post_install_message:
|
84
|
+
rdoc_options: []
|
85
|
+
|
86
|
+
require_paths:
|
87
|
+
- lib
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
hash: 1458013719312908271
|
94
|
+
segments:
|
95
|
+
- 0
|
96
|
+
version: "0"
|
97
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: "0"
|
103
|
+
requirements: []
|
104
|
+
|
105
|
+
rubyforge_project:
|
106
|
+
rubygems_version: 1.8.5
|
107
|
+
signing_key:
|
108
|
+
specification_version: 3
|
109
|
+
summary: Convert hostname range pattern into array of hostnames.
|
110
|
+
test_files: []
|
111
|
+
|