razor-client 0.15.0 → 0.15.1

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.
data/NEWS.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Razor Client Release Notes
2
2
 
3
+ ## 0.15.1 - 2014-06-12
4
+
5
+ Server version compatibility
6
+
7
+ * It is highly recommended that razor-client version 0.15.x be used with
8
+ razor-server version 0.15.x or higher.
9
+
3
10
  ## 0.15.0 - 2014-05-22
4
11
 
5
12
  Usability of the client has been greatly enhanced:
@@ -19,20 +19,20 @@ module Razor::CLI
19
19
  end
20
20
 
21
21
  def format_document(doc, parse = nil)
22
- format = parse.format
23
- arguments = parse.args
22
+ format = parse && parse.format
23
+ arguments = parse && parse.args
24
24
  doc = Razor::CLI::Document.new(doc, format)
25
25
 
26
26
  return "There are no items for this query." if doc.items.empty?
27
- return format_objects(doc.items).chomp if parse.show_command_help?
27
+ return format_objects(doc.items).chomp if parse && parse.show_command_help?
28
28
 
29
29
  case (doc.format_view['+layout'] or 'list')
30
30
  when 'list'
31
- format_objects(doc.items) + String(additional_details(doc, arguments)).chomp
31
+ format_objects(doc.items) + String(additional_details(doc, parse, arguments)).chomp
32
32
  when 'table'
33
33
  case doc.items
34
34
  when Array then
35
- get_table(doc.items, doc.format_view) + String(additional_details(doc, arguments))
35
+ get_table(doc.items, doc.format_view) + String(additional_details(doc, parse, arguments))
36
36
  else doc.to_s
37
37
  end
38
38
  else
@@ -43,18 +43,27 @@ module Razor::CLI
43
43
  private
44
44
  def get_table(doc, formatting)
45
45
  # Use the formatting if it exists, otherwise build from the data.
46
- headings = (formatting['+show'] and formatting['+show'].keys or [])
47
- Terminal::Table.new do |t|
48
- t.rows = doc.map do |page|
49
- page.map do |item|
50
- headings << item[0] unless headings.include? item[0]
51
- item[1]
46
+ headings = (formatting['+show'] and formatting['+show'].keys or get_headers(doc))
47
+ Terminal::Table.new do |table|
48
+ table.rows = doc.map do |page|
49
+ headings.map do |heading|
50
+ page[heading]
52
51
  end
53
52
  end
54
- t.headings = headings
53
+ table.headings = headings
55
54
  end.to_s
56
55
  end
57
56
 
57
+ def get_headers(doc)
58
+ [].tap do |headers|
59
+ doc.map do |page|
60
+ page.map do |item|
61
+ headers << item[0] unless headers.include?(item[0])
62
+ end
63
+ end
64
+ end
65
+ end
66
+
58
67
  # We assume that all collections are homogenous
59
68
  def format_objects(objects, indent = 0)
60
69
  objects.map do |obj|
@@ -106,10 +115,12 @@ module Razor::CLI
106
115
  (PriorityKeys & keys) + (keys - PriorityKeys) - ['+spec']
107
116
  end
108
117
 
109
- def additional_details(doc, arguments)
118
+ def additional_details(doc, parse, arguments)
110
119
  objects = doc.original_items
111
- # If every element has the 'name' key, it has nested elements.
112
- if doc.is_list? and objects.all? { |it| it.is_a?(Hash) && it.has_key?('name')}
120
+ if objects.empty? or (parse and not parse.query?)
121
+ ""
122
+ elsif doc.is_list? and objects.all? { |it| it.is_a?(Hash) && it.has_key?('name')}
123
+ # If every element has the 'name' key, it has nested elements.
113
124
  "\n\nQuery an entry by including its name, e.g. `razor #{arguments.join(' ')} #{objects.first['name']}`"
114
125
  elsif objects.any?
115
126
  object = objects.first
@@ -35,11 +35,11 @@ module Razor::CLI
35
35
  end
36
36
 
37
37
  def query?
38
- collections.any? { |coll| coll["name"] == @segments.first }
38
+ @query ||= collections.any? { |coll| coll["name"] == @segments.first }
39
39
  end
40
40
 
41
41
  def command(name)
42
- commands.find { |coll| coll["name"] == name }
42
+ @command ||= commands.find { |coll| coll["name"] == name }
43
43
  end
44
44
 
45
45
  def command?
@@ -102,7 +102,7 @@ module Razor::CLI
102
102
  # `--arg=value` or `--arg value`
103
103
  arg, value = [$1, $3]
104
104
  value = @segments.shift if value.nil? && @segments[0] !~ /^--/
105
- if value =~ /\A([a-zA-Z._-]+)=(\S+)?\z/
105
+ if value =~ /\A(.+?)=(\S+)?\z/
106
106
  # `--arg name=value`
107
107
  unless body[arg].nil? or body[arg].is_a?(Hash)
108
108
  # Error: `--arg value --arg name=value`
@@ -214,11 +214,16 @@ module Razor::CLI
214
214
 
215
215
  private
216
216
  def cmd_schema(cmd_name)
217
- cmd = json_get(@cmd_url)
218
- cmd['schema'] or raise VersionCompatibilityError, 'Server must supply the expected datatypes for command arguments'
217
+ begin
218
+ json_get(@cmd_url)['schema']
219
+ rescue RestClient::ResourceNotFound => _
220
+ raise VersionCompatibilityError, 'Server must supply the expected datatypes for command arguments; use `--json` or upgrade razor-server'
221
+ end
219
222
  end
220
223
 
221
224
  def arg_type(cmd_name, arg_name)
225
+ # Short-circuit to allow this as a work-around for backwards compatibility.
226
+ return nil if arg_name == 'json'
222
227
  cmd = cmd_schema(cmd_name)
223
228
  cmd && cmd[arg_name] && cmd[arg_name]['type'] or nil
224
229
  end
@@ -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"
@@ -35,5 +35,8 @@ module Razor::CLI
35
35
  def count(arr)
36
36
  arr.size
37
37
  end
38
+ def count_hash(hash)
39
+ hash.is_a?(Hash) ? hash.keys.size : 0
40
+ end
38
41
  end
39
42
  end
@@ -18,7 +18,7 @@ module Razor
18
18
  #
19
19
  # The next line is the one that our packaging tools modify, so please make
20
20
  # sure that any change to it is discussed and agreed first.
21
- version = '0.15.0'
21
+ version = '0.15.1'
22
22
 
23
23
  if version == "DEVELOPMENT"
24
24
  root = File.expand_path("../../..", File.dirname(__FILE__))
@@ -40,6 +40,9 @@ collections:
40
40
  +format: join_names
41
41
  policy:
42
42
  +format: select_name
43
+ metadata count:
44
+ +column: metadata
45
+ +format: count_hash
43
46
  member:
44
47
  +short:
45
48
  +layout: list
@@ -49,6 +52,9 @@ collections:
49
52
  +format: mac
50
53
  state:
51
54
  last_checkin:
55
+ +format: if_present
56
+ metadata:
57
+ +format: if_present
52
58
  tags:
53
59
  +format: join_names
54
60
  tags:
@@ -174,6 +180,7 @@ collections:
174
180
  command:
175
181
  name parameter:
176
182
  +format: name
183
+ +column: params
177
184
  errors:
178
185
  +format: count
179
186
  status:
@@ -14,7 +14,7 @@ describe Razor::CLI::Format do
14
14
  include described_class
15
15
 
16
16
  def format(doc, args = {})
17
- args = {:format => 'short', :args => ['something', 'else'], :show_command_help? => false}.merge(args)
17
+ args = {:format => 'short', :args => ['something', 'else'], :query? => true, :show_command_help? => false}.merge(args)
18
18
  parse = double(args)
19
19
  format_document doc, parse
20
20
  end
@@ -60,6 +60,11 @@ describe Razor::CLI::Format do
60
60
  result = format doc
61
61
  result.should =~ /Query an entry by including its name, e.g. `razor something else entirely`\z/
62
62
  end
63
+ it "hides for commands" do
64
+ doc = {'items' => [{'name' => 'entirely'}, {'name' => 'bar'} ]}
65
+ result = format doc, query?: false
66
+ result.should_not =~ /Query an entry by including its name/
67
+ end
63
68
  end
64
69
 
65
70
  context 'empty display' do
@@ -74,4 +79,21 @@ describe Razor::CLI::Format do
74
79
  result.should == "There are no items for this query."
75
80
  end
76
81
  end
82
+
83
+ context 'tabular display' do
84
+ it "works right when columns do not match up" do
85
+ doc = {"spec"=>"http://api.puppetlabs.com/razor/v1/collections/nodes/log",
86
+ "items"=>[{'a' => 'b', 'c' => 'd'},
87
+ {'b' => 'c', 'e' => 'f'}]}
88
+ result = format doc
89
+ result.should == <<-OUTPUT.rstrip
90
+ +---+---+---+---+
91
+ | a | c | b | e |
92
+ +---+---+---+---+
93
+ | b | d | | |
94
+ | | | c | f |
95
+ +---+---+---+---+
96
+ OUTPUT
97
+ end
98
+ end
77
99
  end
@@ -1,3 +1,4 @@
1
+ # -*- encoding: utf-8 -*-
1
2
  # Needed to make the client work on Ruby 1.8.7
2
3
  unless Kernel.respond_to?(:require_relative)
3
4
  module Kernel
@@ -92,7 +93,15 @@ describe Razor::CLI::Navigate do
92
93
  nav = Razor::CLI::Parse.new(['create-broker', '--name', 'broker1', '--broker-type', 'puppet',
93
94
  '--configuration', 'server=puppet.example.org', '--configuration',
94
95
  'environment=production']).navigate
95
- nav.get_document
96
+ keys = nav.get_document['configuration'].keys
97
+ keys.should include 'server'
98
+ keys.should include 'environment'
99
+ end
100
+ it "should construct a json object with unicode", :preserve_exact_body_bytes do
101
+ doc = Razor::CLI::Parse.new(['register-node', '--installed', 'true', '--hw-info', '{"net0": "abcdef"}']).navigate.get_document
102
+ name = doc['name']
103
+ nav = Razor::CLI::Parse.new(['modify-node-metadata', '--node', name, '--update', 'keyᓱ123=valueᓱ1']).navigate
104
+ nav.get_document['metadata'].should == {'keyᓱ123' => 'valueᓱ1'}
96
105
  end
97
106
  it "should fail with mixed types (array then hash)" do
98
107
  nav = Razor::CLI::Parse.new(['create-broker', '--name', 'broker2', '--broker-type', 'puppet',
@@ -0,0 +1,412 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: http://localhost:8080/api
6
+ body:
7
+ encoding: UTF-8
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - application/json
12
+ Accept-Encoding:
13
+ - gzip, deflate
14
+ User-Agent:
15
+ - Ruby
16
+ response:
17
+ status:
18
+ code: 200
19
+ message: OK
20
+ headers:
21
+ Server:
22
+ - Apache-Coyote/1.1
23
+ X-Content-Type-Options:
24
+ - nosniff
25
+ Content-Type:
26
+ - application/json;charset=utf-8
27
+ Content-Length:
28
+ - '4980'
29
+ Date:
30
+ - Tue, 03 Jun 2014 23:18:44 GMT
31
+ body:
32
+ encoding: UTF-8
33
+ string: '{"commands":[{"name":"add-policy-tag","rel":"http://api.puppetlabs.com/razor/v1/commands/add-policy-tag","id":"http://localhost:8080/api/commands/add-policy-tag"},{"name":"create-broker","rel":"http://api.puppetlabs.com/razor/v1/commands/create-broker","id":"http://localhost:8080/api/commands/create-broker"},{"name":"create-policy","rel":"http://api.puppetlabs.com/razor/v1/commands/create-policy","id":"http://localhost:8080/api/commands/create-policy"},{"name":"create-repo","rel":"http://api.puppetlabs.com/razor/v1/commands/create-repo","id":"http://localhost:8080/api/commands/create-repo"},{"name":"create-tag","rel":"http://api.puppetlabs.com/razor/v1/commands/create-tag","id":"http://localhost:8080/api/commands/create-tag"},{"name":"create-task","rel":"http://api.puppetlabs.com/razor/v1/commands/create-task","id":"http://localhost:8080/api/commands/create-task"},{"name":"delete-broker","rel":"http://api.puppetlabs.com/razor/v1/commands/delete-broker","id":"http://localhost:8080/api/commands/delete-broker"},{"name":"delete-node","rel":"http://api.puppetlabs.com/razor/v1/commands/delete-node","id":"http://localhost:8080/api/commands/delete-node"},{"name":"delete-policy","rel":"http://api.puppetlabs.com/razor/v1/commands/delete-policy","id":"http://localhost:8080/api/commands/delete-policy"},{"name":"delete-repo","rel":"http://api.puppetlabs.com/razor/v1/commands/delete-repo","id":"http://localhost:8080/api/commands/delete-repo"},{"name":"delete-tag","rel":"http://api.puppetlabs.com/razor/v1/commands/delete-tag","id":"http://localhost:8080/api/commands/delete-tag"},{"name":"disable-policy","rel":"http://api.puppetlabs.com/razor/v1/commands/disable-policy","id":"http://localhost:8080/api/commands/disable-policy"},{"name":"enable-policy","rel":"http://api.puppetlabs.com/razor/v1/commands/enable-policy","id":"http://localhost:8080/api/commands/enable-policy"},{"name":"modify-node-metadata","rel":"http://api.puppetlabs.com/razor/v1/commands/modify-node-metadata","id":"http://localhost:8080/api/commands/modify-node-metadata"},{"name":"modify-policy-max-count","rel":"http://api.puppetlabs.com/razor/v1/commands/modify-policy-max-count","id":"http://localhost:8080/api/commands/modify-policy-max-count"},{"name":"move-policy","rel":"http://api.puppetlabs.com/razor/v1/commands/move-policy","id":"http://localhost:8080/api/commands/move-policy"},{"name":"reboot-node","rel":"http://api.puppetlabs.com/razor/v1/commands/reboot-node","id":"http://localhost:8080/api/commands/reboot-node"},{"name":"register-node","rel":"http://api.puppetlabs.com/razor/v1/commands/register-node","id":"http://localhost:8080/api/commands/register-node"},{"name":"reinstall-node","rel":"http://api.puppetlabs.com/razor/v1/commands/reinstall-node","id":"http://localhost:8080/api/commands/reinstall-node"},{"name":"remove-node-metadata","rel":"http://api.puppetlabs.com/razor/v1/commands/remove-node-metadata","id":"http://localhost:8080/api/commands/remove-node-metadata"},{"name":"remove-policy-tag","rel":"http://api.puppetlabs.com/razor/v1/commands/remove-policy-tag","id":"http://localhost:8080/api/commands/remove-policy-tag"},{"name":"set-node-desired-power-state","rel":"http://api.puppetlabs.com/razor/v1/commands/set-node-desired-power-state","id":"http://localhost:8080/api/commands/set-node-desired-power-state"},{"name":"set-node-hw-info","rel":"http://api.puppetlabs.com/razor/v1/commands/set-node-hw-info","id":"http://localhost:8080/api/commands/set-node-hw-info"},{"name":"set-node-ipmi-credentials","rel":"http://api.puppetlabs.com/razor/v1/commands/set-node-ipmi-credentials","id":"http://localhost:8080/api/commands/set-node-ipmi-credentials"},{"name":"update-node-metadata","rel":"http://api.puppetlabs.com/razor/v1/commands/update-node-metadata","id":"http://localhost:8080/api/commands/update-node-metadata"},{"name":"update-tag-rule","rel":"http://api.puppetlabs.com/razor/v1/commands/update-tag-rule","id":"http://localhost:8080/api/commands/update-tag-rule"}],"collections":[{"name":"brokers","rel":"http://api.puppetlabs.com/razor/v1/collections/brokers","id":"http://localhost:8080/api/collections/brokers"},{"name":"repos","rel":"http://api.puppetlabs.com/razor/v1/collections/repos","id":"http://localhost:8080/api/collections/repos"},{"name":"tags","rel":"http://api.puppetlabs.com/razor/v1/collections/tags","id":"http://localhost:8080/api/collections/tags"},{"name":"policies","rel":"http://api.puppetlabs.com/razor/v1/collections/policies","id":"http://localhost:8080/api/collections/policies"},{"name":"nodes","rel":"http://api.puppetlabs.com/razor/v1/collections/nodes","id":"http://localhost:8080/api/collections/nodes"},{"name":"tasks","rel":"http://api.puppetlabs.com/razor/v1/collections/tasks","id":"http://localhost:8080/api/collections/tasks"},{"name":"commands","rel":"http://api.puppetlabs.com/razor/v1/collections/commands","id":"http://localhost:8080/api/collections/commands"}],"version":{"server":"v0.15.0-3-gb0cbb3f-dirty"}}'
34
+ http_version:
35
+ recorded_at: Tue, 03 Jun 2014 23:18:44 GMT
36
+ - request:
37
+ method: get
38
+ uri: http://localhost:8080/api/commands/register-node
39
+ body:
40
+ encoding: UTF-8
41
+ string: ''
42
+ headers:
43
+ Accept:
44
+ - application/json
45
+ Accept-Encoding:
46
+ - gzip, deflate
47
+ User-Agent:
48
+ - Ruby
49
+ response:
50
+ status:
51
+ code: 200
52
+ message: OK
53
+ headers:
54
+ Server:
55
+ - Apache-Coyote/1.1
56
+ Etag:
57
+ - '"server-version-v0.15.0-3-gb0cbb3f-dirty"'
58
+ X-Content-Type-Options:
59
+ - nosniff
60
+ Content-Type:
61
+ - application/json;charset=utf-8
62
+ Content-Length:
63
+ - '2936'
64
+ Date:
65
+ - Tue, 03 Jun 2014 23:18:44 GMT
66
+ body:
67
+ encoding: UTF-8
68
+ string: '{"name":"register-node","help":{"full":"# SYNOPSIS\nRegister a node
69
+ with Razor before it is discovered\n\n# DESCRIPTION\nIn order to make brownfield
70
+ deployments of Razor easier we allow users to\nregister nodes explicitly. This
71
+ command allows you to perform the same\nregistration that would happen when
72
+ a new node checked in, ahead of time.\n\nIn order for this to be effective
73
+ the hw_info must contain enough information\nthat the node can successfully
74
+ be matched during the iPXE boot phase.\n\nIf the node matches an existing
75
+ node, in keeping with the overall policy of\ncommands declaring desired state,
76
+ the node installed field will be updated to\nmatch the value in this command.\n\nThe
77
+ final state is that a node with the supplied hardware information, and the\ndesired
78
+ installed state, will be present in the database, regardless of it\nexisting
79
+ before hand or not.\n\n# Access Control\n\nThis command''s access control
80
+ pattern: `commands:register-node`\n\nFor more detail on how the permission
81
+ strings are structured and work, you can\nsee the [Shiro Permissions documentation][shiro]. That
82
+ pattern is expanded\nand then a permission check applied to it, before the
83
+ command is authorized.\n\nThese checks only apply if security is enabled in
84
+ the Razor configuration\nfile; on this server security is currently disabled.\n\n[shiro]:
85
+ http://shiro.apache.org/permissions.html\n\n# Attributes\n\n * installed\n -
86
+ Should the node be considered ''installed'' already? Installed nodes are\n not
87
+ eligible for policy matching, and will simply boot locally.\n - This attribute
88
+ is required.\n - It must be of type boolean.\n\n * hw-info\n - The hardware
89
+ information for the node. This is used to match the node on first\n boot
90
+ with the record in the database. The order of MAC address assignment in\n this
91
+ data is not significant, as a node with reordered MAC addresses will be\n treated
92
+ as the same node.\n - This attribute is required.\n - It must be of type
93
+ object.\n - It must be between 1 and Infinity in length.\n \n # Attributes\n \n *
94
+ serial\n - The DMI serial number of the node\n - It must be of type
95
+ string.\n \n * asset\n - The DMI asset tag of the node\n -
96
+ It must be of type string.\n \n * uuid\n - The DMI UUID of the node\n -
97
+ It must be of type string.\n\n# EXAMPLES\n\n Register a machine before you
98
+ boot it, and note that it already has an OS\n installed, so should not be
99
+ subject to policy-based reinstallation:\n \n {\n \"hw_info\":
100
+ {\n \"net0\": \"78:31:c1:be:c8:00\",\n \"net1\": \"72:00:01:f2:13:f0\",\n \"net2\": \"72:00:01:f2:13:f1\",\n \"serial\":
101
+ \"xxxxxxxxxxx\",\n \"asset\": \"Asset-1234567890\",\n \"uuid\": \"Not
102
+ Settable\"\n },\n \"installed\": true\n }\n"},"schema":{"installed":{"type":"boolean"},"hw-info":{"type":"object"}}}'
103
+ http_version:
104
+ recorded_at: Tue, 03 Jun 2014 23:18:45 GMT
105
+ - request:
106
+ method: get
107
+ uri: http://localhost:8080/api/commands/register-node
108
+ body:
109
+ encoding: UTF-8
110
+ string: ''
111
+ headers:
112
+ Accept:
113
+ - application/json
114
+ Accept-Encoding:
115
+ - gzip, deflate
116
+ User-Agent:
117
+ - Ruby
118
+ response:
119
+ status:
120
+ code: 200
121
+ message: OK
122
+ headers:
123
+ Server:
124
+ - Apache-Coyote/1.1
125
+ Etag:
126
+ - '"server-version-v0.15.0-3-gb0cbb3f-dirty"'
127
+ X-Content-Type-Options:
128
+ - nosniff
129
+ Content-Type:
130
+ - application/json;charset=utf-8
131
+ Content-Length:
132
+ - '2936'
133
+ Date:
134
+ - Tue, 03 Jun 2014 23:18:44 GMT
135
+ body:
136
+ encoding: UTF-8
137
+ string: '{"name":"register-node","help":{"full":"# SYNOPSIS\nRegister a node
138
+ with Razor before it is discovered\n\n# DESCRIPTION\nIn order to make brownfield
139
+ deployments of Razor easier we allow users to\nregister nodes explicitly. This
140
+ command allows you to perform the same\nregistration that would happen when
141
+ a new node checked in, ahead of time.\n\nIn order for this to be effective
142
+ the hw_info must contain enough information\nthat the node can successfully
143
+ be matched during the iPXE boot phase.\n\nIf the node matches an existing
144
+ node, in keeping with the overall policy of\ncommands declaring desired state,
145
+ the node installed field will be updated to\nmatch the value in this command.\n\nThe
146
+ final state is that a node with the supplied hardware information, and the\ndesired
147
+ installed state, will be present in the database, regardless of it\nexisting
148
+ before hand or not.\n\n# Access Control\n\nThis command''s access control
149
+ pattern: `commands:register-node`\n\nFor more detail on how the permission
150
+ strings are structured and work, you can\nsee the [Shiro Permissions documentation][shiro]. That
151
+ pattern is expanded\nand then a permission check applied to it, before the
152
+ command is authorized.\n\nThese checks only apply if security is enabled in
153
+ the Razor configuration\nfile; on this server security is currently disabled.\n\n[shiro]:
154
+ http://shiro.apache.org/permissions.html\n\n# Attributes\n\n * installed\n -
155
+ Should the node be considered ''installed'' already? Installed nodes are\n not
156
+ eligible for policy matching, and will simply boot locally.\n - This attribute
157
+ is required.\n - It must be of type boolean.\n\n * hw-info\n - The hardware
158
+ information for the node. This is used to match the node on first\n boot
159
+ with the record in the database. The order of MAC address assignment in\n this
160
+ data is not significant, as a node with reordered MAC addresses will be\n treated
161
+ as the same node.\n - This attribute is required.\n - It must be of type
162
+ object.\n - It must be between 1 and Infinity in length.\n \n # Attributes\n \n *
163
+ serial\n - The DMI serial number of the node\n - It must be of type
164
+ string.\n \n * asset\n - The DMI asset tag of the node\n -
165
+ It must be of type string.\n \n * uuid\n - The DMI UUID of the node\n -
166
+ It must be of type string.\n\n# EXAMPLES\n\n Register a machine before you
167
+ boot it, and note that it already has an OS\n installed, so should not be
168
+ subject to policy-based reinstallation:\n \n {\n \"hw_info\":
169
+ {\n \"net0\": \"78:31:c1:be:c8:00\",\n \"net1\": \"72:00:01:f2:13:f0\",\n \"net2\": \"72:00:01:f2:13:f1\",\n \"serial\":
170
+ \"xxxxxxxxxxx\",\n \"asset\": \"Asset-1234567890\",\n \"uuid\": \"Not
171
+ Settable\"\n },\n \"installed\": true\n }\n"},"schema":{"installed":{"type":"boolean"},"hw-info":{"type":"object"}}}'
172
+ http_version:
173
+ recorded_at: Tue, 03 Jun 2014 23:18:45 GMT
174
+ - request:
175
+ method: post
176
+ uri: http://localhost:8080/api/commands/register-node
177
+ body:
178
+ encoding: UTF-8
179
+ string: '{"installed":true,"hw-info":{"net0":"abcdef"}}'
180
+ headers:
181
+ Accept:
182
+ - application/json
183
+ Accept-Encoding:
184
+ - gzip, deflate
185
+ Content-Type:
186
+ - application/json
187
+ Content-Length:
188
+ - '46'
189
+ User-Agent:
190
+ - Ruby
191
+ response:
192
+ status:
193
+ code: 202
194
+ message: Accepted
195
+ headers:
196
+ Server:
197
+ - Apache-Coyote/1.1
198
+ X-Content-Type-Options:
199
+ - nosniff
200
+ Content-Type:
201
+ - application/json;charset=utf-8
202
+ Content-Length:
203
+ - '203'
204
+ Date:
205
+ - Tue, 03 Jun 2014 23:18:44 GMT
206
+ body:
207
+ encoding: UTF-8
208
+ string: '{"spec":"http://api.puppetlabs.com/razor/v1/collections/nodes/member","id":"http://localhost:8080/api/collections/nodes/node1","name":"node1","command":"http://localhost:8080/api/collections/commands/1"}'
209
+ http_version:
210
+ recorded_at: Tue, 03 Jun 2014 23:18:45 GMT
211
+ - request:
212
+ method: get
213
+ uri: http://localhost:8080/api/collections/nodes/node1
214
+ body:
215
+ encoding: UTF-8
216
+ string: ''
217
+ headers:
218
+ Accept:
219
+ - application/json
220
+ Accept-Encoding:
221
+ - gzip, deflate
222
+ User-Agent:
223
+ - Ruby
224
+ response:
225
+ status:
226
+ code: 200
227
+ message: OK
228
+ headers:
229
+ Server:
230
+ - Apache-Coyote/1.1
231
+ X-Content-Type-Options:
232
+ - nosniff
233
+ Content-Type:
234
+ - application/json;charset=utf-8
235
+ Content-Length:
236
+ - '335'
237
+ Date:
238
+ - Tue, 03 Jun 2014 23:18:44 GMT
239
+ body:
240
+ encoding: UTF-8
241
+ string: '{"spec":"http://api.puppetlabs.com/razor/v1/collections/nodes/member","id":"http://localhost:8080/api/collections/nodes/node1","name":"node1","hw_info":{"mac":["abcdef"]},"log":{"id":"http://localhost:8080/api/collections/nodes/node1/log","name":"log"},"tags":[],"state":{"installed":"true","installed_at":"2014-06-03T18:18:45-05:00"}}'
242
+ http_version:
243
+ recorded_at: Tue, 03 Jun 2014 23:18:45 GMT
244
+ - request:
245
+ method: get
246
+ uri: http://localhost:8080/api
247
+ body:
248
+ encoding: UTF-8
249
+ string: ''
250
+ headers:
251
+ Accept:
252
+ - application/json
253
+ Accept-Encoding:
254
+ - gzip, deflate
255
+ User-Agent:
256
+ - Ruby
257
+ response:
258
+ status:
259
+ code: 200
260
+ message: OK
261
+ headers:
262
+ Server:
263
+ - Apache-Coyote/1.1
264
+ X-Content-Type-Options:
265
+ - nosniff
266
+ Content-Type:
267
+ - application/json;charset=utf-8
268
+ Content-Length:
269
+ - '4980'
270
+ Date:
271
+ - Tue, 03 Jun 2014 23:18:44 GMT
272
+ body:
273
+ encoding: UTF-8
274
+ string: '{"commands":[{"name":"add-policy-tag","rel":"http://api.puppetlabs.com/razor/v1/commands/add-policy-tag","id":"http://localhost:8080/api/commands/add-policy-tag"},{"name":"create-broker","rel":"http://api.puppetlabs.com/razor/v1/commands/create-broker","id":"http://localhost:8080/api/commands/create-broker"},{"name":"create-policy","rel":"http://api.puppetlabs.com/razor/v1/commands/create-policy","id":"http://localhost:8080/api/commands/create-policy"},{"name":"create-repo","rel":"http://api.puppetlabs.com/razor/v1/commands/create-repo","id":"http://localhost:8080/api/commands/create-repo"},{"name":"create-tag","rel":"http://api.puppetlabs.com/razor/v1/commands/create-tag","id":"http://localhost:8080/api/commands/create-tag"},{"name":"create-task","rel":"http://api.puppetlabs.com/razor/v1/commands/create-task","id":"http://localhost:8080/api/commands/create-task"},{"name":"delete-broker","rel":"http://api.puppetlabs.com/razor/v1/commands/delete-broker","id":"http://localhost:8080/api/commands/delete-broker"},{"name":"delete-node","rel":"http://api.puppetlabs.com/razor/v1/commands/delete-node","id":"http://localhost:8080/api/commands/delete-node"},{"name":"delete-policy","rel":"http://api.puppetlabs.com/razor/v1/commands/delete-policy","id":"http://localhost:8080/api/commands/delete-policy"},{"name":"delete-repo","rel":"http://api.puppetlabs.com/razor/v1/commands/delete-repo","id":"http://localhost:8080/api/commands/delete-repo"},{"name":"delete-tag","rel":"http://api.puppetlabs.com/razor/v1/commands/delete-tag","id":"http://localhost:8080/api/commands/delete-tag"},{"name":"disable-policy","rel":"http://api.puppetlabs.com/razor/v1/commands/disable-policy","id":"http://localhost:8080/api/commands/disable-policy"},{"name":"enable-policy","rel":"http://api.puppetlabs.com/razor/v1/commands/enable-policy","id":"http://localhost:8080/api/commands/enable-policy"},{"name":"modify-node-metadata","rel":"http://api.puppetlabs.com/razor/v1/commands/modify-node-metadata","id":"http://localhost:8080/api/commands/modify-node-metadata"},{"name":"modify-policy-max-count","rel":"http://api.puppetlabs.com/razor/v1/commands/modify-policy-max-count","id":"http://localhost:8080/api/commands/modify-policy-max-count"},{"name":"move-policy","rel":"http://api.puppetlabs.com/razor/v1/commands/move-policy","id":"http://localhost:8080/api/commands/move-policy"},{"name":"reboot-node","rel":"http://api.puppetlabs.com/razor/v1/commands/reboot-node","id":"http://localhost:8080/api/commands/reboot-node"},{"name":"register-node","rel":"http://api.puppetlabs.com/razor/v1/commands/register-node","id":"http://localhost:8080/api/commands/register-node"},{"name":"reinstall-node","rel":"http://api.puppetlabs.com/razor/v1/commands/reinstall-node","id":"http://localhost:8080/api/commands/reinstall-node"},{"name":"remove-node-metadata","rel":"http://api.puppetlabs.com/razor/v1/commands/remove-node-metadata","id":"http://localhost:8080/api/commands/remove-node-metadata"},{"name":"remove-policy-tag","rel":"http://api.puppetlabs.com/razor/v1/commands/remove-policy-tag","id":"http://localhost:8080/api/commands/remove-policy-tag"},{"name":"set-node-desired-power-state","rel":"http://api.puppetlabs.com/razor/v1/commands/set-node-desired-power-state","id":"http://localhost:8080/api/commands/set-node-desired-power-state"},{"name":"set-node-hw-info","rel":"http://api.puppetlabs.com/razor/v1/commands/set-node-hw-info","id":"http://localhost:8080/api/commands/set-node-hw-info"},{"name":"set-node-ipmi-credentials","rel":"http://api.puppetlabs.com/razor/v1/commands/set-node-ipmi-credentials","id":"http://localhost:8080/api/commands/set-node-ipmi-credentials"},{"name":"update-node-metadata","rel":"http://api.puppetlabs.com/razor/v1/commands/update-node-metadata","id":"http://localhost:8080/api/commands/update-node-metadata"},{"name":"update-tag-rule","rel":"http://api.puppetlabs.com/razor/v1/commands/update-tag-rule","id":"http://localhost:8080/api/commands/update-tag-rule"}],"collections":[{"name":"brokers","rel":"http://api.puppetlabs.com/razor/v1/collections/brokers","id":"http://localhost:8080/api/collections/brokers"},{"name":"repos","rel":"http://api.puppetlabs.com/razor/v1/collections/repos","id":"http://localhost:8080/api/collections/repos"},{"name":"tags","rel":"http://api.puppetlabs.com/razor/v1/collections/tags","id":"http://localhost:8080/api/collections/tags"},{"name":"policies","rel":"http://api.puppetlabs.com/razor/v1/collections/policies","id":"http://localhost:8080/api/collections/policies"},{"name":"nodes","rel":"http://api.puppetlabs.com/razor/v1/collections/nodes","id":"http://localhost:8080/api/collections/nodes"},{"name":"tasks","rel":"http://api.puppetlabs.com/razor/v1/collections/tasks","id":"http://localhost:8080/api/collections/tasks"},{"name":"commands","rel":"http://api.puppetlabs.com/razor/v1/collections/commands","id":"http://localhost:8080/api/collections/commands"}],"version":{"server":"v0.15.0-3-gb0cbb3f-dirty"}}'
275
+ http_version:
276
+ recorded_at: Tue, 03 Jun 2014 23:18:45 GMT
277
+ - request:
278
+ method: get
279
+ uri: http://localhost:8080/api/commands/modify-node-metadata
280
+ body:
281
+ encoding: UTF-8
282
+ string: ''
283
+ headers:
284
+ Accept:
285
+ - application/json
286
+ Accept-Encoding:
287
+ - gzip, deflate
288
+ User-Agent:
289
+ - Ruby
290
+ response:
291
+ status:
292
+ code: 200
293
+ message: OK
294
+ headers:
295
+ Server:
296
+ - Apache-Coyote/1.1
297
+ Etag:
298
+ - '"server-version-v0.15.0-3-gb0cbb3f-dirty"'
299
+ X-Content-Type-Options:
300
+ - nosniff
301
+ Content-Type:
302
+ - application/json;charset=utf-8
303
+ Content-Length:
304
+ - '2610'
305
+ Date:
306
+ - Tue, 03 Jun 2014 23:18:44 GMT
307
+ body:
308
+ encoding: UTF-8
309
+ string: '{"name":"modify-node-metadata","help":{"full":"# SYNOPSIS\nPerform
310
+ various editing operations on node metadata\n\n# DESCRIPTION\nNode metadata
311
+ can be added, changed, or removed with this command; it contains\na limited
312
+ editing language to make changes to the existing metadata in an\natomic fashion.\n\nIt
313
+ can also clear all metadata from a node, although that operation is\nexclusive
314
+ to all other editing operations, and cannot be performed atomically\nwith
315
+ them.\n\n# Access Control\n\nThis command''s access control pattern: `commands:modify-node-metadata:%{node}`\n\nWords
316
+ surrounded by `%{...}` are substitutions from the input data: typically\nthe
317
+ name of the object being modified, or some other critical detail, these\nallow
318
+ roles to be granted partial access to modify the system.\n\nFor more detail
319
+ on how the permission strings are structured and work, you can\nsee the [Shiro
320
+ Permissions documentation][shiro]. That pattern is expanded\nand then a permission
321
+ check applied to it, before the command is authorized.\n\nThese checks only
322
+ apply if security is enabled in the Razor configuration\nfile; on this server
323
+ security is currently disabled.\n\n[shiro]: http://shiro.apache.org/permissions.html\n\n#
324
+ Attributes\n\n * node\n - The name of the node for which to modify metadata.\n -
325
+ This attribute is required.\n - It must be of type string.\n - It must
326
+ match the name of an existing node.\n\n * update\n - The metadata to update\n -
327
+ It must be of type object.\n\n * remove\n - The metadata to remove\n -
328
+ It must be of type array.\n\n * clear\n - Remove all metadata from the node. Cannot
329
+ be used together with\n either ''update'' or ''remove''.\n - It must
330
+ be of type boolean.\n - If present, update, remove must not be present.\n\n
331
+ * no-replace\n - If true, the `update` operation will cause this command
332
+ to fail if the\n metadata key is already present on the node. No effect
333
+ on `remove` or\n clear.\n - It must be of type boolean.\n\n# EXAMPLES\n\n Editing
334
+ node metadata, by adding and removing some keys, but refusing to\n modify
335
+ an existing value already present on a node:\n \n {\n \"node\":
336
+ \"node1\",\n \"update\": {\n \"key1\": \"value1\",\n \"key2\":
337
+ \"value2\"\n }\n \"remove\": [\"key3\", \"key4\"],\n \"no-replace\":
338
+ true\n }\n \n Removing all node metadata:\n \n {\"node\": \"node1\",
339
+ \"clear\": true}\n"},"schema":{"node":{"type":"string"},"update":{"type":"object"},"remove":{"type":"array"},"clear":{"type":"boolean"},"no-replace":{"type":"boolean"}}}'
340
+ http_version:
341
+ recorded_at: Tue, 03 Jun 2014 23:18:45 GMT
342
+ - request:
343
+ method: post
344
+ uri: http://localhost:8080/api/commands/modify-node-metadata
345
+ body:
346
+ encoding: UTF-8
347
+ string: '{"node":"node1","update":{"keyᓱ123":"valueᓱ1"}}'
348
+ headers:
349
+ Accept:
350
+ - application/json
351
+ Accept-Encoding:
352
+ - gzip, deflate
353
+ Content-Type:
354
+ - application/json
355
+ Content-Length:
356
+ - '51'
357
+ User-Agent:
358
+ - Ruby
359
+ response:
360
+ status:
361
+ code: 202
362
+ message: Accepted
363
+ headers:
364
+ Server:
365
+ - Apache-Coyote/1.1
366
+ X-Content-Type-Options:
367
+ - nosniff
368
+ Content-Type:
369
+ - application/json;charset=utf-8
370
+ Content-Length:
371
+ - '203'
372
+ Date:
373
+ - Tue, 03 Jun 2014 23:18:44 GMT
374
+ body:
375
+ encoding: UTF-8
376
+ string: '{"spec":"http://api.puppetlabs.com/razor/v1/collections/nodes/member","id":"http://localhost:8080/api/collections/nodes/node1","name":"node1","command":"http://localhost:8080/api/collections/commands/2"}'
377
+ http_version:
378
+ recorded_at: Tue, 03 Jun 2014 23:18:45 GMT
379
+ - request:
380
+ method: get
381
+ uri: http://localhost:8080/api/collections/nodes/node1
382
+ body:
383
+ encoding: UTF-8
384
+ string: ''
385
+ headers:
386
+ Accept:
387
+ - application/json
388
+ Accept-Encoding:
389
+ - gzip, deflate
390
+ User-Agent:
391
+ - Ruby
392
+ response:
393
+ status:
394
+ code: 200
395
+ message: OK
396
+ headers:
397
+ Server:
398
+ - Apache-Coyote/1.1
399
+ X-Content-Type-Options:
400
+ - nosniff
401
+ Content-Type:
402
+ - application/json;charset=utf-8
403
+ Content-Length:
404
+ - '368'
405
+ Date:
406
+ - Tue, 03 Jun 2014 23:18:44 GMT
407
+ body:
408
+ encoding: UTF-8
409
+ string: '{"spec":"http://api.puppetlabs.com/razor/v1/collections/nodes/member","id":"http://localhost:8080/api/collections/nodes/node1","name":"node1","hw_info":{"mac":["abcdef"]},"log":{"id":"http://localhost:8080/api/collections/nodes/node1/log","name":"log"},"tags":[],"metadata":{"keyᓱ123":"valueᓱ1"},"state":{"installed":"true","installed_at":"2014-06-03T18:18:45-05:00"}}'
410
+ http_version:
411
+ recorded_at: Tue, 03 Jun 2014 23:18:45 GMT
412
+ recorded_with: VCR 2.5.0
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: razor-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.0
4
+ version: 0.15.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-05-28 00:00:00.000000000 Z
12
+ date: 2014-06-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: mime-types
@@ -112,6 +112,7 @@ files:
112
112
  - LICENSE
113
113
  - 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
114
114
  - spec/fixtures/vcr/Razor_CLI_Navigate/with_multiple_arguments_with_same_name/combining_as_an_object/should_construct_a_json_object.yml
115
+ - spec/fixtures/vcr/Razor_CLI_Navigate/with_multiple_arguments_with_same_name/combining_as_an_object/should_construct_a_json_object_with_unicode.yml
115
116
  - 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
116
117
  - 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
117
118
  - 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
@@ -163,6 +164,7 @@ summary: Razor is an advanced provisioning application
163
164
  test_files:
164
165
  - 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
165
166
  - spec/fixtures/vcr/Razor_CLI_Navigate/with_multiple_arguments_with_same_name/combining_as_an_object/should_construct_a_json_object.yml
167
+ - spec/fixtures/vcr/Razor_CLI_Navigate/with_multiple_arguments_with_same_name/combining_as_an_object/should_construct_a_json_object_with_unicode.yml
166
168
  - 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
167
169
  - 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
168
170
  - 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