pe-razor-client 0.14.0 → 0.15.2
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/NEWS.md +25 -0
- data/bin/razor +9 -4
- data/lib/razor/cli.rb +10 -0
- data/lib/razor/cli/document.rb +59 -0
- data/lib/razor/cli/format.rb +81 -20
- data/lib/razor/cli/navigate.rb +121 -27
- data/lib/razor/cli/parse.rb +83 -10
- data/lib/razor/cli/transforms.rb +42 -0
- data/lib/razor/cli/version.rb +46 -0
- data/lib/razor/cli/views.rb +25 -0
- data/lib/razor/cli/views.yaml +196 -0
- data/spec/cli/format_spec.rb +99 -0
- data/spec/cli/navigate_spec.rb +111 -2
- data/spec/cli/parse_spec.rb +20 -0
- data/spec/fixtures/vcr/Razor_CLI_Navigate/argument_formatting/should_allow_spaces.yml +966 -0
- data/spec/fixtures/vcr/Razor_CLI_Navigate/for_command_help/should_provide_command_help_for_razor_--help_command_.yml +99 -0
- data/spec/fixtures/vcr/Razor_CLI_Navigate/for_command_help/should_provide_command_help_for_razor_-h_command_.yml +99 -0
- data/spec/fixtures/vcr/Razor_CLI_Navigate/for_command_help/should_provide_command_help_for_razor_command_--help_.yml +99 -0
- data/spec/fixtures/vcr/Razor_CLI_Navigate/for_command_help/should_provide_command_help_for_razor_command_-h_.yml +99 -0
- data/spec/fixtures/vcr/Razor_CLI_Navigate/for_command_help/should_provide_command_help_for_razor_command_help_.yml +99 -0
- data/spec/fixtures/vcr/Razor_CLI_Navigate/for_command_help/should_provide_command_help_for_razor_help_command_.yml +99 -0
- data/spec/fixtures/vcr/Razor_CLI_Navigate/with_authentication/should_preserve_that_across_navigation.yml +9 -42
- data/spec/fixtures/vcr/Razor_CLI_Navigate/with_authentication/should_supply_that_to_the_API_service.yml +5 -5
- data/spec/fixtures/vcr/Razor_CLI_Navigate/with_invalid_parameter/should_fail_with_bad_JSON.yml +228 -0
- data/spec/fixtures/vcr/Razor_CLI_Navigate/with_invalid_parameter/should_fail_with_malformed_argument.yml +120 -0
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- data/spec/fixtures/vcr/Razor_CLI_Navigate/with_no_parameters/should_fail_with_bad_JSON.yml +36 -0
- data/spec/fixtures/vcr/Razor_CLI_Parse/_new/_help/should_print_a_list_of_known_endpoints.yml +5 -5
- data/spec/spec_helper.rb +12 -1
- data/spec/testing.md +16 -0
- data/spec/version_spec.rb +8 -0
- metadata +67 -60
- data/.gitignore +0 -7
- data/.yardopts +0 -2
- data/Gemfile +0 -35
- data/Gemfile.lock +0 -53
- data/Rakefile +0 -37
- data/lib/razor/cli/navigate.yaml +0 -28
- data/pe-razor-client.gemspec +0 -32
- data/spec/fixtures/vcr/Razor_CLI_Navigate/with_a_single_item_path/.yml +0 -69
- data/spec/fixtures/vcr/Razor_CLI_Navigate/with_an_invalid_path/.yml +0 -36
- data/spec/fixtures/vcr/Razor_CLI_Navigate/with_no_path/.yml +0 -36
- data/spec/fixtures/vcr/Razor_CLI_Parse/_new/_help/.yml +0 -36
data/lib/razor/cli/parse.rb
CHANGED
@@ -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 <<
|
42
|
-
|
43
|
-
|
44
|
-
|
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 <<
|
47
|
-
|
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
|
-
|
66
|
-
|
67
|
-
|
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:
|