a4tools 1.2.7
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 +7 -0
- data/.bundle/install.log +38 -0
- data/.gitignore +2 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +38 -0
- data/a4tools.gemspec +38 -0
- data/bin/deploy_latest_clients +32 -0
- data/bin/devsite_config_server +48 -0
- data/bin/netshell +23 -0
- data/bin/update_server +101 -0
- data/bin/usher +54 -0
- data/lib/a4tools.rb +61 -0
- data/lib/a4tools/version.rb +3 -0
- data/lib/acres_client.rb +376 -0
- data/lib/clients/caching_client.rb +151 -0
- data/lib/clients/deployment_client.rb +53 -0
- data/lib/clients/kai_config_client.rb +39 -0
- data/lib/clients/usher_client.rb +72 -0
- data/lib/clients/usher_mgmt_client.rb +201 -0
- data/lib/event_manager.rb +24 -0
- data/lib/events.json +1 -0
- data/lib/net_shell/builtin_command.rb +312 -0
- data/lib/net_shell/builtin_commands/build.rb +251 -0
- data/lib/net_shell/builtin_commands/cd.rb +12 -0
- data/lib/net_shell/builtin_commands/connect.rb +122 -0
- data/lib/net_shell/builtin_commands/deploy.rb +280 -0
- data/lib/net_shell/builtin_commands/disconnect.rb +15 -0
- data/lib/net_shell/builtin_commands/excerpt.rb +97 -0
- data/lib/net_shell/builtin_commands/exit.rb +7 -0
- data/lib/net_shell/builtin_commands/get.rb +38 -0
- data/lib/net_shell/builtin_commands/help.rb +40 -0
- data/lib/net_shell/builtin_commands/host.rb +126 -0
- data/lib/net_shell/builtin_commands/inject.rb +42 -0
- data/lib/net_shell/builtin_commands/jsoncache.rb +80 -0
- data/lib/net_shell/builtin_commands/kai_event.rb +151 -0
- data/lib/net_shell/builtin_commands/persist.rb +24 -0
- data/lib/net_shell/builtin_commands/pwd.rb +6 -0
- data/lib/net_shell/builtin_commands/recap.rb +188 -0
- data/lib/net_shell/builtin_commands/references.rb +63 -0
- data/lib/net_shell/builtin_commands/select.rb +36 -0
- data/lib/net_shell/builtin_commands/send.rb +74 -0
- data/lib/net_shell/builtin_commands/set.rb +29 -0
- data/lib/net_shell/builtin_commands/show.rb +183 -0
- data/lib/net_shell/builtin_commands/site.rb +122 -0
- data/lib/net_shell/builtin_commands/ssh.rb +62 -0
- data/lib/net_shell/builtin_commands/talk.rb +90 -0
- data/lib/net_shell/builtin_commands/translate.rb +45 -0
- data/lib/net_shell/builtin_commands/unset.rb +14 -0
- data/lib/net_shell/builtin_commands/usher.rb +55 -0
- data/lib/net_shell/builtin_commands/usher_device.rb +39 -0
- data/lib/net_shell/builtin_commands/usher_site.rb +245 -0
- data/lib/net_shell/builtin_commands/usherm_connect.rb +21 -0
- data/lib/net_shell/colors.rb +149 -0
- data/lib/net_shell/command.rb +97 -0
- data/lib/net_shell/io.rb +132 -0
- data/lib/net_shell/net_shell.rb +396 -0
- data/lib/net_shell/prompt.rb +335 -0
- data/lib/object_builder/definitions/app_info_for_script.rb +83 -0
- data/lib/object_builder/definitions/connection_request.rb +28 -0
- data/lib/object_builder/definitions/device_info_for_system.rb +37 -0
- data/lib/object_builder/object_builder.rb +145 -0
- data/lib/talk.json +1 -0
- data/lib/talk_consumer.rb +235 -0
- metadata +279 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
category "Protocol manipulation"
|
2
|
+
description "Disconnect from remote server"
|
3
|
+
help <<-EOS
|
4
|
+
Immediately disconnects from the remote server, closing open websockets if appropriate.
|
5
|
+
EOS
|
6
|
+
|
7
|
+
validate do
|
8
|
+
return "must connect first" if client.nil?
|
9
|
+
end
|
10
|
+
|
11
|
+
run do
|
12
|
+
client.disconnect
|
13
|
+
""
|
14
|
+
end
|
15
|
+
|
@@ -0,0 +1,97 @@
|
|
1
|
+
category "Protocol manipulation"
|
2
|
+
description "Access an individual field in a JSON object"
|
3
|
+
usage "field_path"
|
4
|
+
|
5
|
+
help "Finds a field path inside a JSON object supplied over standard input. For example, use 'tok.rand' to find the 'rand' field inside the 'tok' object inside the object."
|
6
|
+
|
7
|
+
validate { args.length <= 2 }
|
8
|
+
|
9
|
+
tab :type do
|
10
|
+
talk.definition[:class].map { |defn| talk.truncated_name(defn[:name]) }
|
11
|
+
end
|
12
|
+
|
13
|
+
tab :class do
|
14
|
+
talk.definition[:class].map { |defn| talk.truncated_name(defn[:name]) }
|
15
|
+
end
|
16
|
+
|
17
|
+
opt :class, "Excerpt the first field of the given class name", :type => :string
|
18
|
+
opt :no_hint, "Do not force result object to contain an __class field"
|
19
|
+
opt :type, "Assume the object has the specified type", :type => :string
|
20
|
+
opt :no_bypass, "Do not automatically bypass JSONRPCRequest, JSONRPCResponse and NamedObjectWrapper toplevels"
|
21
|
+
|
22
|
+
run do
|
23
|
+
object, type = toplevel_value
|
24
|
+
return show_error("Invalid JSON") if object.nil?
|
25
|
+
|
26
|
+
data, type = talk.locate_data(object, args[1], params[:type])
|
27
|
+
return show_error("Unable to locate field in JSON.") if data.nil?
|
28
|
+
|
29
|
+
result = if data.is_a? Hash or data.is_a? Array then
|
30
|
+
unless params[:class].nil?
|
31
|
+
data = find_class(params[:class], data, type)
|
32
|
+
return show_error("Unable to locate class type in JSON") if data.nil?
|
33
|
+
type = params[:class]
|
34
|
+
end
|
35
|
+
data[:__class] = talk.expand_name(type) if data.is_a? Hash and not params[:no_hint]
|
36
|
+
JSON.generate(data)
|
37
|
+
else
|
38
|
+
data
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
###
|
43
|
+
|
44
|
+
def find_class(target, data, type=nil)
|
45
|
+
return find_class_in_array(target, data, type) if data.is_a? Array
|
46
|
+
|
47
|
+
type ||= talk.guess_class(data)
|
48
|
+
cls = talk.class_named(type) rescue nil
|
49
|
+
|
50
|
+
if cls.nil? then
|
51
|
+
data.each do |key, value|
|
52
|
+
searchval = find_class(target, value)
|
53
|
+
return searchval unless searchval.nil?
|
54
|
+
end
|
55
|
+
else
|
56
|
+
cls[:field].each do |field|
|
57
|
+
value = data[field[:name].to_sym]
|
58
|
+
fieldtype = talk.expand_name(field[:type].first)
|
59
|
+
next if value.nil? or fieldtype.nil?
|
60
|
+
return value if talk.name_matches?(fieldtype, target)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
nil
|
65
|
+
end
|
66
|
+
|
67
|
+
def find_class_in_array(target, data, type)
|
68
|
+
data.each do |datum|
|
69
|
+
result = find_class(target, datum, type)
|
70
|
+
return result unless result.nil?
|
71
|
+
end
|
72
|
+
|
73
|
+
return nil
|
74
|
+
end
|
75
|
+
|
76
|
+
def toplevel_value
|
77
|
+
json = @input.read_all
|
78
|
+
object = symbolify(JSON.parse(json)) rescue nil
|
79
|
+
type = (talk.expand_name(params[:type]) rescue nil) || talk.guess_class(object) rescue nil
|
80
|
+
|
81
|
+
return nil if type.nil? or object.nil?
|
82
|
+
return [object, type] if params[:no_bypass]
|
83
|
+
return bypass(object, type)
|
84
|
+
end
|
85
|
+
|
86
|
+
def bypass(object, type)
|
87
|
+
case type
|
88
|
+
when "com.acres4.common.info.NamedObjectWrapper"
|
89
|
+
return bypass(object[:body], object[:className])
|
90
|
+
when "com.acres4.common.info.JSONRPCRequest"
|
91
|
+
return bypass(object[:params], talk.guess_class(object[:params]))
|
92
|
+
when "com.acres4.common.info.JSONRPCResponse"
|
93
|
+
return bypass(object[:result], talk.guess_class(object[:result]))
|
94
|
+
else
|
95
|
+
return [object, type]
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
category "Shell management"
|
2
|
+
description "Get contents of environment variables"
|
3
|
+
usage "[variable_name]"
|
4
|
+
help <<-EOS
|
5
|
+
List the value of environment variable ENV, or all environment variables if not specified.
|
6
|
+
|
7
|
+
Environment variables are NOT imported from your system's native shell.
|
8
|
+
EOS
|
9
|
+
|
10
|
+
validate do
|
11
|
+
case args.length
|
12
|
+
when 1
|
13
|
+
true
|
14
|
+
when 2
|
15
|
+
if @shell.get_env(args[1]).nil?
|
16
|
+
"#{args[1]}: key not set"
|
17
|
+
else
|
18
|
+
true
|
19
|
+
end
|
20
|
+
else
|
21
|
+
false
|
22
|
+
end
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
tab 0 do
|
27
|
+
@shell.env.keys
|
28
|
+
end
|
29
|
+
|
30
|
+
run do
|
31
|
+
if args.length == 2 then
|
32
|
+
@shell.get_env(args[1])
|
33
|
+
else
|
34
|
+
list = []
|
35
|
+
@shell.env.each { |key, value| list.push "#{key.to_s.style(:environment)}: \"#{value.to_s.bold}\"" }
|
36
|
+
list.join("\n")
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
category "Shell management"
|
2
|
+
description "Show help for a command"
|
3
|
+
|
4
|
+
tab 0 do
|
5
|
+
@shell.built_ins
|
6
|
+
end
|
7
|
+
|
8
|
+
help <<-EOS
|
9
|
+
Show help for a specific built-in command, or outline all built-in commands if none is available.
|
10
|
+
EOS
|
11
|
+
|
12
|
+
run { args.length == 1 ? list_all_commands : list_command(args[1]) }
|
13
|
+
|
14
|
+
###
|
15
|
+
|
16
|
+
def list_all_commands
|
17
|
+
(categories.map { |cat| list_category(cat) }).join("\n\n")
|
18
|
+
end
|
19
|
+
|
20
|
+
def list_command(name)
|
21
|
+
return show_error("#{name}: command not found") unless @shell.has_built_in?(name)
|
22
|
+
cmd = @shell.built_in(name).new(@shell)
|
23
|
+
cmd.educate
|
24
|
+
end
|
25
|
+
|
26
|
+
def categories
|
27
|
+
(@shell.built_ins.map { |name| @shell.built_in(name).category_text }).sort.uniq
|
28
|
+
end
|
29
|
+
|
30
|
+
def list_category(category)
|
31
|
+
commands = @shell.built_ins.select { |name| @shell.built_in(name).category_text == category }
|
32
|
+
cat = category.style(:category)
|
33
|
+
cmds = (commands.sort.map do |name|
|
34
|
+
cmd = @shell.built_in(name).new(@shell)
|
35
|
+
usermark = cmd.user_defined? ? "@".style(:userdefined) : " "
|
36
|
+
"#{sprintf("%25s", name.to_s).style(:command)}#{usermark} -- #{cmd.description}"
|
37
|
+
end).join("\n")
|
38
|
+
|
39
|
+
[cat, cmds].join("\n")
|
40
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
category "Usher"
|
2
|
+
description "Show information about Usher hosts"
|
3
|
+
usage "hostname"
|
4
|
+
help <<-EOS
|
5
|
+
Shows information for a given usher host. If no usher host is specified, lists all hosts.
|
6
|
+
EOS
|
7
|
+
|
8
|
+
validate do
|
9
|
+
return show_error("must connect usherm first") if usherm.nil?
|
10
|
+
args.length < 3
|
11
|
+
end
|
12
|
+
|
13
|
+
tab 0 do
|
14
|
+
(usherm[:usherSystemId][:systemHosts].map { |host| host[:hostName] }) rescue []
|
15
|
+
end
|
16
|
+
|
17
|
+
run do
|
18
|
+
usherm.ensure_fresh
|
19
|
+
if args.length == 1 then
|
20
|
+
(usherm[:usherSystemId][:systemHosts].map do |host|
|
21
|
+
concise_host(host)
|
22
|
+
end).join("\n")
|
23
|
+
elsif args.length == 2 then
|
24
|
+
host = usherm.host_named(args[1])
|
25
|
+
return show_error("#{args[1]}: unknown host") if host.nil?
|
26
|
+
verbose_host(host)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
###
|
31
|
+
|
32
|
+
def string_for_range(start, last, params={})
|
33
|
+
if start == last then
|
34
|
+
last
|
35
|
+
else
|
36
|
+
"#{start}-#{last}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def collapse_ranges(elements)
|
41
|
+
return "None" if elements.nil? or elements.empty?
|
42
|
+
elements = (elements.map { |element| element.to_i }).sort
|
43
|
+
|
44
|
+
ranges = []
|
45
|
+
start = elements.first
|
46
|
+
last = nil
|
47
|
+
|
48
|
+
elements.each do |element|
|
49
|
+
if not(last.nil?) and element != last + 1
|
50
|
+
ranges.push(string_for_range(start, last))
|
51
|
+
start = element
|
52
|
+
end
|
53
|
+
last = element
|
54
|
+
end
|
55
|
+
|
56
|
+
ranges.push(string_for_range(start, last))
|
57
|
+
ranges.join(", ")
|
58
|
+
end
|
59
|
+
|
60
|
+
def provider_line(id_provider)
|
61
|
+
provider = usherm.provider(id_provider)
|
62
|
+
return "Non-existent provider #{id_provider}" if provider.nil?
|
63
|
+
return nil if provider[:isSpecial]
|
64
|
+
|
65
|
+
sites = collapse_ranges(provider[:idSites])
|
66
|
+
|
67
|
+
ipLines = ["Internal", "External"].map do |zone|
|
68
|
+
hosts = provider["usherHosts#{zone}".to_sym] || []
|
69
|
+
zone + ": " + if hosts.empty? then
|
70
|
+
"None"
|
71
|
+
else
|
72
|
+
urls = hosts.map { |host| host[:url] }
|
73
|
+
urls.join(", ")
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
out = "\t\t#{provider[:product].style(:product)}: Site #{sites}\n"
|
78
|
+
out += (ipLines.map { |line| "\t\t\t#{line}"}).join("\n") + "\n"
|
79
|
+
out
|
80
|
+
end
|
81
|
+
|
82
|
+
def acl_line(acl)
|
83
|
+
service = usherm.service_for_id(acl[:idService])
|
84
|
+
return "Non-existent service #{acl[:idService]}" if service.nil?
|
85
|
+
|
86
|
+
proto = service[:isUdp] ? "UDP" : "TCP"
|
87
|
+
external_addr = [acl[:ip], acl[:port]].compact.join(":")
|
88
|
+
"\t\t#{service[:name].style(:service)}, #{proto} #{service[:port]} (#{external_addr} external)"
|
89
|
+
end
|
90
|
+
|
91
|
+
def verbose_host(host)
|
92
|
+
datacenter = usherm.datacenter(host[:idDataCenter])
|
93
|
+
out = "Host #{host[:hostName].style(:host)} (#{host[:idSystemHost]})\n"
|
94
|
+
out += "\tInternal #{host[:ipAddrInt].style(:ip)}\n"
|
95
|
+
out += "\tExternal #{host[:ipAddrExt].style(:ip)}\n"
|
96
|
+
if datacenter.nil?
|
97
|
+
out += "\tDatacenter: not found in usher (#{host[:idDataCenter]})\n"
|
98
|
+
else
|
99
|
+
out += "\tDatacenter: #{datacenter[:dataCenterName].style(:datacenter)} (#{host[:idDataCenter]})\n"
|
100
|
+
end
|
101
|
+
out += "\tHost environment: #{usherm.env_type(host[:systemHostEnvironment])}\n"
|
102
|
+
out += "\tUsher system type: #{usherm.system_type(host[:usherResponseType])}\n"
|
103
|
+
out += (host[:providers].map { |id_provider| provider_line(id_provider) }).compact.join("\n")
|
104
|
+
|
105
|
+
out += "\tACLs:\n"
|
106
|
+
acls = usherm.acls_for_host_id(host[:idSystemHost])
|
107
|
+
if acls.empty?
|
108
|
+
out += "\t\tNo ACLs for this host."
|
109
|
+
else
|
110
|
+
out += (acls.map { |acl| acl_line(acl) }).compact.join("\n")
|
111
|
+
end
|
112
|
+
|
113
|
+
out
|
114
|
+
end
|
115
|
+
|
116
|
+
def concise_host(host)
|
117
|
+
datacenter = usherm.datacenter(host[:idDataCenter])
|
118
|
+
dcnote = if datacenter.nil?
|
119
|
+
"unknown (#{host[:idDataCenter]})"
|
120
|
+
else
|
121
|
+
"#{datacenter[:dataCenterName].style(:datacenter)}"
|
122
|
+
end
|
123
|
+
|
124
|
+
"#{host[:hostName].style(:host)} -- #{dcnote} #{usherm.env_type(host[:systemHostEnvironment])}"
|
125
|
+
end
|
126
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
category "Protocol manipulation"
|
2
|
+
description "Inject a JSON string from the command line into another JSON object from STDIN"
|
3
|
+
usage "field_path json"
|
4
|
+
|
5
|
+
validate { args.length == 3 }
|
6
|
+
|
7
|
+
run do
|
8
|
+
path = args[1].split(".")
|
9
|
+
last = path.pop
|
10
|
+
json = @input.read_all
|
11
|
+
|
12
|
+
parent = nil
|
13
|
+
toplevel = object = symbolify(JSON.parse(json)) rescue nil
|
14
|
+
injected = JSON.parse(args[2]) rescue args[2]
|
15
|
+
|
16
|
+
return show_error("Invalid source object") if injected.nil?
|
17
|
+
return show_error("Invalid replacement object") if injected.nil?
|
18
|
+
|
19
|
+
until path.empty? do
|
20
|
+
field_name = path.first
|
21
|
+
path = path[1..-1]
|
22
|
+
object = field_value(object, field_name)
|
23
|
+
return show_error("Path not in JSON object") if object.nil?
|
24
|
+
end
|
25
|
+
|
26
|
+
return json if object.nil?
|
27
|
+
object[last.to_sym] = injected
|
28
|
+
toplevel.to_json
|
29
|
+
end
|
30
|
+
|
31
|
+
###
|
32
|
+
|
33
|
+
def field_value(object, field_name)
|
34
|
+
m = field_name.to_s.match(/^([a-zA-Z0-9_]+)\[([0-9]+)\]$/)
|
35
|
+
if m.nil? then
|
36
|
+
return object[field_name.to_sym] rescue nil
|
37
|
+
else
|
38
|
+
name = m[1]
|
39
|
+
value = object[name.to_sym][m[2].to_i] rescue nil
|
40
|
+
return value
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
category "Protocol manipulation"
|
2
|
+
description "Access a pre-cached request object"
|
3
|
+
usage "[identifier]"
|
4
|
+
help <<-EOS
|
5
|
+
Reading cache
|
6
|
+
#{command.style(:command)} builds object instances based on definitions. These definitions can either be Ruby scripts providing dynamic content, or JSON strings with static content.
|
7
|
+
|
8
|
+
The definitions included by default are located in lib/object_builder/definitions, and the filenames reflect the identifiers used by #{command.style(:command)}. Adding a file to this directory will cause it to be included automatically. Files ending in .rb will be interpreted as ruby scripts; all others will be treated as raw JSON.
|
9
|
+
|
10
|
+
Writing cache
|
11
|
+
Using the --store option #{command.style(:command)} can write objects to the cache.
|
12
|
+
EOS
|
13
|
+
|
14
|
+
validate do
|
15
|
+
return args.length <= 3 if params[:store]
|
16
|
+
return args.length == 2 if params[:persist]
|
17
|
+
args.length <= 2
|
18
|
+
end
|
19
|
+
|
20
|
+
tab 0 do
|
21
|
+
(ObjectBuilder.identifiers_like(args[1]).map { |id| id.to_s }) + ObjectBuilder.supported_classes
|
22
|
+
end
|
23
|
+
|
24
|
+
opt :store, "Store a JSON object supplied on STDIN to the specified identifier", :type => :string
|
25
|
+
opt :persist, "Write an identifier to disk"
|
26
|
+
opt :field, "Read a specific field from the JSON string", :type => :string
|
27
|
+
opt :type, "Assume the top-level datatype is of a specified type", :type => :string
|
28
|
+
|
29
|
+
run do
|
30
|
+
return store if params[:store]
|
31
|
+
return persist if params[:persist]
|
32
|
+
read
|
33
|
+
end
|
34
|
+
|
35
|
+
###
|
36
|
+
|
37
|
+
def acquire_object
|
38
|
+
obj = JSON.parse(@input.read_all) rescue nil
|
39
|
+
talk.locate_data(obj, params[:field], params[:type]) rescue nil
|
40
|
+
end
|
41
|
+
|
42
|
+
def store
|
43
|
+
description = args[1] rescue "Defined from console"
|
44
|
+
obj, type = acquire_object
|
45
|
+
return show_error("Unable to acquire field from JSON") if obj.nil?
|
46
|
+
|
47
|
+
obj[:__class] = type unless type.nil?
|
48
|
+
|
49
|
+
ObjectBuilder.load_object(obj, params[:store], description)
|
50
|
+
""
|
51
|
+
end
|
52
|
+
|
53
|
+
def persist
|
54
|
+
builder = ObjectBuilder[args[1]]
|
55
|
+
return show_error("#{args[1]}: no such identifier") if builder.nil?
|
56
|
+
File.write(File.join(@shell.shelldir(:json), args[1]), builder.value.to_json)
|
57
|
+
""
|
58
|
+
end
|
59
|
+
|
60
|
+
def read
|
61
|
+
if args.length == 1 then
|
62
|
+
builders = ObjectBuilder.builders
|
63
|
+
return show_error("no builders defined") if builders.empty?
|
64
|
+
return show_builder_list(builders)
|
65
|
+
end
|
66
|
+
|
67
|
+
builder = ObjectBuilder[args[1]]
|
68
|
+
return builder.value.to_json unless builder.nil?
|
69
|
+
|
70
|
+
builders = ObjectBuilder.builders_for_name(args[1])
|
71
|
+
return "#{args[0]}: #{args[1]}: no such identifier or class in cache" if builders.empty?
|
72
|
+
show_builder_list(builders)
|
73
|
+
end
|
74
|
+
|
75
|
+
def show_builder_list(builders)
|
76
|
+
(builders.map do |builder|
|
77
|
+
"#{builder.name.to_s.style(:class)} #{builder.identifier.to_s.green}: #{builder.description}"
|
78
|
+
end).join("\n")
|
79
|
+
end
|
80
|
+
|