kinetic-ruby 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5179b8e65cbb4885b2608d5bd9519cd220929ce9
4
- data.tar.gz: ec917651a4e0e04075687e2d407df02e60b5b446
3
+ metadata.gz: ce317494566b4a799ad6f6d0fcd85b76710236ac
4
+ data.tar.gz: 16d20839e916fe61f7d8af3efbee17ce58f24acd
5
5
  SHA512:
6
- metadata.gz: 45ec0ac9230b4c4e0778ea3b37b1bdcfa0f82bc00fad86ec0bf425b41398f8a059fb22f67c2969743ff4507c2374485c23d05113d00551fd18eeedd9e4e10c48
7
- data.tar.gz: c0fefbb104086a319b620b9a471e40190d35cd93c504fc91636239177cd34b846ac5da8326ad6d3f6dc6d61f4efd8fa606a53b02bc55acfa3fe7fd76bfb35244
6
+ metadata.gz: e328a4e1ec4b30b4f558d5d7125bee2e402a6f8db56dc371e4bb9d969370ccb8a57406c78cbe50ff7115195ef4d237c784b8d20de4606b538317415b05ab2ce4
7
+ data.tar.gz: acef68467e27a99e6e7792085abf33ca24dcd663c271561468e82de8b52560a9f264bafdcd9036db3b7b0d2fb756d27970b565e4a047e29ea8329232fb200684
data/Rakefile CHANGED
@@ -29,13 +29,19 @@ task :default => [:example]
29
29
 
30
30
  desc "Build kinetic-ruby gem"
31
31
  task :build do
32
- banner "Building kinetic-ruby gem v#{KineticRuby::VERSION}"
32
+ banner "Building kinetic-ruby gem v#{KineticRuby::VERSION} using Kinetic Protocol #{KineticRuby::KINETIC_PROTOCOL_VERSION}"
33
33
  sh "gem build kinetic-ruby.gemspec"
34
34
  puts
35
35
  end
36
36
 
37
37
  task :release => :build do
38
38
  banner "Publishing kinetic-ruby gem v#{KineticRuby::VERSION} to RubyGems"
39
+ proto_ver = KineticRuby::KINETIC_PROTOCOL_VERSION
40
+ if proto_ver !~ /v\d+\.\d+\.\d+/
41
+ raise "Can only publish gem with a release tag of Kinetic Protocol!\n" +
42
+ " reported Kinetic Protocol version: "
43
+ end
44
+ puts "Releasing gem built w/ Kinetic Protocol #{proto_ver}"
39
45
  sh "gem push kinetic-ruby-#{KineticRuby::VERSION}.gem"
40
46
  puts
41
47
  end
data/lib/kinetic-ruby.rb CHANGED
@@ -1,9 +1,17 @@
1
1
  require_relative "protobuf/kinetic.pb"
2
2
  require 'yaml'
3
+ require 'fileutils'
3
4
 
4
5
  class KineticRuby
5
6
 
6
- VERSION = "0.2.0"
7
+ VERSION = "0.2.1"
8
+
9
+ kp_tag = ''
10
+ FileUtils.cd "./vendor/kinetic-protocol" do
11
+ kp_tag = 'v' + `git describe --tags`.strip
12
+ kp_tag = "<Unknown Kinetic Protocol version!>" if kp_tag !~ /^v\d+\.\d+\.\d+/
13
+ end
14
+ KINETIC_PROTOCOL_VERSION = kp_tag
7
15
 
8
16
  LOG_LEVELS = [
9
17
  LOG_LEVEL_NONE = 0,
@@ -0,0 +1,367 @@
1
+ ## Generated from kinetic.proto for com.seagate.kinetic.proto
2
+ require "beefcake"
3
+
4
+ module Seagate
5
+ module Kinetic
6
+
7
+ class Message
8
+ include Beefcake::Message
9
+
10
+ module Synchronization
11
+ INVALID_SYNCHRONIZATION = -1
12
+ WRITETHROUGH = 1
13
+ WRITEBACK = 2
14
+ FLUSH = 3
15
+ end
16
+
17
+ module Algorithm
18
+ INVALID_ALGORITHM = -1
19
+ SHA1 = 1
20
+ SHA2 = 2
21
+ SHA3 = 3
22
+ CRC32 = 4
23
+ CRC64 = 5
24
+ end
25
+
26
+ module MessageType
27
+ INVALID_MESSAGE_TYPE = -1
28
+ GET = 2
29
+ GET_RESPONSE = 1
30
+ PUT = 4
31
+ PUT_RESPONSE = 3
32
+ DELETE = 6
33
+ DELETE_RESPONSE = 5
34
+ GETNEXT = 8
35
+ GETNEXT_RESPONSE = 7
36
+ GETPREVIOUS = 10
37
+ GETPREVIOUS_RESPONSE = 9
38
+ GETKEYRANGE = 12
39
+ GETKEYRANGE_RESPONSE = 11
40
+ GETVERSION = 16
41
+ GETVERSION_RESPONSE = 15
42
+ SETUP = 22
43
+ SETUP_RESPONSE = 21
44
+ GETLOG = 24
45
+ GETLOG_RESPONSE = 23
46
+ SECURITY = 26
47
+ SECURITY_RESPONSE = 25
48
+ PEER2PEERPUSH = 28
49
+ PEER2PEERPUSH_RESPONSE = 27
50
+ NOOP = 30
51
+ NOOP_RESPONSE = 29
52
+ FLUSHALLDATA = 32
53
+ FLUSHALLDATA_RESPONSE = 31
54
+ end
55
+
56
+ class Command
57
+ include Beefcake::Message
58
+ end
59
+
60
+ class Header
61
+ include Beefcake::Message
62
+ end
63
+
64
+ class Body
65
+ include Beefcake::Message
66
+ end
67
+
68
+ class Status
69
+ include Beefcake::Message
70
+
71
+ module StatusCode
72
+ INVALID_STATUS_CODE = -1
73
+ NOT_ATTEMPTED = 0
74
+ SUCCESS = 1
75
+ HMAC_FAILURE = 2
76
+ NOT_AUTHORIZED = 3
77
+ VERSION_FAILURE = 4
78
+ INTERNAL_ERROR = 5
79
+ HEADER_REQUIRED = 6
80
+ NOT_FOUND = 7
81
+ VERSION_MISMATCH = 8
82
+ SERVICE_BUSY = 9
83
+ EXPIRED = 10
84
+ DATA_ERROR = 11
85
+ PERM_DATA_ERROR = 12
86
+ REMOTE_CONNECTION_ERROR = 13
87
+ NO_SPACE = 14
88
+ NO_SUCH_HMAC_ALGORITHM = 15
89
+ INVALID_REQUEST = 16
90
+ NESTED_OPERATION_ERRORS = 17
91
+ end
92
+ end
93
+
94
+ class KeyValue
95
+ include Beefcake::Message
96
+ end
97
+
98
+ class Range
99
+ include Beefcake::Message
100
+ end
101
+
102
+ class Setup
103
+ include Beefcake::Message
104
+ end
105
+
106
+ class P2POperation
107
+ include Beefcake::Message
108
+
109
+ class Operation
110
+ include Beefcake::Message
111
+ end
112
+
113
+ class Peer
114
+ include Beefcake::Message
115
+ end
116
+ end
117
+
118
+ class GetLog
119
+ include Beefcake::Message
120
+
121
+ module Type
122
+ INVALID_TYPE = -1
123
+ UTILIZATIONS = 0
124
+ TEMPERATURES = 1
125
+ CAPACITIES = 2
126
+ CONFIGURATION = 3
127
+ STATISTICS = 4
128
+ MESSAGES = 5
129
+ LIMITS = 6
130
+ end
131
+
132
+ class Utilization
133
+ include Beefcake::Message
134
+ end
135
+
136
+ class Temperature
137
+ include Beefcake::Message
138
+ end
139
+
140
+ class Capacity
141
+ include Beefcake::Message
142
+ end
143
+
144
+ class Configuration
145
+ include Beefcake::Message
146
+
147
+ class Interface
148
+ include Beefcake::Message
149
+ end
150
+ end
151
+
152
+ class Statistics
153
+ include Beefcake::Message
154
+ end
155
+
156
+ class Limits
157
+ include Beefcake::Message
158
+ end
159
+ end
160
+
161
+ class Security
162
+ include Beefcake::Message
163
+
164
+ class ACL
165
+ include Beefcake::Message
166
+
167
+ module HMACAlgorithm
168
+ INVALID_HMAC_ALGORITHM = -1
169
+ HmacSHA1 = 1
170
+ end
171
+
172
+ module Permission
173
+ INVALID_PERMISSION = -1
174
+ READ = 0
175
+ WRITE = 1
176
+ DELETE = 2
177
+ RANGE = 3
178
+ SETUP = 4
179
+ P2POP = 5
180
+ GETLOG = 7
181
+ SECURITY = 8
182
+ end
183
+
184
+ class Scope
185
+ include Beefcake::Message
186
+ end
187
+ end
188
+ end
189
+ end
190
+
191
+ class Message
192
+
193
+ class Command
194
+ optional :header, Message::Header, 1
195
+ optional :body, Message::Body, 2
196
+ optional :status, Message::Status, 3
197
+ end
198
+
199
+ class Header
200
+ optional :clusterVersion, :int64, 1
201
+ optional :identity, :int64, 2
202
+ optional :connectionID, :int64, 3
203
+ optional :sequence, :int64, 4
204
+ optional :ackSequence, :int64, 6
205
+ optional :messageType, Message::MessageType, 7
206
+ optional :timeout, :int64, 9
207
+ optional :earlyExit, :bool, 10
208
+ optional :backgroundScan, :bool, 11
209
+ end
210
+
211
+ class Body
212
+ optional :keyValue, Message::KeyValue, 1
213
+ optional :range, Message::Range, 2
214
+ optional :setup, Message::Setup, 3
215
+ optional :p2pOperation, Message::P2POperation, 4
216
+ optional :getLog, Message::GetLog, 6
217
+ optional :security, Message::Security, 7
218
+ end
219
+
220
+ class Status
221
+ optional :code, Message::Status::StatusCode, 1
222
+ optional :statusMessage, :string, 2
223
+ optional :detailedMessage, :bytes, 3
224
+ end
225
+
226
+ class KeyValue
227
+ optional :newVersion, :bytes, 2
228
+ optional :force, :bool, 8
229
+ optional :key, :bytes, 3
230
+ optional :dbVersion, :bytes, 4
231
+ optional :tag, :bytes, 5
232
+ optional :algorithm, Message::Algorithm, 6
233
+ optional :metadataOnly, :bool, 7
234
+ optional :synchronization, Message::Synchronization, 9
235
+ end
236
+
237
+ class Range
238
+ optional :startKey, :bytes, 1
239
+ optional :endKey, :bytes, 2
240
+ optional :startKeyInclusive, :bool, 3
241
+ optional :endKeyInclusive, :bool, 4
242
+ optional :maxReturned, :int32, 5
243
+ optional :reverse, :bool, 6
244
+ repeated :key, :bytes, 8
245
+ end
246
+
247
+ class Setup
248
+ optional :newClusterVersion, :int64, 1
249
+ optional :instantSecureErase, :bool, 2
250
+ optional :setPin, :bytes, 3
251
+ optional :pin, :bytes, 4
252
+ optional :firmwareDownload, :bool, 5
253
+ end
254
+
255
+ class P2POperation
256
+
257
+ class Operation
258
+ optional :key, :bytes, 3
259
+ optional :version, :bytes, 4
260
+ optional :newKey, :bytes, 5
261
+ optional :force, :bool, 6
262
+ optional :status, Message::Status, 7
263
+ optional :p2pop, Message::P2POperation, 8
264
+ end
265
+
266
+ class Peer
267
+ optional :hostname, :string, 1
268
+ optional :port, :int32, 2
269
+ optional :tls, :bool, 3
270
+ end
271
+ optional :peer, Message::P2POperation::Peer, 1
272
+ repeated :operation, Message::P2POperation::Operation, 2
273
+ optional :allChildOperationsSucceeded, :bool, 3
274
+ end
275
+
276
+ class GetLog
277
+
278
+ class Utilization
279
+ optional :name, :string, 1
280
+ optional :value, :float, 2
281
+ end
282
+
283
+ class Temperature
284
+ optional :name, :string, 1
285
+ optional :current, :float, 2
286
+ optional :minimum, :float, 3
287
+ optional :maximum, :float, 4
288
+ optional :target, :float, 5
289
+ end
290
+
291
+ class Capacity
292
+ optional :nominalCapacityInBytes, :uint64, 4
293
+ optional :portionFull, :float, 5
294
+ end
295
+
296
+ class Configuration
297
+
298
+ class Interface
299
+ optional :name, :string, 1
300
+ optional :MAC, :bytes, 2
301
+ optional :ipv4Address, :bytes, 3
302
+ optional :ipv6Address, :bytes, 4
303
+ end
304
+ optional :vendor, :string, 5
305
+ optional :model, :string, 6
306
+ optional :serialNumber, :bytes, 7
307
+ optional :worldWideName, :bytes, 14
308
+ optional :version, :string, 8
309
+ optional :compilationDate, :string, 12
310
+ optional :sourceHash, :string, 13
311
+ optional :protocolVersion, :string, 15
312
+ optional :protocolCompilationDate, :string, 16
313
+ optional :protocolSourceHash, :string, 17
314
+ repeated :interface, Message::GetLog::Configuration::Interface, 9
315
+ optional :port, :int32, 10
316
+ optional :tlsPort, :int32, 11
317
+ end
318
+
319
+ class Statistics
320
+ optional :messageType, Message::MessageType, 1
321
+ optional :count, :uint64, 4
322
+ optional :bytes, :uint64, 5
323
+ end
324
+
325
+ class Limits
326
+ optional :maxKeySize, :uint32, 1
327
+ optional :maxValueSize, :uint32, 2
328
+ optional :maxVersionSize, :uint32, 3
329
+ optional :maxTagSize, :uint32, 4
330
+ optional :maxConnections, :uint32, 5
331
+ optional :maxOutstandingReadRequests, :uint32, 6
332
+ optional :maxOutstandingWriteRequests, :uint32, 7
333
+ optional :maxMessageSize, :uint32, 8
334
+ optional :maxKeyRangeCount, :uint32, 9
335
+ end
336
+ repeated :type, Message::GetLog::Type, 1
337
+ repeated :utilization, Message::GetLog::Utilization, 2
338
+ repeated :temperature, Message::GetLog::Temperature, 3
339
+ optional :capacity, Message::GetLog::Capacity, 4
340
+ optional :configuration, Message::GetLog::Configuration, 5
341
+ repeated :statistics, Message::GetLog::Statistics, 6
342
+ optional :messages, :bytes, 7
343
+ optional :limits, Message::GetLog::Limits, 8
344
+ end
345
+
346
+ class Security
347
+
348
+ class ACL
349
+
350
+ class Scope
351
+ optional :offset, :int64, 1
352
+ optional :value, :bytes, 2
353
+ repeated :permission, Message::Security::ACL::Permission, 3
354
+ optional :TlsRequired, :bool, 4
355
+ end
356
+ optional :identity, :int64, 1
357
+ optional :key, :bytes, 2
358
+ optional :hmacAlgorithm, Message::Security::ACL::HMACAlgorithm, 3
359
+ repeated :scope, Message::Security::ACL::Scope, 4
360
+ end
361
+ repeated :acl, Message::Security::ACL, 2
362
+ end
363
+ optional :command, Message::Command, 1
364
+ optional :hmac, :bytes, 3
365
+ end
366
+ end
367
+ end
@@ -0,0 +1,1560 @@
1
+ # Overview
2
+ Kinetic is a key-value storage system. A Kinetic Device (e.g. a Kinetic Drive or a traditional server running the Java Reference Implementation) stores key-value objects. Kinetic Client applications can communicate with a Kinetic Device by sending messages over a network using TCP. Each individual message is called a “Kinetic Protocol Data Unit” (Kinetic PDU) and represents an individual request or response. For example, a Kinetic Client may send a message requesting the value associated with a particular key to a Kinetic Device. The device would respond with a message containing the value.
3
+
4
+ ## Document Assumptions
5
+ This document describes the structure of Protocol Buffer messages in detail. It is important to have a familiarity with the Protocol Buffer data interchange format ([https://code.google.com/p/protobuf/](https://code.google.com/p/protobuf/)). Where data types are specified with respect to fields in `protobuf` messages, the Scalar Value Types documented here: [https://developers.google.com/protocol-buffers/docs/proto](https://developers.google.com/protocol-buffers/docs/proto) will be used.
6
+
7
+ # Kinetic Protocol Data Unit Structure
8
+ A Kinetic Protocol Data Unit is composed of a Protocol Buffer (`protobuf`) message, containing operation metadata & key-value metadata, and the value. It is important to note that the value is not encoded in the `protobuf` message; it is a separate top-level component of the Kinetic PDU.
9
+
10
+ Specifically, a Kinetic PDU is structured as follows:
11
+
12
+
13
+ | Offset | Type | Length | Description |
14
+ | ------ | ------ | ---- |----------- |
15
+ | 0 | Byte | 1 Byte | Version prefix: currently the character ‘F’, denoting the beginning of the message. (The character ‘F’, the Hex value 46). |
16
+ | 1 | 4 Byte Big Endian Integer |4 Bytes | The number of bytes in the `protobuf` message (the maximum length for `protobuf` messages is 1024*1024 bytes).|
17
+ | 5 | 4 Byte Big Endian Integer| 4 Bytes | The number of bytes in the value (the maximum length for values is 1024*1024 bytes).|
18
+ | 9 | Bytes |<= 1024*1024 Bytes | The `protobuf` message. |
19
+ | 9 + length of `protobuf` message | Bytes | <= 1024*1024 Bytes | The value. |
20
+
21
+
22
+ ### Protobuf Structure
23
+ Within a Kinetic PDU, the `protobuf` message encodes the specifics of the requested operation (or response). At a high level, each `protobuf` message contains:
24
+
25
+ - A single command
26
+ - An HMAC of the byte representation of the command
27
+
28
+ Each command contains a:
29
+
30
+ - Header, containing metadata about the message such as type (e.g. GET, GET_RESPONSE, PUT, PUT_RESPONSE, etc)
31
+ - Body, containing operation-specific information, such as key-value information for PUT or key range information for GETKEYRANGE.
32
+ - Status, containing information about whether an associated operation succeeded or failed (and why).
33
+
34
+ The message structure for each operation will be described in depth in the following sections.
35
+
36
+ # Access Control
37
+ The Kinetic Protocol supports restricting the operations a requester (identity) can perform by way of Access Control Lists (ACLs). They are structured as follows:
38
+
39
+ ```
40
+ message ACL {
41
+ // The same identity specified in the header of messages
42
+ optional int64 identity = 1;
43
+
44
+ // This is the identity's HMAC Key. This is a shared secret between the
45
+ // client and the device, used to sign requests.
46
+ optional bytes key = 2;
47
+
48
+ // This is the algorithm used for performing the HMAC for messages for
49
+ // this identity.
50
+ // The supported values are: HmacSHA1.
51
+ optional HMACAlgorithm hmacAlgorithm = 3;
52
+
53
+ // Scope is the core of an ACL, an identity can have several.
54
+ // See below.
55
+ repeated Scope scope = 4;
56
+
57
+ // Scopes grant a set of permissions to the identity associated
58
+ // with the ACL. Scopess can further restrict which situations
59
+ // those permissions apply to by using the offset, value,
60
+ // and TlsRequired fields
61
+ message Scope {
62
+ // Offset and value are optional and should be used to restrict
63
+ // which keys the Scope applies to. If offset and value are
64
+ // specified, the permission will only apply to keys that match
65
+ // the value at the given offset. This is analogous to a substring
66
+ // match in many languages, where the key in question is the target.
67
+ optional int64 offset = 1;
68
+ optional bytes value = 2;
69
+
70
+ // The Permission being granted.
71
+ // There can be many, there must be at least one.
72
+ repeated Permission permission = 3;
73
+
74
+ // Optional boolean, defaults to false.
75
+ // When set to true, this scope only applies to SSL connections.
76
+ // Even if an identity has an ACL with a scope containing a specific
77
+ // permission, if that permission belongs to a scope for which
78
+ // TlsRequired is true and the identity makes a non-ssl request,
79
+ // Kinetic will behave as if the identity does not have that
80
+ // permission.
81
+ optional bool TlsRequired = 4;
82
+ }
83
+
84
+ // These are the permissions that can be included in a scope
85
+ enum Permission {
86
+ INVALID = -1; // place holder for backward compatibility
87
+ READ = 0; // can read key/values
88
+ WRITE = 1; // can write key/values
89
+ DELETE = 2; // can delete key/values
90
+ RANGE = 3; // can do a range
91
+ SETUP = 4; // can set up a device
92
+ P2POP = 5; // can do a peer to peer operation
93
+ GETLOG = 7; // can get log
94
+ SECURITY = 8; // can set up the security permission of the device
95
+ }
96
+
97
+ // Currently only one valid HMAC algorithm is supported
98
+ enum HMACAlgorithm {
99
+ // Added to allow additional HmacAlgorithms without breaking
100
+ // backward compatibility.
101
+ Unknown = 0;
102
+ // this is the default
103
+ HmacSHA1 = 1;
104
+ }
105
+
106
+ }
107
+
108
+ ```
109
+
110
+ See the Security section below for details on setting ACLs.
111
+
112
+ ## Examples
113
+ In this section we'll give some concrete examples of how ACLs can be used.
114
+
115
+ ###Client 1
116
+
117
+ Suppose client 1 has an ACL like so:
118
+
119
+ ```
120
+ ACL {
121
+ identity: 1
122
+ key: "a3b38c37298f7f01a377518dae81dd99655b2be8129c3b2c6357b7e779064159"
123
+ HMACAlgorithm: HmacSHA1
124
+
125
+ // There can be multiple scopes, we'll show that in these examples by
126
+ // repeated scope objects like this
127
+ scope {
128
+ permission: READ
129
+ }
130
+
131
+ scope {
132
+ offset: 0
133
+ value: "foo"
134
+ permission: WRITE
135
+ }
136
+ }
137
+ ```
138
+
139
+ Client 1 would be able to `GET` any object in the store, but only `PUT` keys that start with "foo".
140
+
141
+ ###Client 2
142
+
143
+ Suppose client 2 has an ACL like so:
144
+
145
+ ```
146
+ ACL {
147
+ identity: 2
148
+ key: "13010b8d8acdbe6abc005840aad1dc5dedb4345e681ed4e3c4645d891241d6b2"
149
+ HMACAlgorithm: HmacSHA1
150
+
151
+ scope {
152
+ permission: SECURITY
153
+ TlsRequired: true
154
+ }
155
+ }
156
+ ```
157
+
158
+ Client 2 would be able to create new identities and set ACLs (using the Security operation) but only over SSL connections. Client 2 would not be able to read or write any keys on the device (though they could reset their own ACL to allow such activity).
159
+
160
+
161
+
162
+
163
+
164
+ # Operation Details
165
+
166
+ ## Overview
167
+ This section describes the `protobuf` message structure for each operation supported by the Kinetic protocol. There are many fields that may be set on all requests, to simplify this document those will be documented once in the Cross-Cutting Concerns section. Within each logical grouping of operations (read value, modify value, etc) there are additional common fields. We will begin each sub-section with a description of common fields.
168
+
169
+ ## Cross-Cutting Concerns
170
+ There are many fields in the `protobuf` message which can be specified on many operations. Instead of repeating the documentation for those fields for each call, we will show them here.
171
+
172
+ **Request Message**
173
+
174
+ ```
175
+ command {
176
+ header {
177
+ // Optional int64, default value is 0
178
+ // The version number of this cluster definition. If this is not equal to
179
+ // the value on the device, the request is rejected and will return a
180
+ // `VERSION_FAILURE` `statusCode` in the `Status` message.
181
+ clusterVersion: ...
182
+
183
+ // Required int64
184
+ // The identity associated with this request. See the ACL discussion above.
185
+ // The Kinetic Device will use this identity value to lookup the
186
+ // HMAC key (shared secret) to verify the HMAC.
187
+ identity: ...
188
+
189
+ // Required int64
190
+ // A unique number for this connection between the source and target.
191
+ // On the first request to the drive, this should be the time of day in
192
+ // seconds since 1970. The drive can change this number and the client must
193
+ // continue to use the new number and the number must remain constant
194
+ // during the session
195
+ connectionID: ...
196
+
197
+ // Required int64
198
+ // Sequence is a monotonically increasing number for each request in a TCP
199
+ // connection.
200
+ sequence: ...
201
+
202
+ // Required MessageType
203
+ // The message type identifies which sort of operation this is.
204
+ // See the MessageType enum in the protobuf definition for all potential
205
+ // values.
206
+ // Note that the *_RESPONSE message types are reserved for messages from
207
+ // the Kinetic Device to the client (i.e. responses).
208
+ messageType: ...
209
+ }
210
+ body {
211
+ // Omitted in this cross-cutting documentation section
212
+ }
213
+ }
214
+
215
+ // Required bytes
216
+ // The HMAC of this message used to verify integrity.
217
+ // The HMAC is taken of the byte-representaiton of the command message of this
218
+ // protobuf message. An identity-specific shared secret is used to compute the HMAC.
219
+ // The Kinetic Device must have the key associated with the identity in
220
+ // the header.
221
+ // For example, in pseudocode where a computeHMAC function exists which takes
222
+ // a value and an algorithm:
223
+ // hmac = computeHMAC(message.command.toBytes(), identityHMACAlgorithm)
224
+ hmac: "..."
225
+ ```
226
+
227
+ **Response Message**
228
+
229
+ ```
230
+ command {
231
+ header {
232
+ // Required int64.
233
+ // In a response message, ackSequence will be the same as the
234
+ // sequence value set in the request message.
235
+ // The client can use this to map async responses to their
236
+ // associated requests.
237
+ // This is important because operations within a connection may be reorderd.
238
+ ackSequence: ...
239
+
240
+ // In a response, messageType corresponds to the requested messageType.
241
+ // For instance, requests with a PUT messageType will receive a response
242
+ // with a PUT_REPONSE messageType.
243
+ messageType: ...
244
+ }
245
+ body {
246
+ // Omitted in this cross-cutting documentation section
247
+ }
248
+ status {
249
+ // Every response from the Kinetic Device will specify a code indicating
250
+ // whether the request was successful, or the specific error case
251
+ // encountered. The full list of codes is specified by the
252
+ // Status.StatusCode enum.
253
+ code: SUCCESS
254
+ }
255
+ }
256
+ // Required bytes
257
+ // See the description for the request above. Responses will include an HMAC
258
+ // in addition to request, using the identity-specific key.
259
+ hmac: ""
260
+
261
+ ```
262
+
263
+ ###Error Cases###
264
+ When an error occurs on the Kinetic Device, the response message includes a `status` with a `code`. These codes are enumerated in the `StatusCode` enum in the protocol definition. They will be discussed here in more detail.
265
+
266
+ * `INTERNAL_ERROR` indicates that the Kinetic Device experiences a malfunction. (Currently this code is returned in certain cases that don't indicate a drive malfunction, these will be updated.)
267
+ * `HMAC_FAILURE` indicates that the HMAC of the request is incorrect or missing. This will also be returned when an unknown identity is set in the header, since the device cannot verify an HMAC for an unknown identity.
268
+ * `NOT_AUTHORIZED` indicates the attemped operation could not be completed because the identity set in the header did not have authorization. This may mean that the identity does not have the required Permission in any Scope in the ACL, or it may indicate that the Scope containing that Permission does not apply (due to offset & index or tls rules).
269
+ * `VERSION_FAILURE` indicates that the `clusterVersion` of the Kinetic Device does not match the `clusterVersion` set in the header of the requesting message.
270
+ * `NOT_FOUND` indicates that the requested key was not found in the Kinetic Device's data store.
271
+ * `VERSION_MISMATCH` indicates that the `PUT` or `DELETE` operation failed because the `dbVersion` passed in the `KeyValue` object does not match the store's version. Pasing `force: true` in the `KeyValue` object ignores the mismatch and completes the operation.
272
+ * `NO_SPACE` indicates that the drive is full. There are background processes which may free space, so this error may occur once, and not on subsequent tries even though no data has been explicitly removed. Similarly, executing a delete may not immediately free space, so a `PUT` which fails with this error may not immediately succeed even after a `DELETE` which should free space.
273
+ * `NO_SUCH_HMAC_ALGORITHM` indicates that the `hmacAlgorithm` field in the `Security` message was invalid.
274
+ * `INVALID_REQUEST` indicates that the request is not valid. Subsequent attempts with the same request will return the same code. Examples: GET does not specify keyValue message, GETKEYRANGE operation does not specify startKey, etc.
275
+ * `NOT_ATTEMPTED` indicates that a P2P operation was received but was not even attempted due to some other error halting execution early.
276
+ * `REMOTE_CONNECTION_ERROR` indicates that a P2P operation was attempted but could not be completed.
277
+ * `NESTED_OPERATION_ERRORS` indicates that a P2P request completed but that an operation (possibly nested) failed.
278
+ * `EXPIRED` indicates that an operation did not complete in the alotted time.
279
+
280
+
281
+ A number of error codes are defined in the protocol file but not currently used:
282
+
283
+ * `HEADER_REQUIRED`
284
+ * `SERVICE_BUSY`
285
+ * `DATA_ERROR`
286
+ * `PERM_DATA_ERROR`
287
+
288
+ It is possible that an error will occur that will prevent the Kinetic Device from returning a `protobuf` message with a status code. These are some situations:
289
+
290
+ * **Invalid Kinetic PDU:** If the Kinetic PDU is not formed as described above, the TCP connection will be closed abruptly. This includes the case that a value or protobuf message exceeds the size limitations.
291
+ * **Invalid Protobuf:** If the `protobuf` message cannot be decoded because it is not well formed, the TCP connection will be closed abruptly.
292
+
293
+
294
+ ## No Op
295
+ The `NOOP` operation can be used as a quick test of whether the Kinetic Device is running and available. If the Kinetic Device is running, this operation will always return succeed.
296
+
297
+ **Request Message**
298
+
299
+ ```
300
+ command {
301
+ header {
302
+ // See above for descriptions of these fields
303
+ clusterVersion: ...
304
+ identity: ...
305
+ connectionID: ...
306
+ sequence: ...
307
+ // messageType should be NOOP
308
+ messageType: NOOP
309
+ }
310
+ }
311
+ hmac: "..."
312
+ ```
313
+
314
+ **Response Message**
315
+
316
+ ```
317
+
318
+ command {
319
+ header {
320
+ // See above
321
+ ackSequence: ...
322
+
323
+ // messageType should be NOOP_RESPONSE
324
+ messageType: NOOP_RESPONSE
325
+ }
326
+ status {
327
+ code: SUCCESS
328
+ }
329
+ }
330
+ hmac: ""
331
+ ```
332
+
333
+
334
+ ## Modify Value Operations
335
+
336
+ ### Cross-Cutting Concerns
337
+
338
+ Within the `body` message of a value modification operation, many fields in the `keyValue` apply to all operations.
339
+
340
+ ```
341
+ command: {
342
+ ...
343
+ body: {
344
+ keyValue {
345
+ // Required bytes
346
+ // The key for the value being set
347
+ key: "..."
348
+
349
+ // Required bytes
350
+ // Versions are set on objects to support optimistic locking.
351
+ // For operations that modify data, if the dbVersion sent in the
352
+ // request message does not match the version stored in the db, the
353
+ // request will fail.
354
+ dbVersion: "..."
355
+
356
+ // Required bytes
357
+ // Specifies what the next version of the data will be if this
358
+ // operation is successful.
359
+ newVersion: "..."
360
+
361
+ // Optional bool, default false
362
+ // Setting force to true ignores potential version mismatches
363
+ // and carries out the operation.
364
+ force: true
365
+
366
+ // Optional bytes
367
+ // The integrity value for the data. This value should be computed
368
+ // by the client application by applying the hash algorithm
369
+ // specified below to the value (and only to the value).
370
+ // The algorithm used should be specified in the algorithm field.
371
+ // The Kinetic Device will not do any processing on this value.
372
+ tag: "..."
373
+
374
+ // The algorithm used by the client to compute the tag.
375
+ // The allowed values are: SHA1, SHA2, SHA3, CRC32, CRC64
376
+ algorithm: ...
377
+
378
+ // Optional Synchronization enum value, defaults to WRITETHROUGH
379
+ // Allows client to specify if the data must be written to disk
380
+ // immediately, or can be written in the future.
381
+ //
382
+ // WRITETHROUGH: This request is made persistent before returning.
383
+ // This does not effect any other pending operations.
384
+ // WRITEBACK: They can be made persistent when the drive chooses,
385
+ // or when a subsequent FLUSH is give to the drive.
386
+ // FLUSH: All pending information that has not been written is
387
+ // pushed to the disk and the command that specifies
388
+ // FLUSH is written last and then returned. All WRITEBACK writes
389
+ // that have received ending status will be guaranteed to be
390
+ // written before the FLUSH operation is returned completed.
391
+ synchronization: ...
392
+ }
393
+ }
394
+ }
395
+ ```
396
+
397
+ ### PUT
398
+ The `PUT` operation sets the value and metadata for a given key. If a value already exists in the store for the given key, the client must pass a value for `dbVersion` which matches the stored version for this key to overwrite the value metadata. This behavior can be overridden (so that the version is ignored and the value and metadata are always written) by setting `forced` to `true` in the `KeyValue` option.
399
+
400
+ **Request Message**
401
+
402
+ The following request will add a key value pair to the store. Note that `dbVersion` is not specified, this is allowed when adding (as opposed to updating) a value.
403
+
404
+ ```
405
+ command {
406
+ // See top level cross cutting concerns for header details
407
+ header {
408
+ clusterVersion: ...
409
+ identity: ...
410
+ connectionID: ...
411
+ sequence: ...
412
+ // The messageType should be PUT
413
+ messageType: PUT
414
+ }
415
+ body {
416
+ keyValue {
417
+ // See write operation cross cutting concerns
418
+ newVersion: "..."
419
+ key: "..."
420
+ tag: "..."
421
+ algorithm: ...
422
+ synchronization: ...
423
+ }
424
+ }
425
+ }
426
+ // See above
427
+ hmac: "..."
428
+ ```
429
+
430
+ **Response Message**
431
+ When the key is successfully written, the device will respond with the following message:
432
+
433
+ ```
434
+ command {
435
+ header {
436
+ // See above
437
+ ackSequence: ...
438
+ // The messageType should be PUT_RESPONSE
439
+ messageType: PUT_RESPONSE
440
+ }
441
+ body {
442
+ keyValue {
443
+ // Empty
444
+ }
445
+ }
446
+ status {
447
+ // A successful PUT will return SUCCESS
448
+ code: SUCCESS
449
+ }
450
+ }
451
+ hmac: ""
452
+ ```
453
+
454
+ Error Cases:
455
+
456
+ * `code = VERSION_MISMATCH`
457
+ * For a PUT of a new key (insert, not update) specifying a dbVersion
458
+ * If the version doesn't match (should not occur for create)
459
+ * `code = NOT_AUTHORIZED`
460
+ * If the identity doesn't have permission to put this value, in this case `status.statusMessage` will be "permission denied."
461
+ * The connection will be closed without reply if the value is too long. (The result in a client library may be some sort of IO Error, depending on implementation).
462
+
463
+
464
+ ### Delete
465
+ The `DELETE` operation removes the entry for a given key. It respects the same locking behavior around `dbVersion` and `force` as described in the previous sections.
466
+
467
+ **Request Message**
468
+
469
+ The following request will remove a key value pair to the store.
470
+
471
+ ```
472
+ command {
473
+ // See top level cross cutting concerns for header details
474
+ header {
475
+ clusterVersion: ...
476
+ identity: ...
477
+ connectionID: ...
478
+ sequence: ...
479
+ // messageType should be DELETE
480
+ messageType: DELETE
481
+ }
482
+ body {
483
+ keyValue {
484
+ key: "..."
485
+ // See write operation cross cutting concerns
486
+ synchronization: ...
487
+ }
488
+ }
489
+ }
490
+ // See above
491
+ hmac: "..."
492
+ ```
493
+
494
+ **Response Message**
495
+ When the entry is successfully removed, the device will respond with the following message:
496
+
497
+ ```
498
+
499
+ command {
500
+ // See top level cross cutting concerns for header details
501
+ header {
502
+ ackSequence: ...
503
+
504
+ // messageType should be DELETE_RESPONSE
505
+ messageType: DELETE_RESPONSE
506
+ }
507
+ body {
508
+ keyValue {
509
+ }
510
+ }
511
+ status {
512
+ // A successful DELETE will return SUCCESS
513
+ code: SUCCESS
514
+ }
515
+ }
516
+ hmac: "..."
517
+
518
+ ```
519
+
520
+ There are many cases where a delete could fail with a properly functioning drive. The following `status.code` values identify these cases:
521
+
522
+ * `code = VERSION_MISMATCH` The dbVersion in the request doesn't match the version stored in the device.
523
+ * `code = NOT_FOUND` The key was not found in the data store.
524
+ * `code = NOT_AUTHORIZED` The identity doesn't have permission to delete this value, in this case `status.statusMessage` will be "permission denied."
525
+
526
+
527
+ ### Flush
528
+ The `FLUSHALLDATA` operation flushes any outstanding PUTs or DELETEs on the device. For example, if the client `PUT` many keys with `synchronization=WRITEBACK` the data
529
+ would not be guaranteed to be persisted, so power cycling could result in lost data. When a `FLUSHALLDATA` command returns, all previous operations with `synchronization=WRITEBACK` on
530
+ this connection are guaranteed to be persisted. Data on separate connections is not guaranteed to be persisted, but may as an indirect consequence of this operation.
531
+
532
+ **Request Message**
533
+
534
+ The following request will flush the write cache.
535
+
536
+ ```
537
+ command {
538
+ // See top level cross cutting concerns for header details
539
+ header {
540
+ clusterVersion: ...
541
+ identity: ...
542
+ connectionID: ...
543
+ sequence: ...
544
+ // messageType should be FLUSHALLDATA
545
+ messageType: FLUSHALLDATA
546
+ }
547
+ body {
548
+ }
549
+ }
550
+ // See above
551
+ hmac: "..."
552
+ ```
553
+
554
+ **Response Message**
555
+ When the cache is flushed, the device will return the following message:
556
+
557
+ ```
558
+
559
+ command {
560
+ // See top level cross cutting concerns for header details
561
+ header {
562
+ ackSequence: ...
563
+
564
+ // messageType should be FLUSHALLDATA_RESPONSE
565
+ messageType: FLUSHALLDATA_RESPONSE
566
+ }
567
+ body {
568
+ }
569
+ status {
570
+ // A successful FLUSHALLDATA will return SUCCESS
571
+ code: SUCCESS
572
+ }
573
+ }
574
+ hmac: "..."
575
+
576
+ ```
577
+
578
+ **Permissions**
579
+ No special permissions are required.
580
+
581
+
582
+ ## Read Operations
583
+ There are a number of operations which are designed to allow clients to read values from the Kinetic Device. They will be discussed in this section.
584
+
585
+ ### Cross-Cutting Concenrs
586
+
587
+ Within the `body` message of a read value operation, many fields in the `keyValue` message apply to all operations.
588
+
589
+
590
+ ```
591
+ keyValue {
592
+ // Required bytes.
593
+ // The key identifying the value in the data store.
594
+ key: "..."
595
+
596
+ // Optional bool, defaults to false.
597
+ // If true, only metadata (not the full value) will be returned
598
+ // If false, metadata and value will be returned
599
+ metadataOnly: ...
600
+ }
601
+ ```
602
+
603
+
604
+ ### GET
605
+ The `GET` operation is used to retrieve the value and metadata for a given key.
606
+
607
+ **Request Message**
608
+
609
+ ```
610
+ command {
611
+ header {
612
+ // See above for descriptions of these fields
613
+ clusterVersion: ...
614
+ identity: ...
615
+ connectionID: ...
616
+ sequence: ...
617
+
618
+ // The mesageType should be GET
619
+ messageType: GET
620
+ }
621
+ body {
622
+ keyValue {
623
+ // See above
624
+ key: "..."
625
+ }
626
+ }
627
+ }
628
+ // See above
629
+ hmac: "..."
630
+ ```
631
+
632
+ **Response Message**
633
+
634
+ A successful response will return the value in the top level Kinetic PDU, and will have a `SUCCESS` status:
635
+
636
+ ```
637
+ command {
638
+ header {
639
+ // See above
640
+ ackSequence: ...
641
+ // messageType should be GET_RESPONSE
642
+ messageType: GET_RESPONSE
643
+ }
644
+ body {
645
+ keyValue {
646
+ // These fields are documented above
647
+ key: ""
648
+ dbVersion: ""
649
+ tag: ""
650
+ algorithm: SHA2
651
+ }
652
+ }
653
+ status {
654
+ code: SUCCESS
655
+ }
656
+ }
657
+ hmac: "..."
658
+ ```
659
+
660
+ There are many cases where a read could fail with a properly functioning drive. The following `status.code` values identify these cases:
661
+
662
+ * `NOT_FOUND` The key does not exist in the data store (the Kinetic PDU will have a zero-length value component).
663
+ * `NOT_AUTHORIZED` The identity doesn't have permission to put this value, in this case `status.statusMessage` will be "permission denied."
664
+
665
+
666
+ ### Get Version
667
+ The `GETVERSION` operation provdes the current store version for a given key.
668
+
669
+ **Request Message**
670
+
671
+ ```
672
+ command {
673
+ header {
674
+ // These fields are documented above
675
+ clusterVersion: ...
676
+ identity: ...
677
+ connectionID: ...
678
+ sequence: ...
679
+ // messageType should be GETVERSION
680
+ messageType: GETVERSION
681
+ }
682
+ body {
683
+ keyValue {
684
+ // Required. See above.
685
+ key: "..."
686
+ }
687
+ }
688
+ }
689
+ hmac: "..."
690
+ ```
691
+
692
+ **Response Message**
693
+
694
+ ```
695
+ command {
696
+ header {
697
+ // This field is documented above
698
+ ackSequence: ...
699
+ // messageType should be GETVERSION_RESPONSE
700
+ messageType: GETVERSION_RESPONSE
701
+ }
702
+ body {
703
+ keyValue {
704
+ // The dbVersion is the only entry in the keyValue object that will
705
+ // be returned by the server
706
+ dbVersion: "..."
707
+ }
708
+ }
709
+ status {
710
+ code: SUCCESS
711
+ }
712
+ }
713
+ hmac: ""
714
+ ```
715
+ Error Cases:
716
+
717
+ * `code = NOT_FOUND` The key does not exist in the data store (the Kinetic PDU will have a zero-length value component).
718
+ * `code = NOT_AUTHORIZED` The requester doesn't have permission to put this value, in this case `status.statusMessage` will be "permission denied."
719
+
720
+
721
+
722
+ ### Get Next
723
+ The `GETNEXT` operation takes a key and returns the value for the next key in the sorted set of keys. Keys are sorted lexicographically by their byte representation.
724
+
725
+ **Request Message**
726
+
727
+ ```
728
+ command {
729
+ header {
730
+ // See above for descriptions of these fields
731
+ clusterVersion: ...
732
+ identity: ...
733
+ connectionID: ...
734
+ sequence: ...
735
+ // messageType should be GETNEXT
736
+ messageType: GETNEXT
737
+ }
738
+ body {
739
+ keyValue {
740
+ // A key is required. Note that this is different from GET in that you
741
+ // will not get the value for this key, but the value for the subsequent
742
+ // key in the ordering.
743
+ key: "..."
744
+ }
745
+ }
746
+ }
747
+ // See above
748
+ hmac: "..."
749
+ ```
750
+
751
+ **Response Message**
752
+
753
+ ```
754
+ command {
755
+ header {
756
+ // See above for descriptions of this field
757
+ ackSequence: ...
758
+ // messageType should be GETNEXT_RESPONSE
759
+ messageType: GETNEXT_RESPONSE
760
+ }
761
+ body {
762
+ keyValue {
763
+ // This is the key for the value that is being returned
764
+ // This will be different from the key passed in the request
765
+ key: "..."
766
+
767
+ // These fields are documented above
768
+ dbVersion: "..."
769
+ tag: "..."
770
+ algorithm: ...
771
+ }
772
+ }
773
+ status {
774
+ // If the operation does not succeed, a different code will be specified.
775
+ // See below.
776
+ code: SUCCESS
777
+ }
778
+ }
779
+ // See above
780
+ hmac: "..."
781
+ ```
782
+
783
+ Error Cases:
784
+
785
+ * `code = NOT_FOUND`
786
+ * There is no key in the store that is sorted after the given key.
787
+ * This can occur if the given key is the last key in the store, of if the key given is not included in the store but would be sorted after the last key.
788
+ * `code = NOT_AUTHORIZED` The identity does not have read permission on the key that would be returned.
789
+
790
+ Edge Cases:
791
+
792
+ * If a `key` is provided which is not found in the store, the service will find the first key which would be sorted after the given key. For example, if the store has keys `key0` and `key2` and the client sends a request for `GETNEXT` of `key1`, the device will return the value for `key2`.
793
+ * Note that if the identity does not have permission to read the key passed in the `GETNEXT` request, but they do have permission to read the key that would be returned, the request should succeed.
794
+
795
+ ### Get Previous
796
+ The `GETPREVIOUS` operation takes a key and returns the value for the previous key in the sorted set of keys. Keys are sorted lexicographically by their byte representation.
797
+
798
+ **Request Message**
799
+
800
+ ```
801
+ command {
802
+ header {
803
+ // See above for descriptions of these fields
804
+ clusterVersion: ...
805
+ identity: ...
806
+ connectionID: ...
807
+ sequence: ...
808
+ // messageType should be GETPREVIOUS
809
+ messageType: GETPREVIOUS
810
+ }
811
+ body {
812
+ keyValue {
813
+ // A key is required. Note that this is different from GET in that you
814
+ // will not get the value for this key, but the value for the subsequent
815
+ // key in the ordering.
816
+
817
+ key: "..."
818
+ }
819
+ }
820
+ }
821
+ // See above
822
+ hmac: "..."
823
+ ```
824
+
825
+ **Response Message**
826
+
827
+ ```
828
+ command {
829
+ header {
830
+ // See above for descriptions of this field
831
+ ackSequence: ...
832
+ // messageType should be GETPREVIOUS_RESPONSE
833
+ messageType: GETPREVIOUS_RESPONSE
834
+ }
835
+ body {
836
+ keyValue {
837
+ // This is the key for the value that is being returned
838
+ // This will be different from the key passed in the request
839
+ key: "..."
840
+
841
+ // These fields are documented above
842
+ dbVersion: "..."
843
+ tag: "..."
844
+ algorithm: ...
845
+ }
846
+ }
847
+ status {
848
+ // If the operation does not succeed, a different code will be specified.
849
+ // See below.
850
+ code: SUCCESS
851
+ }
852
+ }
853
+ // See above
854
+ hmac: "..."
855
+ ```
856
+
857
+ Error Cases:
858
+
859
+ * `code = NOT_FOUND`
860
+ * There is no key in the store that is sorted brefore the given key.
861
+ * This can occur if the given key is the first key in the store, of if the key given is not included in the store but would be sorted before the first key.
862
+ * `code = NOT_AUTHORIZED`:
863
+ * If the identity does not have read permission on the key that would be returned.
864
+
865
+ Edge Cases:
866
+
867
+ * If a `key` is provided which is not found in the store, the service will find the first key which would be sorted before the given key. For example, if the store has keys `key0` and `key2` and the client sends a request for `GETPREVIOUS` of `key1`, the device will return the value for `key0`.
868
+ * Note that if the identity does not have permission to read the key passed in the `GETNEXT` request, but they do have permission to read the key that would be returned, the request should succeed.
869
+
870
+
871
+
872
+ ### Get Key Range
873
+ The `GETKEYRANGE` operation takes a start and end key and returns all keys between those in the sorted set of keys. This operation can be configured so that the range is either inclusive or exclusive of the start and end keys, the range can be reversed, and the requester can cap the number of keys returned.
874
+
875
+ Note that this operation does not fetch associated values, or other metadata. It only returns the keys themselves, which can be used for other operations.
876
+
877
+ **Request Message**
878
+
879
+ ```
880
+ command {
881
+ header {
882
+ // See above for descriptions of these fields
883
+ clusterVersion: ...
884
+ identity: ...
885
+ connectionID: ...
886
+ sequence: ...
887
+
888
+ // messageType should be GETKEYRANGE
889
+ messageType: GETKEYRANGE
890
+ }
891
+ body {
892
+ // The range message must be populated
893
+ range {
894
+ // Required bytes, the beginning of the requested range
895
+ startKey: "..."
896
+
897
+ // Optional bool, defaults to false
898
+ // True indicates that the start key should be included in the returned
899
+ // range
900
+ startKeyInclusive: ...
901
+
902
+ // Required bytes, the end of the requested range
903
+ endKey: "..."
904
+
905
+ // Optional bool, defaults to false
906
+ // True indicates that the end key should be included in the returned
907
+ // range
908
+ endKeyInclusive: ...
909
+
910
+ // Required int32, must be greater than 0
911
+ // The maximum number of keys returned, in sorted order
912
+ maxReturned: ...
913
+
914
+ // Optional bool, defaults to false
915
+ // If true, the key range will be returned in reverse order, starting at
916
+ // endKey and moving back to startKey. For instance
917
+ // if the search is startKey="j", endKey="k", maxReturned=2,
918
+ // reverse=true and the keys "k0", "k1", "k2" exist
919
+ // the system will return "k2" and "k1" in that order.
920
+ reverse: ....
921
+ }
922
+ }
923
+ }
924
+ ```
925
+
926
+ **Response Message**
927
+
928
+
929
+ ```
930
+ command {
931
+ header {
932
+ ackSequence: ...
933
+ messageType: GETKEYRANGE_RESPONSE
934
+ }
935
+ body {
936
+ // The range message is populated with up to maxReturned keys.
937
+ // If no keys are found in the range then the range message will be omitted
938
+ // and the status code will be SUCCESS
939
+ range {
940
+ key: "..."
941
+ key: "..."
942
+ ...
943
+ key: "..."
944
+ }
945
+ }
946
+ status {
947
+ code: SUCCESS
948
+ }
949
+ }
950
+ hmac: "..."
951
+ ```
952
+
953
+
954
+ Error Cases:
955
+
956
+ * `code = INVALID_REQUEST`
957
+ * The `maxReturned` exceeded the limit, the `status.statusMessage` will be `Key limit exceeded.`
958
+
959
+ Edge Cases:
960
+
961
+ * If neither `startKey` or `endKey` are found in the store, any keys that would be sorted between them will be returned.
962
+ * If the given keys are out of order (e.g. `startKey` is sorted after `endKey`), then no keys will be returned.
963
+
964
+ **Permissions**
965
+
966
+ This operation should return the first contiguous block of keys for which the requesting identity has the `RANGE` permission on an applicable scope. This means that not necessarily each key in the requested range for which the identity has this permission will be returned. For instance, consider a store that contains `k0`, `k1`, `k2`, `k4`, and `k5`, where the requesting identity has the `RANGE` permission on scopes which aply to `k0`, `k1`, `k4`, and `k5` but notably does not have `RANGE` permission on any scope which applies to `k2`. Then if that identity requests a `GETKEYRANGE` with `startKey=k0` (inclusive), `endKey=k5` (inclusive) the Kinetic Device will return `k0` and `k1`. When it reaches `k2`, for which it does not have a `RANGE` permission, it will stop the operation.
967
+
968
+
969
+ ## Setup
970
+ The `SETUP` operation can be used to set the device's `clusterVersion` and `pin`, to perform an "Instant Secure Erase", or to download new firmware on the device. As these operations are quite different, we'll discuss them separately in this section. The Kinetic Device will only allow one of these operations per message (though syntactically several could be combined).
971
+
972
+
973
+ ### Set Cluster Version
974
+
975
+ **Request Message**
976
+
977
+ ```
978
+ command {
979
+ header {
980
+ // Important: this should be the current cluster version. This operation is
981
+ // intended to change the clusterVersion, but the current clusterVersion
982
+ // must be specified here.
983
+ clusterVersion: ...
984
+
985
+ // See top level cross cutting concerns for header details
986
+ identity: ...
987
+ connectionID: ...
988
+ sequence: ...
989
+
990
+ // The messageType should be SETUP
991
+ messageType: SETUP
992
+ }
993
+ body {
994
+ setup {
995
+ // Required int64, needed to update the cluster version
996
+ // (otherwise request will be treated as a different Setup operation)
997
+ // This is the clusterVersion being set on the device.
998
+ newClusterVersion: 1
999
+ }
1000
+ }
1001
+ }
1002
+ hmac: ""
1003
+ ```
1004
+
1005
+ **Response Message**
1006
+
1007
+ ```
1008
+ command {
1009
+ header {
1010
+ ackSequence: ...
1011
+ // The messageType should be SETUP_RESPONSE
1012
+ messageType: SETUP_RESPONSE
1013
+ }
1014
+ status {
1015
+ code: SUCCESS
1016
+ }
1017
+ }
1018
+ hmac: ""
1019
+ ```
1020
+
1021
+ ### Set Pin
1022
+
1023
+ ### Instant Secure Erase
1024
+ This operation should be used to erase all stored data from the device. **This operation is currently neither instant nor secure. In future versions of the application, it will be both.**
1025
+
1026
+ **Request Message**
1027
+
1028
+ ```
1029
+ command {
1030
+ header {
1031
+ // See top level cross cutting concerns for header details
1032
+ clusterVersion: ...
1033
+ identity: ...
1034
+ connectionID: ...
1035
+ sequence: ...
1036
+ // The messageType should be SETUP
1037
+ messageType: SETUP
1038
+ }
1039
+ body {
1040
+ setup {
1041
+ // Required bool, defaults to false if omitted.
1042
+ // Must be true for this request to be treated as an ISE.
1043
+ instantSecureErase: true
1044
+ }
1045
+ }
1046
+ }
1047
+ hmac: ""
1048
+ ```
1049
+
1050
+ **Response Message**
1051
+
1052
+ ```
1053
+ command {
1054
+ header {
1055
+ ackSequence: ...
1056
+ // The messageType should be SETUP_RESPONSE
1057
+ messageType: SETUP_RESPONSE
1058
+ }
1059
+ status {
1060
+ code: SUCCESS
1061
+ }
1062
+ }
1063
+ hmac: ""
1064
+ ```
1065
+
1066
+
1067
+ ### Firmware Download
1068
+ This operation should be used load new firmware on the device.
1069
+
1070
+ **Request Message**
1071
+
1072
+ ```
1073
+ command {
1074
+ header {
1075
+ // See top level cross cutting concerns for header details
1076
+ clusterVersion: ...
1077
+ identity: ...
1078
+ connectionID: ...
1079
+ sequence: ...
1080
+ // The messageType should be SETUP
1081
+ messageType: SETUP
1082
+ }
1083
+ body {
1084
+ setup {
1085
+ // Required bool, must be present and true to indicate that this is
1086
+ // a firmware download operation.
1087
+ // Indicates that the value (in the Kinetic PDU) will contain the firmware
1088
+ firmwareDownload: true
1089
+ }
1090
+ }
1091
+ }
1092
+ hmac: ""
1093
+ ```
1094
+
1095
+ The value field in the Kinetic PDU (describe above) will contain the firmware payload.
1096
+
1097
+ **Response Message**
1098
+
1099
+ ```
1100
+ command {
1101
+ header {
1102
+ ackSequence: ...
1103
+ // The messageType should be SETUP_RESPONSE
1104
+ messageType: SETUP_RESPONSE
1105
+ }
1106
+ status {
1107
+ code: SUCCESS
1108
+ }
1109
+ }
1110
+ hmac: ""
1111
+ ```
1112
+
1113
+
1114
+ ## Administration
1115
+
1116
+ ### Security
1117
+ The security operation allows administrators to specify ACLs, granting access to specific operations. Some semantics of the Security operation are noteworthy:
1118
+
1119
+ * A `identity` has one ACL, and an ACL only applies to one `identity`. They have a one-to-one relationship.
1120
+ * An ACL list cannot be updated, only set. Each request to SECURITY with a well-formed security body will overwrite the existing setup.
1121
+ * To make a Secuirty operation (set ACLs) the requesting identity must have an applicable scope with a SECURITY permission.
1122
+
1123
+
1124
+ To set the ACL for a identity (or many identities), a request like the following could be sent. See the Access Control section above for further explanation of the ACL message.
1125
+
1126
+ **Request Message**
1127
+
1128
+ ```
1129
+ command {
1130
+ header {
1131
+ // See top level cross cutting concerns for header details
1132
+ clusterVersion: ...
1133
+ identity: ...
1134
+ connectionID: ...
1135
+ sequence: ...
1136
+
1137
+ // messageType should be SECURITY
1138
+ messageType: SECURITY
1139
+ }
1140
+ body {
1141
+ // The security message must be present and contain at least one acl
1142
+ // message. Multiple are allowed but only one can be specified per identity.
1143
+ // Note that security message overwrites the stored ACL list entirely,
1144
+ // no updating is supported.
1145
+ security {
1146
+ acl {
1147
+ // Required int64, the identity this ACL applies to
1148
+ identity: 1
1149
+ // Required bytes, the identity's HMAC key, a shared secret
1150
+ key: "...."
1151
+ // Required HMACAlgorithm, the algorithm used to compute the HMAC for
1152
+ // this identity
1153
+ hmacAlgorithm: ...
1154
+
1155
+ // The scope message has at least one permission, in this example there
1156
+ // are many
1157
+ scope {
1158
+ permission: READ
1159
+ permission: WRITE
1160
+ permission: DELETE
1161
+ permission: RANGE
1162
+ permission: SETUP
1163
+ permission: P2POP
1164
+ permission: GETLOG
1165
+ permission: SECURITY
1166
+ }
1167
+ }
1168
+
1169
+ // This ACL shows that multiple scopes can be set for a identity in one
1170
+ // ACL message
1171
+ acl {
1172
+ identity: 2
1173
+ key: "..."
1174
+ hmacAlgorithm: ...
1175
+
1176
+ // This simple scope allows identity 2 to read all keys
1177
+ scope {
1178
+ permission: READ
1179
+ }
1180
+
1181
+ // This scope gives identity 2 the ability to write keys if and only if
1182
+ // "test" is a substring of key starting at offset 3. For example, with
1183
+ // this scope identity 2 could PUT keys: "xyztest1", "001test2", etc
1184
+ // but could not put keys: "somethingElse", "test123", "1234test"
1185
+ scope {
1186
+ offset: 3
1187
+ value: "test"
1188
+ permission: WRITE
1189
+ }
1190
+ }
1191
+
1192
+ // More ACLs for additional identities may be specified in the
1193
+ // same security message...
1194
+ acl {
1195
+ identity: 3
1196
+ key: "..."
1197
+ hmacAlgorithm: ...
1198
+ scope {
1199
+ permission: WRITE
1200
+ }
1201
+ }
1202
+ acl {
1203
+ identity: 4
1204
+ key: "..."
1205
+ hmacAlgorithm: ...
1206
+ scope {
1207
+ permission: DELETE
1208
+ }
1209
+ }
1210
+ }
1211
+ }
1212
+ hmac: "..."
1213
+
1214
+ ```
1215
+
1216
+
1217
+ **Response Message**
1218
+
1219
+ ```
1220
+ command {
1221
+ header {
1222
+ ackSequence: ...
1223
+
1224
+ // messageType should be SECURITY_RESPONSE
1225
+ messageType: SECURITY_RESPONSE
1226
+ }
1227
+ status {
1228
+ // If successful, code will be SUCCESS
1229
+ code: SUCCESS
1230
+ }
1231
+ }
1232
+ hmac: ""
1233
+ ```
1234
+
1235
+ Error Cases:
1236
+
1237
+ * `code=NOT_AUTHORIZED` if the requesting identity does not have the `SECURITY` permission for an applicable scope.
1238
+ * `code=NO_SUCH_HMAC_ALGORITHM` if an `acl` message has an `hmaclAlgorithm` value which is invalid.
1239
+ * `code=INTERNAL_ERROR` (in the future, this code will be changed)
1240
+ * if an offset is provided which is less than zero
1241
+ * if there are no permissions provided in a scope
1242
+ * if one of the permissions provided is invalid (e.g. Permission.INVALID)
1243
+
1244
+
1245
+ ### Get Log
1246
+
1247
+ The `GETLOG` operation gives the client access to log information. The request message must include at least one type and can have many types. The supported types are:
1248
+
1249
+ * `UTILIZATIONS`
1250
+ * `TEMPERATURES`
1251
+ * `CAPACITIES`
1252
+ * `CONFIGURATION`
1253
+ * `STATISTICS`
1254
+ * `MESSAGES`
1255
+ * `LIMITS`
1256
+
1257
+ Below we will show the message structure used to request all types in a single `GETLOG` request.
1258
+
1259
+
1260
+ **Request Message**
1261
+
1262
+ ```
1263
+ command {
1264
+ header {
1265
+ clusterVersion: ...
1266
+ identity: ...
1267
+ connectionID: ...
1268
+ sequence: ...
1269
+ // The messageType should be GETLOG
1270
+ messageType: GETLOG
1271
+ }
1272
+ body {
1273
+ // The body should contain a getLog message, which must have
1274
+ // at least one value for type. Multiple are allowed.
1275
+ // Here all types are requested.
1276
+ getLog {
1277
+ type: CAPACITIES
1278
+ type: CONFIGURATION
1279
+ type: MESSAGES
1280
+ type: STATISTICS
1281
+ type: TEMPERATURES
1282
+ type: UTILIZATIONS
1283
+ }
1284
+ }
1285
+ }
1286
+ hmac: "..."
1287
+ ```
1288
+
1289
+ **Respose Message**
1290
+
1291
+ ```
1292
+ command {
1293
+ header {
1294
+ ackSequence: ...
1295
+ // messageType should be GETLOG_RESPONSE
1296
+ messageType: GETLOG_RESPONSE
1297
+ }
1298
+ body {
1299
+ getLog {
1300
+ // Each type requested is provided in the response
1301
+ type: CAPACITIES
1302
+ type: CONFIGURATION
1303
+ type: MESSAGES
1304
+ type: STATISTICS
1305
+ type: TEMPERATURES
1306
+ type: UTILIZATIONS
1307
+ type: LIMITS
1308
+
1309
+ // Many utilization messages may be returned
1310
+ utilization {
1311
+ // Required string, the name of the rescource being reported
1312
+ // For example: HDA, ENO, CPU...
1313
+ name: "..."
1314
+ // Required float, the value for this resource's utilization.
1315
+ // value will be between 0.00 and 1.00.
1316
+ value: 0.2
1317
+ }
1318
+
1319
+ utilization {
1320
+ name: "...""
1321
+ value: ...
1322
+ }
1323
+ ...
1324
+
1325
+ // Many temperature messages may be returned
1326
+ temperature {
1327
+ // Required string, the name of the resource being reported
1328
+ name: "..."
1329
+
1330
+ // Required float, the current temperature in degrees celcius
1331
+ current: 39.0
1332
+ // Required float, the current temperature in degrees celcius
1333
+ minimum: 5.0
1334
+ // Required float, the current temperature in degrees celcius
1335
+ maximum: 100.0
1336
+ // Required float, the current temperature in degrees celcius
1337
+ target: 25.0
1338
+ }
1339
+
1340
+ // Only one configuration message will be included
1341
+ configuration {
1342
+ // string, the vendor of the Kinetic Device.
1343
+ vendor: "..."
1344
+
1345
+ // string, the model of the Kinetic Device
1346
+ model: "..."
1347
+
1348
+ // bytes, the serial number of the Kinetic Device
1349
+ serialNumber: "..."
1350
+
1351
+ // string, the version of the kinetic software running on the device
1352
+ version: "..."
1353
+
1354
+ // Multiple interface messages will appear, one per network interface
1355
+ // that the Kinetic Device.
1356
+ interface {
1357
+ name: "..."
1358
+ MAC: "..."
1359
+ ipv4Address: "..."
1360
+ ipv6Address: "..."
1361
+ }
1362
+ interface {
1363
+ name: "..."
1364
+ ipv4Address: "..."
1365
+ ipv6Address: "..."
1366
+ }
1367
+ // int32, the port where the kinetic service is running
1368
+ port: ...
1369
+ // int32, the port where the kinetic service is running over SSL
1370
+ tlsPort: ...
1371
+ // string, he date this version of the kinetic service was compiled
1372
+ compilationDate: "..."
1373
+ // string, a checksum of the source code
1374
+ sourceHash: "..."
1375
+ }
1376
+
1377
+ // There should be one statistics message per messageType (GET, PUT, etc)
1378
+ // The statistics messages aggregate statistics for each messageType.
1379
+ statistics {
1380
+ // Required MessageType, which messageType these statistics apply to
1381
+ messageType: PUT
1382
+ // Required sint64, how many times this messageType has been received
1383
+ count: ...
1384
+ // Required sint64, the sum length of all the value portion of the
1385
+ // Kinetic PDU messages sent since starting the Kinetic Device
1386
+ bytes: ...
1387
+ }
1388
+ ...
1389
+ statistics {
1390
+ messageType: GET
1391
+ count: ...
1392
+ bytes: ...
1393
+ }
1394
+
1395
+ // Only one capacity message will be included
1396
+ capacity {
1397
+ // uint64
1398
+ nominalCapacityInBytes: ...
1399
+ // float
1400
+ portionFull: ...
1401
+ }
1402
+
1403
+ // bytes representing recent Kinetic Device log messages
1404
+ messages: "..."
1405
+
1406
+ // limits that the device will enforce
1407
+ limits {
1408
+ maxKeySize = ...
1409
+ maxValueSize = ...
1410
+ maxVersionSize = ...
1411
+ maxTagSize = ...
1412
+ maxConnections = ...
1413
+ maxOutstandingReadRequests = ...
1414
+ maxOutstandingWriteRequests = ...
1415
+ maxMessageSize = ...
1416
+ maxKeyRangeCount = ...
1417
+ }
1418
+ }
1419
+ }
1420
+ status {
1421
+ code: SUCCESS
1422
+ }
1423
+ }
1424
+ ```
1425
+
1426
+
1427
+ ## Peer to Peer
1428
+ The `PEER2PEERPUSH` operation allows a client to instruct a Kinetic Device to copy a set of keys (and associated value and metadata) to another Kinetic Device. Peer To Peer operations can be nested, so a client could tell device A to copy certain keys to device B, and then have device B copy a set of keys to device C, and so on.
1429
+
1430
+
1431
+ **Request Message**
1432
+
1433
+ ```
1434
+ command {
1435
+ header {
1436
+ clusterVersion: ...
1437
+ identity: ...
1438
+ connectionID: ...
1439
+ sequence: ...
1440
+ messageType: PEER2PEERPUSH
1441
+ }
1442
+ body {
1443
+ p2pOperation {
1444
+ peer {
1445
+ // Required string, the network address of the peer
1446
+ hostname: "..."
1447
+ // Required int32, the port on which the peer is running the Kinetic service
1448
+ port: ...
1449
+ // Optional boolean, defaults to false.
1450
+ // Currently SSL is not supported so this must be false.
1451
+ tls: ...
1452
+ }
1453
+ operation {
1454
+ // Required bytes, the key to copy from the source peer.
1455
+ key: ""
1456
+
1457
+ // Optional bytes, the
1458
+ version: "..."
1459
+
1460
+ // Optional bool, defaults to false
1461
+ // If true, force write ignoring version
1462
+ force: ...
1463
+
1464
+ // Optional bytes, the key to use in the destination peer.
1465
+ newKey: "..."
1466
+
1467
+ // This is a nested Peer To Peer Push operation. The recursive structure
1468
+ // allows arbitrarily deep (up to the message size cap) nesting of
1469
+ // p2p operations.
1470
+ p2pop {
1471
+ // Like the top-level p2pOperation, this specifies a peer and
1472
+ // a set of operations
1473
+ peer {
1474
+ hostname: "..."
1475
+ port: ...
1476
+ tls: false
1477
+ }
1478
+ operation {
1479
+ key: "..."
1480
+ }
1481
+ // Multiple operations can be specified in one P2POperation
1482
+ operation {
1483
+ key: "..."
1484
+ }
1485
+
1486
+ }
1487
+ }
1488
+ }
1489
+ }
1490
+ }
1491
+ hmac: ""
1492
+ ```
1493
+
1494
+ **Response Message**
1495
+
1496
+ ```
1497
+ command {
1498
+ header {
1499
+ ackSequence: ...
1500
+ messageType: PEER2PEERPUSH_RESPONSE
1501
+ }
1502
+ body {
1503
+ p2pOperation {
1504
+ // See below for a description of error handling
1505
+ allChildOperationsSucceeded: false,
1506
+ operation {
1507
+ key: "..."
1508
+ newKey: "..."
1509
+ force: ...
1510
+ status {
1511
+ code: SUCCESS
1512
+ }
1513
+ p2pop {
1514
+ peer {
1515
+ hostname: "..."
1516
+ port: ...
1517
+ tls: false
1518
+ }
1519
+ // See below for a description of error handling
1520
+ allChildOperationsSucceeded: false,
1521
+ operation {
1522
+ key: "..."
1523
+ status {
1524
+ // Status messages can be nested. This is what it would be
1525
+ // returned if an operation failed because the key was not found
1526
+ code: NOT_FOUND
1527
+ }
1528
+ }
1529
+ operation: {
1530
+ key: "...",
1531
+ status {
1532
+ code: NESTED_OPERATION_ERRORS
1533
+ }
1534
+ }
1535
+ }
1536
+ }
1537
+ }
1538
+ }
1539
+ status {
1540
+ code: SUCCESS
1541
+ }
1542
+ }
1543
+ hmac: ""
1544
+ ```
1545
+
1546
+ Error Cases:
1547
+
1548
+ If the command does not start or is terminated early, the status will be reflect that error.
1549
+
1550
+ If the request completed but some operations encountered errors, the message will be `NESTED_OPERATION_ERRORS`.
1551
+
1552
+ If all operations and nested P2P Operations within the top-level operation are successful, the `Status.code` in the `Command` message will be `SUCCESS`.
1553
+
1554
+ For each P2POperation, if any of it's nested operations fail, then it will have the flag `allChildOperationsSucceeded` set to false. Otherwise, that flag will be set to true.
1555
+
1556
+ Any operation may fail for the same reason any `PUT` could fail. Operation's have their own `Status` message to report these failures.
1557
+ In addition to the failures observed by `PUT`, Operations may experience:
1558
+
1559
+ * `NOT_ATTEMPTED` The top level request was aborted before this operation could be attempted, either due to timeouts or another error (e.g. an IO error).
1560
+ * `REMOTE_CONNECTION_ERROR` The operation was attempted, but an error prevented the operation from completing.