continuent-tools-core 0.9.0 → 0.10.6
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.
- 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
|