pe-razor-client 0.14.0 → 0.15.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/NEWS.md +25 -0
  3. data/bin/razor +9 -4
  4. data/lib/razor/cli.rb +10 -0
  5. data/lib/razor/cli/document.rb +59 -0
  6. data/lib/razor/cli/format.rb +81 -20
  7. data/lib/razor/cli/navigate.rb +121 -27
  8. data/lib/razor/cli/parse.rb +83 -10
  9. data/lib/razor/cli/transforms.rb +42 -0
  10. data/lib/razor/cli/version.rb +46 -0
  11. data/lib/razor/cli/views.rb +25 -0
  12. data/lib/razor/cli/views.yaml +196 -0
  13. data/spec/cli/format_spec.rb +99 -0
  14. data/spec/cli/navigate_spec.rb +111 -2
  15. data/spec/cli/parse_spec.rb +20 -0
  16. data/spec/fixtures/vcr/Razor_CLI_Navigate/argument_formatting/should_allow_spaces.yml +966 -0
  17. data/spec/fixtures/vcr/Razor_CLI_Navigate/for_command_help/should_provide_command_help_for_razor_--help_command_.yml +99 -0
  18. data/spec/fixtures/vcr/Razor_CLI_Navigate/for_command_help/should_provide_command_help_for_razor_-h_command_.yml +99 -0
  19. data/spec/fixtures/vcr/Razor_CLI_Navigate/for_command_help/should_provide_command_help_for_razor_command_--help_.yml +99 -0
  20. data/spec/fixtures/vcr/Razor_CLI_Navigate/for_command_help/should_provide_command_help_for_razor_command_-h_.yml +99 -0
  21. data/spec/fixtures/vcr/Razor_CLI_Navigate/for_command_help/should_provide_command_help_for_razor_command_help_.yml +99 -0
  22. data/spec/fixtures/vcr/Razor_CLI_Navigate/for_command_help/should_provide_command_help_for_razor_help_command_.yml +99 -0
  23. data/spec/fixtures/vcr/Razor_CLI_Navigate/with_authentication/should_preserve_that_across_navigation.yml +9 -42
  24. data/spec/fixtures/vcr/Razor_CLI_Navigate/with_authentication/should_supply_that_to_the_API_service.yml +5 -5
  25. data/spec/fixtures/vcr/Razor_CLI_Navigate/with_invalid_parameter/should_fail_with_bad_JSON.yml +228 -0
  26. data/spec/fixtures/vcr/Razor_CLI_Navigate/with_invalid_parameter/should_fail_with_malformed_argument.yml +120 -0
  27. data/spec/fixtures/vcr/Razor_CLI_Navigate/with_multiple_arguments_with_same_name/combining_as_an_array/should_merge_an_array_into_an_existing_array.yml +2006 -0
  28. data/spec/fixtures/vcr/Razor_CLI_Navigate/with_multiple_arguments_with_same_name/combining_as_an_array/should_merge_the_arguments_as_an_array.yml +2006 -0
  29. data/spec/fixtures/vcr/Razor_CLI_Navigate/with_multiple_arguments_with_same_name/combining_as_an_array/should_merge_the_arguments_into_an_existing_array.yml +2006 -0
  30. data/spec/fixtures/vcr/Razor_CLI_Navigate/with_multiple_arguments_with_same_name/combining_as_an_object/should_construct_a_json_object.yml +234 -0
  31. data/spec/fixtures/vcr/Razor_CLI_Navigate/with_multiple_arguments_with_same_name/combining_as_an_object/should_construct_a_json_object_with_unicode.yml +412 -0
  32. data/spec/fixtures/vcr/Razor_CLI_Navigate/with_multiple_arguments_with_same_name/combining_as_an_object/should_fail_with_mixed_types_array_then_hash_.yml +228 -0
  33. data/spec/fixtures/vcr/Razor_CLI_Navigate/with_multiple_arguments_with_same_name/combining_as_an_object/should_fail_with_mixed_types_hash_then_array_.yml +164 -0
  34. data/spec/fixtures/vcr/Razor_CLI_Navigate/with_no_parameters/should_fail_with_bad_JSON.yml +36 -0
  35. data/spec/fixtures/vcr/Razor_CLI_Parse/_new/_help/should_print_a_list_of_known_endpoints.yml +5 -5
  36. data/spec/spec_helper.rb +12 -1
  37. data/spec/testing.md +16 -0
  38. data/spec/version_spec.rb +8 -0
  39. metadata +67 -60
  40. data/.gitignore +0 -7
  41. data/.yardopts +0 -2
  42. data/Gemfile +0 -35
  43. data/Gemfile.lock +0 -53
  44. data/Rakefile +0 -37
  45. data/lib/razor/cli/navigate.yaml +0 -28
  46. data/pe-razor-client.gemspec +0 -32
  47. data/spec/fixtures/vcr/Razor_CLI_Navigate/with_a_single_item_path/.yml +0 -69
  48. data/spec/fixtures/vcr/Razor_CLI_Navigate/with_an_invalid_path/.yml +0 -36
  49. data/spec/fixtures/vcr/Razor_CLI_Navigate/with_no_path/.yml +0 -36
  50. data/spec/fixtures/vcr/Razor_CLI_Parse/_new/_help/.yml +0 -36
@@ -1,11 +1,15 @@
1
1
  require 'uri'
2
2
  require 'optparse'
3
+ require 'forwardable'
3
4
 
4
5
  module Razor::CLI
5
6
 
6
7
  class Parse
8
+ extend Forwardable
7
9
  DEFAULT_RAZOR_API = "http://localhost:8080/api"
8
10
 
11
+ def_delegator 'navigate', 'query?'
12
+
9
13
  def get_optparse
10
14
  @optparse ||= OptionParser.new do |opts|
11
15
  opts.banner = "Usage: razor [FLAGS] NAVIGATION\n"
@@ -14,6 +18,14 @@ module Razor::CLI
14
18
  @dump = true
15
19
  end
16
20
 
21
+ opts.on "-f", "--full", "Show full details when viewing entities" do
22
+ @format = 'full'
23
+ end
24
+
25
+ opts.on "-s", "--short", "Show shortened details when viewing entities" do
26
+ @format = 'short'
27
+ end
28
+
17
29
  opts.on "-u", "--url URL",
18
30
  "The full Razor API URL, can also be set\n" + " "*37 +
19
31
  "with the RAZOR_API environment variable\n" + " "*37 +
@@ -21,7 +33,12 @@ module Razor::CLI
21
33
  parse_and_set_api_url(url, :opts)
22
34
  end
23
35
 
36
+ opts.on "-v", "--version", "Show the version of Razor" do
37
+ @show_version = true
38
+ end
39
+
24
40
  opts.on "-h", "--help", "Show this screen" do
41
+ # If searching for a command's help, leave the argument for navigation.
25
42
  @option_help = true
26
43
  end
27
44
 
@@ -35,41 +52,97 @@ module Razor::CLI
35
52
  end.join("\n")
36
53
  end
37
54
 
55
+ def version
56
+ <<-VERSION
57
+ Razor Server version: #{navigate.server_version}
58
+ Razor Client version: #{Razor::CLI::VERSION}
59
+ VERSION
60
+ end
61
+
38
62
  def help
39
63
  output = get_optparse.to_s
40
64
  begin
41
- output << list_things("Collections", navigate.collections)
42
- output << "\n\n Navigate to entries of a collection using COLLECTION NAME, for example,\n 'nodes node15' for the details of a node or 'nodes node15 log' to see\n the log for node15\n"
43
- output << list_things("Commands", navigate.commands)
44
- output << "\n\n Pass arguments to commands either directly by name ('--name=NAME')\n or save the JSON body for the command in a file and pass it with\n '--json FILE'. Using --json is the only way to pass arguments in\n nested structures such as the configuration for a broker.\n"
65
+ output << <<-HELP
66
+ #{list_things("Collections", navigate.collections)}
67
+
68
+ Navigate to entries of a collection using COLLECTION NAME, for example,
69
+ 'nodes node15' for the details of a node or 'nodes node15 log' to see
70
+ the log for node15
71
+ #{list_things("Commands", navigate.commands)}
72
+
73
+ Pass arguments to commands either directly by name ('--name=NAME')
74
+ or save the JSON body for the command in a file and pass it with
75
+ '--json FILE'. Using --json is the only way to pass arguments in
76
+ nested structures such as the configuration for a broker.
77
+
78
+ HELP
79
+ rescue RestClient::Unauthorized
80
+ output << <<-UNAUTH
81
+ Error: Credentials are required to connect to the server at #{@api_url}"
82
+ UNAUTH
45
83
  rescue
46
- output << "\nCould not connect to the server at #{@api_url}. More help is available after "
47
- output << "pointing\nthe client to a Razor server"
84
+ output << <<-ERR
85
+ Error: Could not connect to the server at #{@api_url}. More help is available after pointing
86
+ the client to a Razor server
87
+ ERR
48
88
  end
49
89
  output
50
90
  end
51
91
 
92
+ def show_version?
93
+ !!@show_version
94
+ end
95
+
52
96
  def show_help?
53
97
  !!@option_help
54
98
  end
55
99
 
100
+ def show_command_help?
101
+ !!@command_help
102
+ end
103
+
56
104
  def dump_response?
57
105
  !!@dump
58
106
  end
59
107
 
60
- attr_reader :api_url
108
+ attr_reader :api_url, :format, :args
61
109
 
62
110
  def initialize(args)
63
111
  parse_and_set_api_url(ENV["RAZOR_API"] || DEFAULT_RAZOR_API, :env)
64
112
  @args = args.dup
65
- rest = get_optparse.order(args)
66
- if rest.any?
67
- @navigation = rest
113
+ @format = 'short'
114
+ @args = get_optparse.order(@args)
115
+ @args = set_help_vars(@args)
116
+ if @args == ['version'] or @show_version
117
+ @show_version = true
118
+ elsif @args.any?
119
+ @navigation = @args.dup
68
120
  else
121
+ # Called with no remaining arguments to parse.
69
122
  @option_help = true
70
123
  end
71
124
  end
72
125
 
126
+ # This method sets the appropriate help flags `@command_help` and `@option_help`,
127
+ # then returns a new set of arguments.
128
+ def set_help_vars(rest)
129
+ # Find and remove 'help' variations anywhere in the command.
130
+ if rest.any? { |arg| ['-h', '--help'].include? arg } or
131
+ rest.first == 'help' or rest.drop(1).first == 'help'
132
+ rest = rest.reject { |arg| ['-h', '--help', 'help'].include? arg }
133
+ # If anything is left, assume it is a command.
134
+ if rest.any?
135
+ @command_help = true
136
+ else
137
+ @option_help = true
138
+ end
139
+ end
140
+ if @option_help && rest.any?
141
+ @command_help = true
142
+ end
143
+ rest
144
+ end
145
+
73
146
  def navigate
74
147
  @navigate ||=Navigate.new(self, @navigation)
75
148
  end
@@ -0,0 +1,42 @@
1
+ module Razor::CLI
2
+ module Transforms
3
+ module_function
4
+ def identity(any)
5
+ any
6
+ end
7
+ def if_present(obj)
8
+ obj.nil? ? "---" : obj
9
+ end
10
+ def join_names(arr)
11
+ (arr.nil? or arr.empty?) ? '(none)' : arr.map { |item| item['name'] }.join(", ")
12
+ end
13
+ def nested(nested_obj)
14
+ (nested_obj.nil? or nested_obj.empty?) ? '(none)' : nested_obj.to_s
15
+ end
16
+ def shallow_hash(hash)
17
+ (hash.nil? or hash.empty?) ? '(none)' :
18
+ hash.map {|key, val| "#{key}: #{val}"}.join(', ')
19
+ end
20
+ def select_name(item)
21
+ item and item['name'] or "---"
22
+ end
23
+ def mac(mac)
24
+ mac ? mac.gsub(/-/, ":") : "---"
25
+ end
26
+ def name(obj)
27
+ obj ? obj['name'] : "---"
28
+ end
29
+ def name_if_present(obj)
30
+ obj ? obj['name'] : "---"
31
+ end
32
+ def count_column(hash)
33
+ hash['count']
34
+ end
35
+ def count(arr)
36
+ arr.size
37
+ end
38
+ def count_hash(hash)
39
+ hash.is_a?(Hash) ? hash.keys.size : 0
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,46 @@
1
+ # -*- encoding: utf-8 -*-
2
+ module Razor
3
+ module CLI
4
+ # Define the Razor version, and stash it in a constant. When we build a
5
+ # package for shipping we burn the version directly into this file, by
6
+ # modifying the text on the fly during package building.
7
+ #
8
+ # That "burns in" the value, but if that hasn't happened we do our best to
9
+ # work out a reasonable version number: If we are running from a git
10
+ # checkout, and we have git installed, determine this with `git describe`,
11
+ #
12
+ # If we don't have git, or it fails, but have the metadata, parse out some
13
+ # useful information directly from the checkout; this isn't great, but does
14
+ # give some guidance as to where the user was working.
15
+ #
16
+ # Finally, fall back to a default version placeholder.
17
+ #
18
+ #
19
+ # The next line is the one that our packaging tools modify, so please make
20
+ # sure that any change to it is discussed and agreed first.
21
+ version = '0.15.2'
22
+
23
+ if version == "DEVELOPMENT"
24
+ root = File.expand_path("../../..", File.dirname(__FILE__))
25
+ if File.directory? File.join(root, ".git")
26
+ git_version = %x{cd '#{root}' && git describe --tags --dirty --always 2>&1}
27
+ if $?.success?
28
+ version = 'v' + git_version
29
+ else # try to read manually...
30
+ head = File.read(File.join(root, ".git", "HEAD")) rescue nil
31
+ if head and match = %r{^ref: (refs/heads/(.[^\n]+))$}.match(head.lines.first)
32
+ version = 'git-' + match[2]
33
+ if sha = File.read(File.join(root, ".git", match[1]))[0,8] rescue nil
34
+ version += '-' + sha
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ # The running version of Razor. Razor follows the tenets of [semantic
42
+ # versioning](http://semver.org), and this version number reflects the rules
43
+ # as of SemVer 2.0.0
44
+ VERSION = version.chomp
45
+ end
46
+ end
@@ -0,0 +1,25 @@
1
+ module Razor::CLI
2
+ module Views
3
+ module_function
4
+ def views
5
+ @views ||= YAML::load_file(File::join(File::dirname(__FILE__), "views.yaml"))
6
+ end
7
+
8
+ def transform(item, transform_name)
9
+ Razor::CLI::Transforms.send(transform_name || 'identity', item)
10
+ end
11
+
12
+ def find_formatting(spec, format, remaining_navigation)
13
+ remaining_navigation ||= ''
14
+ # Scope will narrow by traversing the spec.
15
+ scope = views
16
+ spec = spec ? spec.split('/').drop_while { |i| i != 'collections'} : []
17
+ spec = spec + remaining_navigation.split(' ')
18
+ while spec.any?
19
+ val = spec.shift
20
+ scope = (scope[val] or {})
21
+ end
22
+ scope["+#{format}"] or {}
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,196 @@
1
+ ---
2
+
3
+ # This file contains instructions for how the client should format various
4
+ # objects based on the object's 'spec' path. The structure uses a `+` prefix
5
+ # to denote metadata. `member` is used to describe a member of a group.
6
+ #
7
+ # Accepted metadata annotations are:
8
+ # `+short`: This section configures what the output for the object looks like in short format.
9
+ # `+show`: This section configures which attributes are shown in the output.
10
+ # `+layout`: This configures whether to use 'list' or 'table' output.
11
+ # `+column`: This changes which column is used in the field formatting.
12
+ collections:
13
+ brokers:
14
+ +short:
15
+ +layout: table
16
+ +show:
17
+ name:
18
+ broker-type:
19
+ configuration:
20
+ +format: nested
21
+ policies:
22
+ +format: count_column
23
+ member:
24
+ +short:
25
+ +layout: list
26
+ +show:
27
+ name:
28
+ broker-type:
29
+ configuration:
30
+ policies:
31
+ +format: count_column
32
+ nodes:
33
+ +short:
34
+ +layout: table
35
+ +show:
36
+ name:
37
+ dhcp_mac:
38
+ +format: mac
39
+ tags:
40
+ +format: join_names
41
+ policy:
42
+ +format: select_name
43
+ metadata count:
44
+ +column: metadata
45
+ +format: count_hash
46
+ member:
47
+ +short:
48
+ +layout: list
49
+ +show:
50
+ name:
51
+ dhcp_mac:
52
+ +format: mac
53
+ state:
54
+ last_checkin:
55
+ +format: if_present
56
+ metadata:
57
+ +format: if_present
58
+ tags:
59
+ +format: join_names
60
+ tags:
61
+ +short:
62
+ +layout: table
63
+ +show:
64
+ name:
65
+ rule:
66
+ +format: nested
67
+ nodes:
68
+ +format: count_column
69
+ policies:
70
+ +format: count_column
71
+ hw_info:
72
+ +short:
73
+ +layout: list
74
+ log:
75
+ +short:
76
+ +layout: table
77
+ # +show:
78
+ # event:
79
+ # task:
80
+ # timestamp:
81
+ policies:
82
+ +short:
83
+ +layout: table
84
+ +show:
85
+ name:
86
+ repo:
87
+ +format: name
88
+ task:
89
+ +format: name
90
+ broker:
91
+ +format: name
92
+ enabled:
93
+ max_count:
94
+ tags:
95
+ +format: join_names
96
+ nodes:
97
+ +format: count_column
98
+ member:
99
+ +short:
100
+ +show:
101
+ name:
102
+ repo:
103
+ +format: name
104
+ task:
105
+ +format: name
106
+ broker:
107
+ +format: name
108
+ enabled:
109
+ max_count:
110
+ tags:
111
+ +format: join_names
112
+ nodes:
113
+ +format: count_column
114
+ tasks:
115
+ +short:
116
+ +layout: table
117
+ +show:
118
+ name:
119
+ description:
120
+ base:
121
+ +format: name_if_present
122
+ boot_seq:
123
+ +format: shallow_hash
124
+ member:
125
+ +short:
126
+ +show:
127
+ name:
128
+ description:
129
+ os:
130
+ boot_seq:
131
+ repos:
132
+ +short:
133
+ +layout: table
134
+ +show:
135
+ name:
136
+ iso_url:
137
+ +format: if_present
138
+ url:
139
+ +format: if_present
140
+ task:
141
+ +format: name
142
+ member:
143
+ +short:
144
+ +layout: list
145
+ +show:
146
+ name:
147
+ iso_url:
148
+ +format: if_present
149
+ url:
150
+ +format: if_present
151
+ task:
152
+ +format: name
153
+ tags:
154
+ +short:
155
+ +layout: table
156
+ +show:
157
+ name:
158
+ rule:
159
+ +format: nested
160
+ nodes:
161
+ +format: count_column
162
+ policies:
163
+ +format: count_column
164
+ member:
165
+ +short:
166
+ +layout: list
167
+ +show:
168
+ name:
169
+ rule:
170
+ +format: nested
171
+ nodes:
172
+ +format: count_column
173
+ policies:
174
+ +format: count_column
175
+ commands:
176
+ +short:
177
+ +layout: table
178
+ +show:
179
+ name:
180
+ command:
181
+ name parameter:
182
+ +format: name
183
+ +column: params
184
+ errors:
185
+ +format: count
186
+ status:
187
+ member:
188
+ +short:
189
+ +show:
190
+ name:
191
+ command:
192
+ params:
193
+ errors:
194
+ +format: count
195
+ status:
196
+ submitted_at: