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.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/.bundle/install.log +38 -0
  3. data/.gitignore +2 -0
  4. data/Gemfile +3 -0
  5. data/Gemfile.lock +38 -0
  6. data/a4tools.gemspec +38 -0
  7. data/bin/deploy_latest_clients +32 -0
  8. data/bin/devsite_config_server +48 -0
  9. data/bin/netshell +23 -0
  10. data/bin/update_server +101 -0
  11. data/bin/usher +54 -0
  12. data/lib/a4tools.rb +61 -0
  13. data/lib/a4tools/version.rb +3 -0
  14. data/lib/acres_client.rb +376 -0
  15. data/lib/clients/caching_client.rb +151 -0
  16. data/lib/clients/deployment_client.rb +53 -0
  17. data/lib/clients/kai_config_client.rb +39 -0
  18. data/lib/clients/usher_client.rb +72 -0
  19. data/lib/clients/usher_mgmt_client.rb +201 -0
  20. data/lib/event_manager.rb +24 -0
  21. data/lib/events.json +1 -0
  22. data/lib/net_shell/builtin_command.rb +312 -0
  23. data/lib/net_shell/builtin_commands/build.rb +251 -0
  24. data/lib/net_shell/builtin_commands/cd.rb +12 -0
  25. data/lib/net_shell/builtin_commands/connect.rb +122 -0
  26. data/lib/net_shell/builtin_commands/deploy.rb +280 -0
  27. data/lib/net_shell/builtin_commands/disconnect.rb +15 -0
  28. data/lib/net_shell/builtin_commands/excerpt.rb +97 -0
  29. data/lib/net_shell/builtin_commands/exit.rb +7 -0
  30. data/lib/net_shell/builtin_commands/get.rb +38 -0
  31. data/lib/net_shell/builtin_commands/help.rb +40 -0
  32. data/lib/net_shell/builtin_commands/host.rb +126 -0
  33. data/lib/net_shell/builtin_commands/inject.rb +42 -0
  34. data/lib/net_shell/builtin_commands/jsoncache.rb +80 -0
  35. data/lib/net_shell/builtin_commands/kai_event.rb +151 -0
  36. data/lib/net_shell/builtin_commands/persist.rb +24 -0
  37. data/lib/net_shell/builtin_commands/pwd.rb +6 -0
  38. data/lib/net_shell/builtin_commands/recap.rb +188 -0
  39. data/lib/net_shell/builtin_commands/references.rb +63 -0
  40. data/lib/net_shell/builtin_commands/select.rb +36 -0
  41. data/lib/net_shell/builtin_commands/send.rb +74 -0
  42. data/lib/net_shell/builtin_commands/set.rb +29 -0
  43. data/lib/net_shell/builtin_commands/show.rb +183 -0
  44. data/lib/net_shell/builtin_commands/site.rb +122 -0
  45. data/lib/net_shell/builtin_commands/ssh.rb +62 -0
  46. data/lib/net_shell/builtin_commands/talk.rb +90 -0
  47. data/lib/net_shell/builtin_commands/translate.rb +45 -0
  48. data/lib/net_shell/builtin_commands/unset.rb +14 -0
  49. data/lib/net_shell/builtin_commands/usher.rb +55 -0
  50. data/lib/net_shell/builtin_commands/usher_device.rb +39 -0
  51. data/lib/net_shell/builtin_commands/usher_site.rb +245 -0
  52. data/lib/net_shell/builtin_commands/usherm_connect.rb +21 -0
  53. data/lib/net_shell/colors.rb +149 -0
  54. data/lib/net_shell/command.rb +97 -0
  55. data/lib/net_shell/io.rb +132 -0
  56. data/lib/net_shell/net_shell.rb +396 -0
  57. data/lib/net_shell/prompt.rb +335 -0
  58. data/lib/object_builder/definitions/app_info_for_script.rb +83 -0
  59. data/lib/object_builder/definitions/connection_request.rb +28 -0
  60. data/lib/object_builder/definitions/device_info_for_system.rb +37 -0
  61. data/lib/object_builder/object_builder.rb +145 -0
  62. data/lib/talk.json +1 -0
  63. data/lib/talk_consumer.rb +235 -0
  64. 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,7 @@
1
+ category "Shell management"
2
+ description "Exits netshell"
3
+
4
+ run do
5
+ status = args.length >= 2 ? args[1].to_i : 0
6
+ exit status
7
+ 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
+