Class: Wash::Entry

Inherits:
Object
  • Object
show all
Defined in:
lib/wash/entry.rb

Overview

Entry represents a common base class for Wash entries. All plugin entries should extend this class.

Constant Summary collapse

VOLUMEFS =

Name of the volume filesystem type in Wash. Use with ‘parent_of` when returning `volumefs` in your `list` method.

'__volume::fs__'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#nameObject

All entries have a name. Note that the name is always included in the entry’s state hash.



251
252
253
# File 'lib/wash/entry.rb', line 251

def name
  @name
end

#partial_metadataObject

Contains the entry’s partial metadata.



254
255
256
# File 'lib/wash/entry.rb', line 254

def 
  @partial_metadata
end

Class Method Details

.attributes(attr, *attrs) ⇒ Object

attributes is a class-level tag specifying all the attributes that make sense for instances of this specific kind of entry. It will pass the specified attributes along to attr_accessor so that instances can set their values. For example, something like

Examples:

class Foo
  # Instances of Foo will be able to set the @mtime and @size fields
  attributes :mtime, :size

  def initialize(mtime, size)
    @mtime = mtime
    @size = size
  end
end

Parameters:

  • attr (Symbol)

    An attribute that will be set

  • attrs (Symbol)

    More attributes that will be set



26
27
28
29
# File 'lib/wash/entry.rb', line 26

def attributes(attr, *attrs)
  @attributes ||= []
  @attributes += set_fields(attr, *attrs)
end

.childrenObject

children returns this Entry’s child classes. It is a helper for Entry schemas, and is useful for DRY’ing up schema code when one kind of Entry’s children matches another kind of Entry’s children.

Examples:

class VolumeDir
  parent_of 'VolumeDir', 'VolumeFile'
end

class Volume
  parent_of *VolumeDir.children
end


169
170
171
# File 'lib/wash/entry.rb', line 169

def children
  @child_klasses
end

.description(description) ⇒ Object

description is a class-level tag specifying the entry’s description. It is a helper for Entry schemas.

Parameters:

  • description

    The description.



107
108
109
# File 'lib/wash/entry.rb', line 107

def description(description)
  @description = description
end

.is_singletonObject

is_singleton is a class-level tag indicating that the given Entry’s a singleton. It is a helper for Entry schemas.

Note that if an Entry has the is_singleton tag and its name is not filled-in when that Entry is listed, then the Entry’s name will be set to the specified label. This means that plugin authors do not have to set singleton entries’ names, and it also enforces the convention that singleton entries’ labels should match their names.

Examples:

class Foo
  label 'foo'
  # If Foo's instance does not set @name, then the gem will set @name to 'foo'
  is_singleton
end


99
100
101
# File 'lib/wash/entry.rb', line 99

def is_singleton
  @singleton = true
end

.label(lbl) ⇒ Object

label is a class-level tag specifying the entry’s label. It is a helper for Entry schemas.

Parameters:

  • lbl

    The label.



80
81
82
# File 'lib/wash/entry.rb', line 80

def label(lbl)
  @label = lbl
end

.metadata_schema(schema) ⇒ Object

metadata_schema sets the metadata schema to schema. It is a helper for Entry schemas.

Parameters:

  • schema

    A hash containing the metadata’s JSON schema



134
135
136
# File 'lib/wash/entry.rb', line 134

def (schema)
  @metadata_schema = schema
end

.parent_of(child_klass, *child_klasses) ⇒ Object

parent_of indicates that this kind of Entry is the parent of the given child classes (i.e. child entries). It is a helper for Entry schemas.

Examples:

class Foo
  # This indicates that Foo#list will return instances of Bar and Baz. Note
  # that both direct class constants (Bar) and strings ('Baz') are valid
  # input. The latter's useful when the child class is loaded after the
  # parent.
  parent_of Bar, 'Baz'
end

Parameters:

  • child_klass (Wash::Entry)

    A child class object.

  • child_klasses (Wash::Entry)

    More child class objects.



152
153
154
155
# File 'lib/wash/entry.rb', line 152

def parent_of(child_klass, *child_klasses)
  @child_klasses ||= []
  @child_klasses += [child_klass] + child_klasses
end

.partial_metadata_schema(schema) ⇒ Object

partial_metadata_schema sets the partial metadata’s schema to schema. It is a helper for Entry schemas.

Parameters:

  • schema

    A hash containing the partial metadata’s JSON schema



127
128
129
# File 'lib/wash/entry.rb', line 127

def (schema)
  @partial_metadata_schema = schema
end

.signal(name, description) ⇒ Object

signal adds the given signal to the entry’s list of supported signals. It is a helper for Entry schemas.



113
114
115
# File 'lib/wash/entry.rb', line 113

def signal(name, description)
  add_signal_schema(name, '', description)
end

.signal_group(name, regex, description) ⇒ Object

signal_group adds the given signal group to the entry’s list of supported signals. It is a helper for Entry schemas.



119
120
121
# File 'lib/wash/entry.rb', line 119

def signal_group(name, regex, description)
  add_signal_schema(name, regex, description)
end

.slash_replacer(char) ⇒ Object

slash_replacer is a class-level tag that specifies the slash replacer. It should only be used if there is a chance that instances of the given class can contain a “#” in their names. Otherwise, slash_replacer should be ignored.

Examples:

class Foo
  # Tell Wash to replace all "/"es with ":" in the given Foo instance's
  # name
  slash_replacer ":"
end

Parameters:

  • char (String)

    The slash replacer



44
45
46
# File 'lib/wash/entry.rb', line 44

def slash_replacer(char)
  @slash_replacer = char
end

.state(field, *fields) ⇒ Object

state is a class-level tag that specifies the minimum state required to reconstruct all instances of this specific kind of entry. Each specified state field will be passed along to attr_accessor so that instances can get/set their values.

Note that Wash.run uses Class#allocate when it reconstructs the entries, so it does not call the initialize method.

Examples:

class Foo
  # Indicates that api_key is the minimum state required to reconstruct
  # instances of Foo. The gem will serialize the api_key as part of each
  # instance's state key when passing them along to Wash. If Wash invokes
  # a method on a specific instance, then Wash.run will restore the api_key
  # prior to invoking the method (so all methods are free to directly reference
  # the @api_key field). Thus, plugin authors do not have to manage their entries'
  # states; the gem will do it for them via the state tag.
  state :api_key

  def initialize(api_key)
    @api_key = api_key
  end
end


71
72
73
74
# File 'lib/wash/entry.rb', line 71

def state(field, *fields)
  @state ||= []
  @state += set_fields(field, *fields)
end

Instance Method Details

#cache_ttls(ttls = {}) ⇒ Object

cache_ttls sets the cache TTLs (time-to-live) of the given methods.

Examples:

class Foo
  def initialize(content_size)
    if content_size > 10000
      # content_size > 10000 so tell Wash to cache its read result for
      # 100 seconds
      cache_ttls read: 100 
    end
  end
end

Parameters:

  • ttls (Hash) (defaults to: {})

    A hash of <method_name> => <method_ttl>



352
353
354
355
# File 'lib/wash/entry.rb', line 352

def cache_ttls(ttls = {})
  @cache_ttls ||= {}
  @cache_ttls = @cache_ttls.merge(ttls)
end

#prefetch(method, *methods) ⇒ Object

prefetch indicates that the given methods should be prefetched. This means that the gem will invoke those methods on this particular entry instance and include their results when serializing that entry. Note that the methods are invoked during serialization.

Examples:

class Foo
  def initialize(content_size)
    if content_size < 10
      # content_size < 10, so tell the gem to invoke Foo#list and Foo#read
      # on this Foo instance during its serialization
      prefetch :list, :read
    end
  end
end

Parameters:

  • method (Symbol)

    A method that should be prefetched.

  • methods (Symbol)

    More methods that should be prefetched.



334
335
336
# File 'lib/wash/entry.rb', line 334

def prefetch(method, *methods)
  prefetched_methods.concat([method] + methods)
end

#schemaObject

schema returns the entry’s schema. It should not be overridden.



401
402
403
404
405
# File 'lib/wash/entry.rb', line 401

def schema
  schemaHash = {}
  self.class.send(:schema, schemaHash)
  schemaHash
end

#to_json(jstate = {}) ⇒ Object



256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
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
# File 'lib/wash/entry.rb', line 256

def to_json(jstate = {})
  unless @name && @name.size > 0
    unless singleton
      raise "A nameless entry is being serialized. The entry is an instance of #{type_id}"
    end
    @name = label
  end

  hash = {
    type_id: type_id,
    name: @name,
  }

  # Include the methods
  hash[:methods] = self.class.send(:methods).map do |method|
    if prefetched_methods.include?(method)
      [method, self.send(method)]
    elsif method == :read
      # Check if this entry is block-readable
      #
      # TODO: Generalize this to lib/wash/method.rb if Wash starts
      # supporting more overloaded methods
      block_readable = self.method(:read).arity > 0
      [:read, block_readable]
    elsif method == :exec && @transport
      [:exec, { transport: @transport[0], options: @transport[1] }]
    else
      method
    end
  end

  # Include the remaining keys. Note that these checks are here to
  # ensure that we don't serialize empty keys. They're meant to save
  # some space.
  if attributes.size > 0 && (attributes_hash = to_hash(attributes))
    hash[:attributes] = attributes_hash
  end
  if @partial_metadata
    hash[:partial_metadata] = @partial_metadata
  end
  if cache_ttls.size > 0
    hash[:cache_ttls] = cache_ttls
  end
  if slash_replacer.size > 0
    hash[:slash_replacer] = slash_replacer
  end
  hash[:state] = to_hash(state).merge(klass: type_id, name: @name).to_json
  if Wash.send(:pretty_print?)
    JSON.pretty_generate(hash, jstate)
  else
    JSON.generate(hash, jstate)
  end
end

#transport(klass, options = {}) ⇒ Object

transport requests that Wash use a built-in transport with the supplied transport options to implement Exec. When using this feature, you must also declare the ‘exec’ method so it’s included in the schema. You may use this to implement a fallback implementation for entries where the transport feature is not used.

Examples:

class Foo
  def initialize(name)
    transport :ssh, host: name, user: 'root'
  end

  def exec
    raise 'implemented by transport'
  end
end

Parameters:

  • klass (Symbol)

    The transport to use. Only ‘:ssh` is supported

  • options (Hash) (defaults to: {})

    For SSH: :host (required), :user, :fallback_user, :password, :identity_file, :known_hosts, :host_key_alias, :retries, :port



396
397
398
# File 'lib/wash/entry.rb', line 396

def transport(klass, options = {})
  @transport = [klass, options]
end

#type_idObject

type_id returns the entry’s type ID, which is its fully-qualified class name.



312
313
314
# File 'lib/wash/entry.rb', line 312

def type_id
  self.class.send(:type_id)
end

#volumefs(name, options = {}) ⇒ Object

volumefs creates the ‘volume::fs` entry as specified in Wash’s external plugin docs.

Examples:

class Foo
  parent_of VOLUMEFS
  def list
    [volumefs('fs', maxdepth: 5), Bar.new]
  end
end

Parameters:

  • name (String)

    The name to use for the child representing the remote filesystem.

  • options (Hash) (defaults to: {})

    Options to configure the filesystem.

    • maxdepth: How deep to walk the remote filesystem when needed. This is a trade-off between speed of the transport and filesystem complexity. For fast transports it should be low (1-3), for slower transports higher (3-6).



372
373
374
# File 'lib/wash/entry.rb', line 372

def volumefs(name, options = {})
  { type_id: VOLUMEFS, name: name, state: options.to_json }
end