Class: RubyManta::MantaClient

Inherits:
Object
  • Object
show all
Defined in:
lib/ruby-manta/manta_client.rb

Defined Under Namespace

Classes: MantaClientError

Constant Summary collapse

DEFAULT_ATTEMPTS =
3
DEFAULT_CONNECT_TIMEOUT =
5
DEFAULT_SEND_TIMEOUT =
60
DEFAULT_RECEIVE_TIMEOUT =
60
MAX_LIMIT =
1000
HTTP_AGENT =
"ruby-manta/#{VERSION} (#{RUBY_PLATFORM}; #{OpenSSL::OPENSSL_VERSION}) ruby/#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}"
HTTP_SIGNATURE =
'Signature keyId="/%s/keys/%s",algorithm="%s",signature="%s"'
OBJ_PATH_REGEX =
Regexp.new('^/[^/]+(?:/?$|/stor|/public|/reports|/jobs)(?:/|$)')
JOB_PATH_REGEX =
Regexp.new('^/[^/]+/jobs(?:/|$)')
CORS_ORIGIN_REGEX =

match one or more protocol and hostnames, with optional port numbers. E.g. “example.com example.com:8443

Regexp.new('^\w+://[^\s\:]+(?:\:\d+)?' +
'(?:\s\w+://[^\s\:]+(?:\:\d+)?)*$')
CORS_HEADERS_REGEX =
Regexp.new('^[\w-]+(?:, [\w-]+)*$')
CORS_METHODS =
[ 'GET', 'POST', 'PUT', 'DELETE', 'OPTIONS' ]
ERROR_CLASSES =
[ 'AuthorizationFailed', 'AuthSchemeNotAllowed',
'BadRequest', 'Checksum', 'ConcurrentRequest',
'ContentLength', 'ContentMD5Mismatch',
'DirectoryDoesNotExist', 'DirectoryExists',
'DirectoryNotEmpty', 'DirectoryOperation',
'EntityExists', 'Internal', 'InvalidArgument',
'InvalidAuthToken', 'InvalidCredentials',
'InvalidDurabilityLevel', 'InvalidJob', 'InvalidKeyId',
'InvalidLink', 'InvalidSignature', 'InvalidJobState',
'JobNotFound', 'JobState', 'KeyDoesNotExist',
'LinkNotFound', 'LinkNotObject', 'LinkRequired',
'NotAcceptable', 'NotEnoughSpace', 'ParentNotDirectory',
'PreconditionFailed', 'PreSignedRequest',
'RequestEntityTooLarge', 'ResourceNotFound',
'RootDirectory', 'SecureTransportRequired',
'ServiceUnavailable', 'SourceObjectNotFound',
'SSLRequired', 'TaskInit', 'UploadTimeout',
'UserDoesNotExist', 'UserTaskError',
# and errors that are specific to this class:
'CorruptResult', 'UnknownError',
'UnsupportedKey' ]

Instance Method Summary collapse

Constructor Details

#initialize(host, user, priv_key_data, opts = {}) ⇒ MantaClient

Initialize a MantaClient instance.

priv_key_data is data read directly from an SSH private key (i.e. RFC 4716 format). The method can also accept several optional args: :connect_timeout, :send_timeout, :receive_timeout, :disable_ssl_verification and :attempts. The timeouts are in seconds, and :attempts determines the default number of attempts each method will make upon receiving recoverable errors.

Will throw an exception if given a key whose format it doesn’t understand.

Raises:

  • (ArgumentError)


84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/ruby-manta/manta_client.rb', line 84

def initialize(host, user, priv_key_data, opts = {})
  raise ArgumentError unless host =~ /^https{0,1}:\/\/.*[^\/]/
  raise ArgumentError unless user.is_a?(String) && user.size > 0

  @host        = host
  @user        = user
  @subuser     = opts[:subuser] ? opts[:subuser] : nil

  @attempts = opts[:attempts] || DEFAULT_ATTEMPTS
  raise ArgumentError unless @attempts > 0

  if priv_key_data =~ /BEGIN RSA/
    @digest      = OpenSSL::Digest::SHA1.new
    @digest_name = 'rsa-sha1'
    algorithm    = OpenSSL::PKey::RSA
  elsif priv_key_data =~ /BEGIN DSA/
    @digest      = OpenSSL::Digest::DSS1.new
    @digest_name = 'dsa-sha1'
    algorithm    = OpenSSL::PKey::DSA
  else
    raise UnsupportedKey
  end

  @priv_key    = algorithm.new(priv_key_data)
  @fingerprint = OpenSSL::Digest::MD5.hexdigest(@priv_key.to_blob).
                                      scan(/../).join(':')

  @client = HTTPClient.new
  @client.connect_timeout = opts[:connect_timeout] || DEFAULT_CONNECT_TIMEOUT
  @client.send_timeout    = opts[:send_timeout   ] || DEFAULT_SEND_TIMEOUT
  @client.receive_timeout = opts[:receive_timeout] || DEFAULT_RECEIVE_TIMEOUT
  @client.ssl_config.verify_mode = nil if opts[:disable_ssl_verification]

  @job_base  = '/' + @user + '/jobs'
end

Instance Method Details

#add_job_keys(job_path, obj_paths, opts = {}) ⇒ Object

Adds objects for a running job in Manta to process.

The job_path must start with /<user>/jobs/<job UUID> and point at an actual running job. The obj_paths must be an array of paths, starting with /<user>/stor or /<user>/public, pointing at actual objects.

Returns true, along with received HTTP headers.

If there was an unrecoverable error, throws an exception. On connection or corruption errors, more attempts will be made; the number of attempts can be altered by passing in :attempts.



567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
# File 'lib/ruby-manta/manta_client.rb', line 567

def add_job_keys(job_path, obj_paths, opts = {})
  url = job_url(job_path, '/live/in')
  headers = gen_headers(opts)
  headers.push([ 'Content-Type', 'text/plain' ])

  data = obj_paths.join("\n")

  attempt(opts[:attempts]) do
    result = @client.post(url, data, headers)
    raise unless result.is_a? HTTP::Message

    return true, result.headers if result.status == 204
    raise_error(result)
  end
end

#cancel_job(job_path, opts = {}) ⇒ Object

Cancels a running job in Manta at a given path.

The path must start with /<user>/jobs/<job UUID> and point at an actual job.

Returns true, along with received HTTP headers.

If there was an unrecoverable error, throws an exception. On connection or corruption errors, more attempts will be made; the number of attempts can be altered by passing in :attempts.



527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
# File 'lib/ruby-manta/manta_client.rb', line 527

def cancel_job(job_path, opts = {})
  url     = job_url(job_path, 'live/cancel')

  body = '{}'

  opts[:data] = body

  headers = gen_headers(opts)

  headers << [ 'Accept', 'application/json' ]
  headers << [ 'Content-Type', 'application/json']
  headers << [ 'Content-Length', body.bytesize ]

  args = {
      header: headers,
      body: body
  }

  attempt(opts[:attempts]) do
    result = @client.post(url, args)
    raise unless result.is_a? HTTP::Message

    return true, result.headers if result.status == 202
    raise_error(result)
  end
end

#create_job(job, opts = {}) ⇒ Object

Creates a job in Manta.

The job must be a hash, containing at minimum a :phases key. See README.md or the Manta docs to see the format and options for setting up a job on Manta; this method effectively just converts the job hash to JSON and sends to the Manta service.

Returns the path for the new job, along with received HTTP headers.

If there was an unrecoverable error, throws an exception. On connection or corruption errors, more attempts will be made; the number of attempts can be altered by passing in :attempts.

Raises:

  • (ArgumentError)


420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
# File 'lib/ruby-manta/manta_client.rb', line 420

def create_job(job, opts = {})
  raise ArgumentError unless job[:phases] || job['phases']

  headers = gen_headers(opts)
  headers.push([ 'Content-Type', 'application/json; type=job' ])
  data = job.to_json

  attempt(opts[:attempts]) do
    result = @client.post(job_url(), data, headers)
    raise unless result.is_a? HTTP::Message

    if result.status == 201
      location = result.headers['Location']
      raise unless location

      return location, result.headers
    end

    raise_error(result)
  end
end

#delete_directory(dir_path, opts = {}) ⇒ Object

Removes a directory from Manta at a given path.

The path must start with /<user>/stor or /<user/public and point at an actual object.

Returns true along with received HTTP headers.

If there was an unrecoverable error, throws an exception. On connection or corruption errors, more attempts will be made; the number of attempts can be altered by passing in :attempts.



367
368
369
370
371
372
373
374
375
376
377
378
# File 'lib/ruby-manta/manta_client.rb', line 367

def delete_directory(dir_path, opts = {})
  url     = obj_url(dir_path)
  headers = gen_headers(opts)

  attempt(opts[:attempts]) do
    result = @client.delete(url, nil, headers)
    raise unless result.is_a? HTTP::Message

    return true, result.headers if result.status == 204
    raise_error(result)
  end
end

#delete_object(obj_path, opts = {}) ⇒ Object

Deletes an object off Manta at a given path.

The path must start with /<user>/stor or /<user/public and point at an actual object.

Returns true along with received HTTP headers.

If there was an unrecoverable error, throws an exception. On connection or corruption errors, more attempts will be made; the number of attempts can be altered by passing in :attempts.



217
218
219
220
221
222
223
224
225
226
227
228
# File 'lib/ruby-manta/manta_client.rb', line 217

def delete_object(obj_path, opts = {})
  url     = obj_url(obj_path)
  headers = gen_headers(opts)

  attempt(opts[:attempts]) do
    result = @client.delete(url, nil, headers)
    raise unless result.is_a? HTTP::Message

    return true, result.headers if result.status == 204
    raise_error(result)
  end
end

#end_job_input(job_path, opts = {}) ⇒ Object

Inform Manta that no more objects will be added for processing by a job, and that the job should finish all phases and terminate.

The job_path must start with /<user>/jobs/<job UUID> and point at an actual running job.

Returns true, along with received HTTP headers.

If there was an unrecoverable error, throws an exception. On connection or corruption errors, more attempts will be made; the number of attempts can be altered by passing in :attempts.



596
597
598
599
600
601
602
603
604
605
606
607
# File 'lib/ruby-manta/manta_client.rb', line 596

def end_job_input(job_path, opts = {})
  url     = job_url(job_path, '/live/in/end')
  headers = gen_headers(opts)

  attempt(opts[:attempts]) do
    result = @client.post(url, nil, headers)
    raise unless result.is_a? HTTP::Message

    return true, result.headers if result.status == 202
    raise_error(result)
  end
end

#find(dir_path, opts = {}) ⇒ Object

Finds all objects recursively under a given directory. Optionally, a regular expression can be specified and used to filter the results returned.



318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
# File 'lib/ruby-manta/manta_client.rb', line 318

def find(dir_path, opts = {})
  regex = opts.key?(:regex) ? opts[:regex] : nil

  # We should always be doing GET because switching between methods is used
  # within this function.
  opts.delete(:head)

  begin
    exists = list_directory(dir_path, head: true).first
  rescue
    exists = false
  end

  return [] unless exists

  response = list_directory(dir_path, opts)
  listing = response.first

  listing.inject([]) do |memo, obj|
    if obj['type'] == 'directory'
      sub_dir = "#{dir_path}/#{obj['name']}"
      sub_search = find(sub_dir, regex: regex)
      memo.push(*sub_search)
    end

    if obj['type'] == 'object'
      file = "#{dir_path}/#{obj['name']}"

      if !regex || obj['name'].match(regex)
        memo.push file
      end
    end

    memo
  end
end

#gen_signed_url(expires, method, path, args = []) ⇒ Object

Generates a signed URL which can be used by unauthenticated users to make a request to Manta at the given path. This is typically used to GET an object, or to make a CORS preflighted PUT request.

expires is a Time object or integer representing time after epoch; this determines how long the signed URL will be valid for. The method is either a single HTTP method (:get, :put, :post, :delete, :options) or a list of such methods that the signed URL is allowed to be used for. The path must start with /<user>/stor. Lastly, the optional args is an array containing pairs of query args that will be appended at the end of the URL.

The returned URL is signed, and can be used either over HTTP or HTTPS until it reaches the expiry date.

Raises:

  • (ArgumentError)


717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
# File 'lib/ruby-manta/manta_client.rb', line 717

def gen_signed_url(expires, method, path, args=[])
  methods = method.is_a?(Array) ? method : [method]
  raise ArgumentError unless (methods - [:get, :put, :post, :delete, :options]).empty?
  raise ArgumentError unless path =~ OBJ_PATH_REGEX

  key_id = '/%s/keys/%s' % [user_path, @fingerprint]

  args.push([ 'expires',   expires.to_i ])
  args.push([ 'algorithm', @digest_name ])
  args.push([ 'keyId',     key_id       ])

  method = methods.map {|m| m.to_s.upcase }.sort.join(",")
  host   = URI.encode(@host.split('/').last)
  path   = URI.encode(path)

  args.push(['method', method]) if methods.count > 1

  encoded_args = args.sort.map do |key, val|
    # to comply with RFC 3986
    CGI.escape(key.to_s) + '=' + CGI.escape(val.to_s)
  end.join('&')

  plaintext = "#{method}\n#{host}\n#{path}\n#{encoded_args}"
  signature = @priv_key.sign(@digest, plaintext)
  encoded_signature = CGI.escape(Base64.strict_encode64(signature))

  host + path + '?' + encoded_args + '&signature=' + encoded_signature
end

#get_job(job_path, opts = {}) ⇒ Object

Gets various information about a job in Manta at a given path.

The path must start with /<user>/jobs/<job UUID> and point at an actual job. :head => true can optionally be passed in to do a HEAD instead of a GET.

Returns a hash with job information, along with received HTTP headers.

If there was an unrecoverable error, throws an exception. On connection or corruption errors, more attempts will be made; the number of attempts can be altered by passing in :attempts.



454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
# File 'lib/ruby-manta/manta_client.rb', line 454

def get_job(job_path, opts = {})
  url     = job_url(job_path, '/live/status')
  headers = gen_headers(opts)

  attempt(opts[:attempts]) do
    method = opts[:head] ? :head : :get
    result = @client.send(method, url, nil, headers)
    raise unless result.is_a? HTTP::Message

    if result.status == 200
      raise unless result.headers['Content-Type'] == 'application/json'

      return true, result.headers if method == :head

      job = JSON.parse(result.body)
      return job, result.headers
    end

    raise_error(result)
  end
end

#get_job_errors(job_path, opts = {}) ⇒ Object

Gets errors that occured during the execution of a job in Manta at a given path.

The path must start with /<user>/jobs/<job UUID> and point at an actual job. :head => true can optionally be passed in to do a HEAD instead of a GET.

Returns an array of hashes, each hash containing information about an error; this information is best-effort by Manta, so it may not be complete. Also returns received HTTP headers.

If there was an unrecoverable error, throws an exception. On connection or corruption errors, more attempts will be made; the number of attempts can be altered by passing in :attempts.



491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
# File 'lib/ruby-manta/manta_client.rb', line 491

def get_job_errors(job_path, opts = {})
  url     = job_url(job_path, '/live/err')
  headers = gen_headers(opts)

  attempt(opts[:attempts]) do
    method = opts[:head] ? :head : :get
    result = @client.send(method, url, nil, headers)
    raise unless result.is_a? HTTP::Message

    if result.status == 200
      raise unless result.headers['Content-Type'] ==
                   'application/x-json-stream; type=job-error'

      return true, result.headers if method == :head

      json_chunks = result.body.split("\n")
      errors = json_chunks.map { |i| JSON.parse(i) }

      return errors, result.headers
    end

    raise_error(result)
  end
end

#get_job_failures(job_path, opts = {}) ⇒ Object

Get a list of objects that had failures during processing in a Manta job.

The job_path must start with /<user>/jobs/<job UUID> and point at an actual running job.

Returns an array of object paths, along with received HTTP headers.

If there was an unrecoverable error, throws an exception. On connection or corruption errors, more attempts will be made; the number of attempts can be altered by passing in :attempts.



654
655
656
# File 'lib/ruby-manta/manta_client.rb', line 654

def get_job_failures(job_path, opts = {})
  get_job_state_streams(:fail, job_path, opts)
end

#get_job_input(job_path, opts = {}) ⇒ Object

Get a list of objects that have been given to a Manta job for processing.

The job_path must start with /<user>/jobs/<job UUID> and point at an actual running job.

Returns an array of object paths, along with received HTTP headers.

If there was an unrecoverable error, throws an exception. On connection or corruption errors, more attempts will be made; the number of attempts can be altered by passing in :attempts.



621
622
623
# File 'lib/ruby-manta/manta_client.rb', line 621

def get_job_input(job_path, opts = {})
  get_job_state_streams(:in, job_path, opts)
end

#get_job_output(job_path, opts = {}) ⇒ Object

Get a list of objects that contain the intermediate results of a running Manta job.

The job_path must start with /<user>/jobs/<job UUID> and point at an actual running job.

Returns an array of object paths, along with received HTTP headers.

If there was an unrecoverable error, throws an exception. On connection or corruption errors, more attempts will be made; the number of attempts can be altered by passing in :attempts.



638
639
640
# File 'lib/ruby-manta/manta_client.rb', line 638

def get_job_output(job_path, opts = {})
  get_job_state_streams(:out, job_path, opts)
end

#get_object(obj_path, opts = {}) ⇒ Object

Get an object from Manta at a given path, and checks it’s uncorrupted.

The path must start with /<user>/stor or /<user/public and point at an actual object, as well as output objects for jobs. :head => true can optionally be passed in to do a HEAD instead of a GET.

Returns the retrieved data along with received HTTP headers.

If there was an unrecoverable error, throws an exception. On connection or corruption errors, more attempts will be made; the number of attempts can be altered by passing in :attempts.



180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/ruby-manta/manta_client.rb', line 180

def get_object(obj_path, opts = {})
  url     = obj_url(obj_path)
  headers = gen_headers(opts)

  attempt(opts[:attempts]) do
    method = opts[:head] ? :head : :get
    result = @client.send(method, url, nil, headers)
    raise unless result.is_a? HTTP::Message

    if result.status == 200
      return true, result.headers if method == :head

      sent_md5     = result.headers['Content-MD5']
      received_md5 = Digest::MD5.base64digest(result.body)
      raise CorruptResult if sent_md5 != received_md5

      return result.body, result.headers
    elsif result.status == 304
      return nil, result.headers
    end

    raise_error(result)
  end
end

#list_directory(dir_path, opts = {}) ⇒ Object

Gets a lexicographically sorted directory listing on Manta at a given path,

The path must start with /<user>/stor or /<user/public and point at an actual directory. :limit optionally changes the maximum number of entries; the default is 1000. If given :marker, an object name in the directory, returned directory entries will begin from that point. :head => true can optionally be passed in to do a HEAD instead of a GET.

Returns an array of hash objects, each object representing a directory entry. Also returns the received HTTP headers.

If there was an unrecoverable error, throws an exception. On connection or corruption errors, more attempts will be made; the number of attempts can be altered by passing in :attempts.

Raises:

  • (ArgumentError)


274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
# File 'lib/ruby-manta/manta_client.rb', line 274

def list_directory(dir_path, opts = {})
  url     = obj_url(dir_path)
  headers = gen_headers(opts)
  query_parameters = {}

  limit = opts[:limit] || MAX_LIMIT
  raise ArgumentError unless 0 < limit && limit <= MAX_LIMIT
  query_parameters[:limit] = limit

  marker = opts[:marker]
  if marker
    raise ArgumentError unless marker.is_a? String
    query_parameters[:marker] = marker
  end

  attempt(opts[:attempts]) do
    method = opts[:head] ? :head : :get
    result = @client.send(method, url, query_parameters, headers)
    raise unless result.is_a? HTTP::Message

    if result.status == 200
      raise unless result.headers['Content-Type'] ==
                   'application/x-json-stream; type=directory'

      return true, result.headers if method == :head

      json_chunks = result.body.split("\n")

      if json_chunks.size > limit
        raise CorruptResult
      end

      dir_entries = json_chunks.map { |i| JSON.parse(i) }

      return dir_entries, result.headers
    end

    raise_error(result)
  end
end

#list_jobs(state, opts = {}) ⇒ Object

Get lists of Manta jobs.

The state indicates which kind of jobs to return. :running is for jobs that are currently processing, :done and :all should be obvious. Be careful of the latter two if you’ve run a lot of jobs – the list could be quite long.

Returns an array of hashes, each hash containing some information about a job. Also returns received HTTP headers.

If there was an unrecoverable error, throws an exception. On connection or corruption errors, more attempts will be made; the number of attempts can be altered by passing in :attempts.

Raises:

  • (ArgumentError)


673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
# File 'lib/ruby-manta/manta_client.rb', line 673

def list_jobs(state, opts = {})
  raise ArgumentError unless [:all, :running, :done].include? state
  state = nil if state == :all

  headers = gen_headers(opts)

  attempt(opts[:attempts]) do
  #      method = opts[:head] ? :head : :get
    method = :get # until added to Manta service
    result = @client.send(method, job_url(), { :state => state }, headers)
    raise unless result.is_a? HTTP::Message

    if result.status == 200
  #        return true, result.headers if method == :head
      return [],   result.headers if result.body.size == 0

      raise unless result.headers['Content-Type'] ==
                   'application/x-json-stream; type=job'

      json_chunks = result.body.split("\n")
      job_entries = json_chunks.map { |i| JSON.parse(i) }

      return job_entries, result.headers
    end

    raise_error(result)
  end
end

#put_directory(dir_path, opts = {}) ⇒ Object

Creates a directory on Manta at a given path.

The path must start with /<user>/stor or /<user/public.

Returns true along with received HTTP headers.

If there was an unrecoverable error, throws an exception. On connection or corruption errors, more attempts will be made; the number of attempts can be altered by passing in :attempts.



241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/ruby-manta/manta_client.rb', line 241

def put_directory(dir_path, opts = {})
  url = obj_url(dir_path)
  headers = gen_headers(opts)
  headers.push([ 'Content-Type', 'application/json; type=directory' ])

  cors_headers = gen_cors_headers(opts)
  headers = headers.concat(cors_headers)

  attempt(opts[:attempts]) do
    result = @client.put(url, nil, headers)
    raise unless result.is_a? HTTP::Message

    return true, result.headers if result.status == 204
    raise_error(result)
  end
end

#put_object(obj_path, data, opts = {}) ⇒ Object

Uploads object data to Manta to the given path, along with a computed MD5 hash.

The path must start with /<user>/stor or /<user/public. Data can be any sequence of octets. The HTTP Content-Type stored on Manta can be set with an optional :content_type argument; the default is application/octet-stream. The number of distributed replicates of an object stored in Manta can be set with an optional :durability_level; the default is 2.

Returns true along with received HTTP headers.

If there was an unrecoverable error, throws an exception. On connection or corruption errors, more attempts will be made; the number of attempts can be altered by passing in :attempts.



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/ruby-manta/manta_client.rb', line 137

def put_object(obj_path, data, opts = {})
  url = obj_url(obj_path)

  opts[:data] = data
  headers = gen_headers(opts)

  cors_headers = gen_cors_headers(opts)
  headers = headers.concat(cors_headers)

  durability_level = opts[:durability_level]
  if durability_level
    raise ArgumentError unless durability_level > 0
    headers.push([ 'Durability-Level', durability_level ])
  end

  content_type = opts[:content_type]
  if content_type
    raise ArgumentError unless content_type.is_a? String
    headers.push([ 'Content-Type', content_type ])
  end

  attempt(opts[:attempts]) do
    result = @client.put(url, data, headers)
    raise unless result.is_a? HTTP::Message

    return true, result.headers if [204, 304].include? result.status
    raise_error(result)
  end
end

Creates a snaplink from one object in Manta at a given path to a different path.

Both paths should start with /<user>/stor or /<user/public.

Returns true along with received HTTP headers.

If there was an unrecoverable error, throws an exception. On connection or corruption errors, more attempts will be made; the number of attempts can be altered by passing in :attempts.



392
393
394
395
396
397
398
399
400
401
402
403
404
# File 'lib/ruby-manta/manta_client.rb', line 392

def put_snaplink(orig_path, link_path, opts = {})
  headers = gen_headers(opts)
  headers.push([ 'Content-Type', 'application/json; type=link' ],
               [ 'Location',     obj_url(orig_path)            ])

  attempt(opts[:attempts]) do
    result = @client.put(obj_url(link_path), nil, headers)
    raise unless result.is_a? HTTP::Message

    return true, result.headers if result.status == 204
    raise_error(result)
  end
end

#user_pathObject

Creates a qualified user path consisting of the user and subuser if the subuser is present. Otherwise, it returns the user



758
759
760
# File 'lib/ruby-manta/manta_client.rb', line 758

def user_path
  @subuser ? "#{@user}/#{@subuser}" : @user
end