continuent-tools-core 0.9.0 → 0.10.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +23 -2
- data/bin/tungsten_analyze_thl_index +23 -10
- data/bin/tungsten_create_load +38 -7
- data/bin/tungsten_directory +379 -0
- data/bin/tungsten_manage_configuration +1654 -0
- data/bin/tungsten_migrate_schema +123 -0
- data/lib/continuent-tools-core.rb +123 -0
- data/lib/ipparse.rb +144 -0
- data/lib/ipparse/README +18 -0
- data/lib/ipparse/platforms/linux.rb +103 -0
- data/lib/tungsten/datasources/mysql.rb +4 -36
- data/lib/tungsten/exec.rb +16 -16
- data/lib/tungsten/script.rb +57 -121
- data/lib/tungsten/util.rb +0 -9
- data/providers/awsec2.rb +141 -0
- metadata +12 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 98ee92f1a8d4f2e609211c326b0fe054e9a048ad
|
4
|
+
data.tar.gz: 1a99ad83f75681fca485e740677e876d56fc519f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e97a7d38b5089aa673929764ccac1fa0331921359143e241148d3e693288163c01051a5f13150e80a81996a592ffc167b662fa46d48b870fbe13c4488374295e
|
7
|
+
data.tar.gz: 9da41564c3b4534072dac80f4680fa207b95d6841e7921c5006d034103282d2c859c641b612ae995b7ccd33d0465aec668879dc73a1f065ab20a9834aad0e6ff
|
data/README.md
CHANGED
@@ -1,9 +1,30 @@
|
|
1
1
|
continuent-tools-core
|
2
2
|
=====================
|
3
3
|
|
4
|
-
The continuent-tools-core is a package of libraries
|
4
|
+
The continuent-tools-core is a package of libraries and scripts to use with most Continuent Tungsten deployments. It is the basis for all other RubyGems distributed by Continuent.
|
5
5
|
|
6
|
-
|
6
|
+
The code is focused around the 'TungstenScript' Ruby class that is found in Tungsten Replicator. When the gem is built, these files are automatically exported from [https://code.google.com/p/tungsten-replicator/](https://code.google.com/p/tungsten-replicator/).
|
7
|
+
|
8
|
+
Installation may be done using the `gem` utility. This will ensure that all prerequisites are installed.
|
9
|
+
|
10
|
+
$> gem install continuent-tools-core
|
11
|
+
|
12
|
+
Using the tungsten\_create\_load script
|
13
|
+
===
|
14
|
+
|
15
|
+
The tungsten\_create\_load script may be used to apply load directly to a MySQL server or through a Tungsten Connector. By default, the script will read your configuration and use the Tungsten Connector if it is available. This may be disabled by adding '--use-connector=false'.
|
16
|
+
|
17
|
+
Automated Continuent Tungsten management scripts
|
18
|
+
===
|
19
|
+
|
20
|
+
The automated Continuent Tungsten management scripts are designed to be used as a way to manage Continuent Tungsten host configurations. They use provided or discovered directory information to determine the configuration of the local host and install or update the necessary components.
|
21
|
+
|
22
|
+
These tools can be called using CRON, Puppet, Chef or other devops tools with little customization to the specific platform.
|
23
|
+
|
24
|
+
See [MANAGE\_CONFIGURATION.md](MANAGE\_CONFIGURATION.md) for more details.
|
25
|
+
|
26
|
+
Using the TungstenScript class
|
27
|
+
===
|
7
28
|
|
8
29
|
Script Structure
|
9
30
|
---
|
@@ -50,15 +50,28 @@ class TungstenParseTHLIndex
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def find_thl_record
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
53
|
+
filename = nil
|
54
|
+
|
55
|
+
begin
|
56
|
+
each_thl_index_line() {
|
57
|
+
|line|
|
58
|
+
match = parse_thl_index_line(line)
|
59
|
+
if match != nil
|
60
|
+
if match[:start] <= opt(:seqno) && match[:end] >= opt(:seqno)
|
61
|
+
filename = match[:file]
|
62
|
+
raise IgnoreError.new()
|
63
|
+
end
|
59
64
|
end
|
60
|
-
|
61
|
-
|
65
|
+
}
|
66
|
+
rescue IgnoreError
|
67
|
+
# Do Nothing
|
68
|
+
end
|
69
|
+
|
70
|
+
if filename != nil
|
71
|
+
TU.output(filename)
|
72
|
+
else
|
73
|
+
TU.error("Unable to find THL event ##{opt(:seqno)}")
|
74
|
+
end
|
62
75
|
end
|
63
76
|
|
64
77
|
def parse_thl_index_line(line)
|
@@ -76,14 +89,14 @@ class TungstenParseTHLIndex
|
|
76
89
|
end
|
77
90
|
|
78
91
|
def each_thl_index_line(&block)
|
79
|
-
TU.cmd_stdout("
|
92
|
+
TU.cmd_stdout("#{TI.thl(opt(:service))} index") {
|
80
93
|
|line|
|
81
94
|
block.call(line.strip())
|
82
95
|
}
|
83
96
|
end
|
84
97
|
|
85
98
|
def get_thl_index
|
86
|
-
return TU.cmd_result("
|
99
|
+
return TU.cmd_result("#{TI.thl(opt(:service))} index").split("\n")
|
87
100
|
end
|
88
101
|
|
89
102
|
def configure
|
data/bin/tungsten_create_load
CHANGED
@@ -54,7 +54,16 @@ class ContinuentCreateLoad
|
|
54
54
|
# generation thread.
|
55
55
|
load_threads.peach{
|
56
56
|
|load_thread|
|
57
|
-
|
57
|
+
while (ContinuentCreateLoad.interrupted?() == false)
|
58
|
+
begin
|
59
|
+
TU.cmd(get_mysql_command() + " -h#{load_thread[:host]}", true, method(:create_schema_load), nil, method(:forward_mysql_errors))
|
60
|
+
rescue => e
|
61
|
+
TU.debug(e)
|
62
|
+
end
|
63
|
+
if ContinuentCreateLoad.interrupted?() == false
|
64
|
+
TU.notice("Reconnecting to the closed MySQL connection.")
|
65
|
+
end
|
66
|
+
end
|
58
67
|
}
|
59
68
|
|
60
69
|
puts("\n")
|
@@ -65,7 +74,12 @@ class ContinuentCreateLoad
|
|
65
74
|
[
|
66
75
|
"DROP SCHEMA IF EXISTS tungsten_create_load;",
|
67
76
|
"CREATE SCHEMA tungsten_create_load;",
|
68
|
-
"CREATE TABLE tungsten_create_load
|
77
|
+
"CREATE TABLE tungsten_create_load.#{opt(:table_name)} (
|
78
|
+
id int NOT NULL auto_increment primary key,
|
79
|
+
val int NOT NULL,
|
80
|
+
origin varchar(32) NULL,
|
81
|
+
filler varchar(1024) NULL
|
82
|
+
);"
|
69
83
|
].each{|sql|
|
70
84
|
stdin.puts(sql)
|
71
85
|
putc '.'
|
@@ -74,13 +88,15 @@ class ContinuentCreateLoad
|
|
74
88
|
end
|
75
89
|
|
76
90
|
def create_schema_load(stdin)
|
77
|
-
|
91
|
+
value = ""; 1024.times{value << ((rand(2)==1?65:97) + rand(25)).chr}
|
92
|
+
sql = "INSERT INTO tungsten_create_load.#{opt(:table_name)} (val, origin, filler) VALUES (5, @@hostname, '#{value}');"*[opt(:chunk_size),1].max()
|
78
93
|
while (ContinuentCreateLoad.interrupted?() == false)
|
79
94
|
stdin.puts(sql)
|
80
95
|
putc '.'
|
81
96
|
$stdout.flush()
|
82
97
|
sleep opt(:sleep).to_i()
|
83
98
|
end
|
99
|
+
stdin.puts("exit")
|
84
100
|
end
|
85
101
|
|
86
102
|
def forward_mysql_errors(msg)
|
@@ -102,6 +118,13 @@ class ContinuentCreateLoad
|
|
102
118
|
:default => 1,
|
103
119
|
})
|
104
120
|
|
121
|
+
add_option(:chunk_size, {
|
122
|
+
:on => "--chunk-size String",
|
123
|
+
:parse => method(:parse_integer_option),
|
124
|
+
:help => "How many rows should be entered per iteration",
|
125
|
+
:default => 10,
|
126
|
+
})
|
127
|
+
|
105
128
|
add_option(:sleep, {
|
106
129
|
:on => "--sleep String",
|
107
130
|
:parse => method(:parse_integer_option),
|
@@ -114,6 +137,12 @@ class ContinuentCreateLoad
|
|
114
137
|
:parse => method(:parse_boolean_option),
|
115
138
|
:help => "Enable/Disable use of the Tungsten Connector for adding load to the system.",
|
116
139
|
})
|
140
|
+
|
141
|
+
add_option(:table_name, {
|
142
|
+
:on => "--table-name String",
|
143
|
+
:help => "The MySQL table name to fill with this script",
|
144
|
+
:default => "values"
|
145
|
+
})
|
117
146
|
end
|
118
147
|
|
119
148
|
def validate
|
@@ -123,7 +152,7 @@ class ContinuentCreateLoad
|
|
123
152
|
return TU.is_valid?()
|
124
153
|
end
|
125
154
|
|
126
|
-
if opt(:use_connector) == nil
|
155
|
+
if opt(:use_connector) == nil || opt(:use_connector) == true
|
127
156
|
if TI.is_connector?()
|
128
157
|
opt(:use_connector, true)
|
129
158
|
|
@@ -139,14 +168,17 @@ class ContinuentCreateLoad
|
|
139
168
|
defaults_file.puts("password=#{TI.setting(TI.setting_key(CONNECTORS, "connector_password"))}")
|
140
169
|
defaults_file.flush()
|
141
170
|
|
142
|
-
opt(:mysqlport, TI.setting(TI.setting_key(CONNECTORS, "connector_listen_port")))
|
143
171
|
opt(:mysqlhost, TI.hostname())
|
172
|
+
opt(:mysqlport, TI.setting(TI.setting_key(CONNECTORS, "connector_listen_port")))
|
144
173
|
elsif TI.is_replicator?()
|
145
174
|
opt(:use_connector, false)
|
146
175
|
|
147
176
|
if TI.setting(TI.setting_key(REPL_SERVICES, @options[:service], "repl_datasource_type")) != "mysql"
|
148
177
|
TU.error("Unable to create load on this system because it is not configured for MySQL")
|
149
178
|
end
|
179
|
+
|
180
|
+
opt(:mysqlhost, TI.setting(TI.setting_key(REPL_SERVICES, opt(:service), "repl_direct_datasource_host")))
|
181
|
+
opt(:mysqlport, TI.setting(TI.setting_key(REPL_SERVICES, opt(:service), "repl_direct_datasource_port")))
|
150
182
|
else
|
151
183
|
TU.error("Unable to create load on this system because it is not configured as a Tungsten Connector or Tungsten Replicator")
|
152
184
|
end
|
@@ -157,10 +189,9 @@ class ContinuentCreateLoad
|
|
157
189
|
|h|
|
158
190
|
(h == TI.hostname())
|
159
191
|
}
|
160
|
-
hosts << TI.hostname()
|
161
192
|
opt(:hosts, hosts)
|
162
193
|
else
|
163
|
-
opt(:hosts, [
|
194
|
+
opt(:hosts, [opt(:mysqlhost)])
|
164
195
|
end
|
165
196
|
end
|
166
197
|
|
@@ -0,0 +1,379 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Copyright (C) 2014 Continuent, Inc.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
5
|
+
# not use this file except in compliance with the License. You may obtain
|
6
|
+
# a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
12
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
13
|
+
# License for the specific language governing permissions and limitations
|
14
|
+
# under the License.
|
15
|
+
#
|
16
|
+
# Initial developer(s): Jeff Mace
|
17
|
+
# Contributor(s):
|
18
|
+
|
19
|
+
# TODO : Add commands to output host definitions in Chef form
|
20
|
+
|
21
|
+
begin
|
22
|
+
require 'rubygems'
|
23
|
+
gem 'continuent-tools-core'
|
24
|
+
rescue LoadError
|
25
|
+
end
|
26
|
+
|
27
|
+
require 'continuent-tools-core'
|
28
|
+
|
29
|
+
class TungstenDirectoryProvider
|
30
|
+
def initialize(key)
|
31
|
+
@key = key
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.inherited(subclass)
|
35
|
+
@subclasses ||= []
|
36
|
+
@subclasses << subclass
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.subclasses
|
40
|
+
@subclasses
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.get_provider(key)
|
44
|
+
@subclasses.each{
|
45
|
+
|klass|
|
46
|
+
|
47
|
+
regex = Regexp.new(klass.get_regex())
|
48
|
+
if key =~ regex
|
49
|
+
return klass.new(key)
|
50
|
+
end
|
51
|
+
}
|
52
|
+
|
53
|
+
nil
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
Dir.glob(File.dirname(__FILE__) + '/../providers/*.rb').each do |file|
|
58
|
+
begin
|
59
|
+
require file
|
60
|
+
rescue IgnoreError
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class TungstenDirectory
|
65
|
+
include TungstenScript
|
66
|
+
private
|
67
|
+
|
68
|
+
def main
|
69
|
+
directory_entries = collect_directory_entries()
|
70
|
+
|
71
|
+
unless TU.is_valid?
|
72
|
+
return
|
73
|
+
end
|
74
|
+
|
75
|
+
case command()
|
76
|
+
when "list"
|
77
|
+
TU.output(JSON.pretty_generate(directory_entries))
|
78
|
+
when "hosts"
|
79
|
+
if directory_entries.has_key?(opt(:hostname))
|
80
|
+
location = directory_entries[opt(:hostname)]["location"]
|
81
|
+
else
|
82
|
+
location = nil
|
83
|
+
end
|
84
|
+
hostsmap = generate_hosts_map(directory_entries, location)
|
85
|
+
hostsmap.keys().sort().each{
|
86
|
+
|h|
|
87
|
+
TU.output("#{hostsmap[h]}\t#{h}")
|
88
|
+
}
|
89
|
+
when "hosts_puppet_manifest"
|
90
|
+
if directory_entries.has_key?(opt(:hostname))
|
91
|
+
location = directory_entries[opt(:hostname)]["location"]
|
92
|
+
else
|
93
|
+
location = nil
|
94
|
+
end
|
95
|
+
hostsmap = generate_hosts_map(directory_entries, location)
|
96
|
+
hostsmap.keys().sort().each{
|
97
|
+
|h|
|
98
|
+
TU.output("host { '#{h}' : ip => '#{hostsmap[h]}', comment => 'Created by #{script_name()}'}")
|
99
|
+
}
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def collect_directory_entries
|
104
|
+
found_files = false
|
105
|
+
directory_entries = {}
|
106
|
+
|
107
|
+
Dir.glob(opt(:config)).each{
|
108
|
+
|f|
|
109
|
+
found_files = true
|
110
|
+
|
111
|
+
# Parse the configuration file and remove any sections
|
112
|
+
# that may hold command line options
|
113
|
+
contents = TU.parse_ini_file(f)
|
114
|
+
contents.delete("tungsten_directory")
|
115
|
+
contents.delete("directory")
|
116
|
+
|
117
|
+
# Iterate through each section and merge directory entries
|
118
|
+
contents.each{
|
119
|
+
|k,v|
|
120
|
+
|
121
|
+
matches = k.match("autodetect.(.*)")
|
122
|
+
if matches != nil and matches.size() > 0
|
123
|
+
# Search for a matching autodetect provider
|
124
|
+
provider = TungstenDirectoryProvider.get_provider(matches[1])
|
125
|
+
unless provider == nil
|
126
|
+
directory_entries.merge!(provider.get_entries(v))
|
127
|
+
else
|
128
|
+
TU.error("Unable to autodetect #{matches[1]} entries")
|
129
|
+
end
|
130
|
+
else
|
131
|
+
entry = parse_directory_entry(v)
|
132
|
+
hostname = k
|
133
|
+
if entry.has_key?("hostname")
|
134
|
+
hostname = entry["hostname"]
|
135
|
+
else
|
136
|
+
entry["hostname"] = hostname
|
137
|
+
end
|
138
|
+
|
139
|
+
# Build a manual entry and add it to the list
|
140
|
+
directory_entries[k] = entry
|
141
|
+
end
|
142
|
+
}
|
143
|
+
}
|
144
|
+
|
145
|
+
if found_files == false
|
146
|
+
raise "Unable to find any files at #{opt(:config)}"
|
147
|
+
end
|
148
|
+
|
149
|
+
# Modify each directory entry and prepare it for output
|
150
|
+
directory_entries.each{
|
151
|
+
|id,entry|
|
152
|
+
unless entry["tags"].is_a?(Hash)
|
153
|
+
next
|
154
|
+
end
|
155
|
+
|
156
|
+
unless entry["hostname"] != ""
|
157
|
+
TU.error("Entry '#{entry["id"]}' does not include a hostname")
|
158
|
+
end
|
159
|
+
|
160
|
+
unless entry["location"] != ""
|
161
|
+
TU.error("Entry '#{entry["id"]}' does not include a location")
|
162
|
+
end
|
163
|
+
|
164
|
+
entry["id"] = id
|
165
|
+
entry["tags"].each{
|
166
|
+
|k,v|
|
167
|
+
v = v.split(",")
|
168
|
+
if v.size() > 1
|
169
|
+
entry["tags"][k] = v
|
170
|
+
end
|
171
|
+
}
|
172
|
+
}
|
173
|
+
|
174
|
+
if has_filters?()
|
175
|
+
directory_entries = apply_filters(directory_entries, opt(:filters))
|
176
|
+
end
|
177
|
+
|
178
|
+
return directory_entries
|
179
|
+
end
|
180
|
+
|
181
|
+
def parse_directory_entry(e)
|
182
|
+
entry = e.dup()
|
183
|
+
entry["tags"] = {}
|
184
|
+
entry["provider"] = "ini"
|
185
|
+
|
186
|
+
e.keys().each{
|
187
|
+
|k|
|
188
|
+
parts = k.split(".")
|
189
|
+
if parts.size() == 1
|
190
|
+
next
|
191
|
+
end
|
192
|
+
|
193
|
+
type = parts.shift()
|
194
|
+
remainder = parts.join(".")
|
195
|
+
|
196
|
+
case type
|
197
|
+
when "tags"
|
198
|
+
entry["tags"][remainder] = entry[k]
|
199
|
+
entry.delete(k)
|
200
|
+
end
|
201
|
+
}
|
202
|
+
|
203
|
+
return entry
|
204
|
+
end
|
205
|
+
|
206
|
+
# For each entry include the private address if the host location
|
207
|
+
# matches the given location. Use the public address if there is no private
|
208
|
+
# address or the locations do not match.
|
209
|
+
def generate_hosts_map(directory_entries, location = nil)
|
210
|
+
hosts_map = {}
|
211
|
+
|
212
|
+
directory_entries.each{
|
213
|
+
|hostname,entry|
|
214
|
+
if location != nil && entry["location"] == location
|
215
|
+
if entry.has_key?("private-address")
|
216
|
+
hosts_map[hostname] = entry["private-address"]
|
217
|
+
elsif entry.has_key?("public-address")
|
218
|
+
hosts_map[hostname] = entry["public-address"]
|
219
|
+
else
|
220
|
+
TU.error("Unable to find a private or public address for #{hostname}")
|
221
|
+
end
|
222
|
+
else
|
223
|
+
if entry.has_key?("public-address")
|
224
|
+
hosts_map[hostname] = entry["public-address"]
|
225
|
+
else
|
226
|
+
TU.error("Unable to find a public address for #{hostname}")
|
227
|
+
end
|
228
|
+
end
|
229
|
+
}
|
230
|
+
|
231
|
+
return hosts_map
|
232
|
+
end
|
233
|
+
|
234
|
+
def has_filters?
|
235
|
+
filters = opt(:filters)
|
236
|
+
|
237
|
+
if filters == nil
|
238
|
+
return false
|
239
|
+
end
|
240
|
+
|
241
|
+
if filters.is_a?(Array) && filters.count() > 0
|
242
|
+
return true
|
243
|
+
else
|
244
|
+
return false
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
# Remove any entry that does not match the provided filters
|
249
|
+
def apply_filters(entries, filters)
|
250
|
+
filters.each{
|
251
|
+
|filter|
|
252
|
+
parts = filter.split("=")
|
253
|
+
|
254
|
+
# Determine if the filter is joined with a '=' or '!='
|
255
|
+
last_char=parts[0][-1,1]
|
256
|
+
if last_char == "!"
|
257
|
+
test_equals = false
|
258
|
+
key = parts[0][0, parts[0].length()-1]
|
259
|
+
match = parts[1]
|
260
|
+
else
|
261
|
+
test_equals = true
|
262
|
+
key = parts[0]
|
263
|
+
match = parts[1]
|
264
|
+
end
|
265
|
+
|
266
|
+
entries.each{
|
267
|
+
|e, entry|
|
268
|
+
# Find the key value in entry, or nil if it doesn't exist
|
269
|
+
value = find_entry_setting(entry, key)
|
270
|
+
|
271
|
+
# Calculate if the returned value matches the filter value
|
272
|
+
if value.is_a?(Array)
|
273
|
+
is_equal = false
|
274
|
+
value.each{
|
275
|
+
|v|
|
276
|
+
if is_value_match?(v, match)
|
277
|
+
is_equal = true
|
278
|
+
end
|
279
|
+
}
|
280
|
+
else
|
281
|
+
is_equal = is_value_match?(value, match)
|
282
|
+
end
|
283
|
+
|
284
|
+
# Delete the entry if the result of the match check isn't what
|
285
|
+
# the filter is looking for
|
286
|
+
if is_equal != test_equals
|
287
|
+
entries.delete(e)
|
288
|
+
end
|
289
|
+
}
|
290
|
+
}
|
291
|
+
|
292
|
+
return entries
|
293
|
+
end
|
294
|
+
|
295
|
+
def is_value_match?(value, match)
|
296
|
+
match = match.sub("%", ".*")
|
297
|
+
matches = value.to_s().match("^#{match}$")
|
298
|
+
if matches == nil
|
299
|
+
return false
|
300
|
+
else
|
301
|
+
return true
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
def find_entry_setting(entry, key)
|
306
|
+
attrs = key.split(".")
|
307
|
+
attr_count = attrs.size
|
308
|
+
current_val = entry
|
309
|
+
for i in 0..(attr_count-1)
|
310
|
+
attr_name = attrs[i]
|
311
|
+
return current_val[attr_name] if i == (attr_count-1)
|
312
|
+
return nil if current_val[attr_name].nil?
|
313
|
+
current_val = current_val[attr_name]
|
314
|
+
end
|
315
|
+
|
316
|
+
return nil
|
317
|
+
end
|
318
|
+
|
319
|
+
def configure
|
320
|
+
super()
|
321
|
+
|
322
|
+
require_installed_directory?(false)
|
323
|
+
|
324
|
+
add_option(:config, {
|
325
|
+
:on => "--config String",
|
326
|
+
:help => "Path to INI file that holds directory information",
|
327
|
+
:default => "/etc/tungsten/directory.ini"
|
328
|
+
})
|
329
|
+
|
330
|
+
add_option(:hostname, {
|
331
|
+
:on => "--hostname String",
|
332
|
+
:help => "Use this hostname for calculating hosts entries",
|
333
|
+
:default => TU.hostname()
|
334
|
+
})
|
335
|
+
|
336
|
+
add_option(:filters, {
|
337
|
+
:on => "--filter String"
|
338
|
+
}) {|val|
|
339
|
+
unless @options.has_key?(:filters)
|
340
|
+
@options[:filters] = []
|
341
|
+
end
|
342
|
+
|
343
|
+
parts = val.split("=")
|
344
|
+
if parts.count() != 2
|
345
|
+
TU.error("Unable to parse --filter=#{val}. The filter should be in the form of 'key=value' or 'key!=value'.")
|
346
|
+
end
|
347
|
+
|
348
|
+
@options[:filters] << val
|
349
|
+
nil
|
350
|
+
}
|
351
|
+
|
352
|
+
add_command(:list, {
|
353
|
+
:help => "Output the directory information as JSON",
|
354
|
+
:default => true
|
355
|
+
})
|
356
|
+
|
357
|
+
add_command(:hosts, {
|
358
|
+
:help => "Output /etc/hosts entries for the directory hosts"
|
359
|
+
})
|
360
|
+
|
361
|
+
add_command(:hosts_puppet_manifest, {
|
362
|
+
:help => "Output a Puppet manifest for the directory hosts"
|
363
|
+
})
|
364
|
+
end
|
365
|
+
|
366
|
+
def validate
|
367
|
+
super()
|
368
|
+
|
369
|
+
unless TU.is_valid?()
|
370
|
+
return TU.is_valid?()
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
def script_name
|
375
|
+
"tungsten_directory"
|
376
|
+
end
|
377
|
+
|
378
|
+
self.new().run()
|
379
|
+
end
|