Class: ChefAPI::Resource::Base

Inherits:
Object
  • Object
show all
Extended by:
Enumerable
Defined in:
lib/chef-api/resources/base.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(attributes = {}, prefix = {}) {|_self| ... } ⇒ Base

Initialize a new resource with the given attributes. These attributes are merged with the default values from the schema. Any attributes that aren't defined in the schema are silently ignored for security purposes.

Examples:

create a resource using attributes

Bacon.new(foo: 'bar', zip: 'zap') #=> #<ChefAPI::Resource::Bacon>

using a block

Bacon.new do |bacon|
  bacon.foo = 'bar'
  bacon.zip = 'zap'
end

Parameters:

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

    the list of initial attributes to set on the model

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

    the list of prefix options (for nested resources)

Yields:

  • (_self)

Yield Parameters:


556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
# File 'lib/chef-api/resources/base.rb', line 556

def initialize(attributes = {}, prefix = {})
  @schema = self.class.schema.dup
  @schema.load_flavor(self.class.connection.flavor)

  @associations = {}
  @_prefix      = prefix

  # Define a getter and setter method for each attribute in the schema
  _attributes.each do |key, value|
    define_singleton_method(key) { _attributes[key] }
    define_singleton_method("#{key}=") { |value| update_attribute(key, value) }
  end

  attributes.each do |key, value|
    unless ignore_attribute?(key)
      update_attribute(key, value)
    end
  end

  yield self if block_given?
end

Instance Attribute Details

#associationsHash (readonly)

The list of associations.

Returns:

  • (Hash)

534
535
536
# File 'lib/chef-api/resources/base.rb', line 534

def associations
  @associations
end

Class Method Details

.allArray<Resource::Base>

Note:

Unless you need the entire collection, please consider using the

Return an array of all resources in the collection.

size and each methods instead as they are much more perforant.

Returns:


391
392
393
# File 'lib/chef-api/resources/base.rb', line 391

def all
  entries
end

.build(attributes = {}, prefix = {}) ⇒ Object

Build a new resource from the given attributes.

Examples:

build an empty resource

Bacon.build #=> #<ChefAPI::Resource::Bacon>

build a resource with attributes

Bacon.build(foo: 'bar') #=> #<ChefAPI::Resource::Baocn foo: bar>

Parameters:

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

    the list of attributes for the new resource - any attributes that are not defined in the schema are silently ignored

See Also:


273
274
275
# File 'lib/chef-api/resources/base.rb', line 273

def build(attributes = {}, prefix = {})
  new(attributes, prefix)
end

.classnameString

The name for this resource, minus the parent module.

Examples:

classname #=> Resource::Bacon

Returns:

  • (String)

446
447
448
# File 'lib/chef-api/resources/base.rb', line 446

def classname
  name.split('::')[1..-1].join('::')
end

.collection(prefix = {}) ⇒ Array<Resource::Base>

The full collection list.

Parameters:

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

    any prefix options to use

Returns:


471
472
473
# File 'lib/chef-api/resources/base.rb', line 471

def collection(prefix = {})
  connection.get(expanded_collection_path(prefix))
end

.collection_path(value = UNSET) ⇒ Symbol, String

Get or set the name of the remote resource collection. This is most likely the remote API endpoint (such as /clients), without the leading slash.

Examples:

Setting a base collection path

collection_path '/clients'

Setting a collection path with nesting

collection_path '/data/:name'

Parameters:

  • value (Symbol) (defaults to: UNSET)

    the value to use for the collection name.

Returns:

  • (Symbol, String)

    the name of the collection


116
117
118
119
120
121
122
123
# File 'lib/chef-api/resources/base.rb', line 116

def collection_path(value = UNSET)
  if value != UNSET
    @collection_path = value.to_s
  else
    @collection_path ||
      raise(ArgumentError, "collection_path not set for #{self.class}")
  end
end

.connectionChefAPI::Connection

The current connection object.

Returns:


524
525
526
# File 'lib/chef-api/resources/base.rb', line 524

def connection
  Thread.current['chefapi.connection'] || ChefAPI.connection
end

.count(prefix = {}) ⇒ Fixnum Also known as: size

The total number of reosurces in the collection.

Returns:

  • (Fixnum)

378
379
380
# File 'lib/chef-api/resources/base.rb', line 378

def count(prefix = {})
  collection(prefix).size
end

.create(attributes = {}, prefix = {}) ⇒ Resource::Base

Create a new resource and save it to the Chef Server, raising any exceptions that might occur. This method will save the resource back to the Chef Server, raising any validation errors that occur.

Parameters:

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

    the list of attributes to set on the new resource

Returns:

Raises:


293
294
295
296
297
298
299
300
301
302
# File 'lib/chef-api/resources/base.rb', line 293

def create(attributes = {}, prefix = {})
  resource = build(attributes, prefix)

  unless resource.new_resource?
    raise Error::ResourceAlreadyExists.new
  end

  resource.save!
  resource
end

.delete(id, prefix = {}) ⇒ true

Delete the remote resource from the Chef Sserver.

Parameters:

  • id (String, Fixnum)

    the id of the resource to delete

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

    the list of prefix options (for nested resources)

Returns:

  • (true)

174
175
176
177
178
179
180
# File 'lib/chef-api/resources/base.rb', line 174

def delete(id, prefix = {})
  path = resource_path(id, prefix)
  connection.delete(path)
  true
rescue Error::HTTPNotFound
  true
end

.destroy(id, prefix = {}) ⇒ Base?

Destroy a record with the given id.

Parameters:

  • id (String, Fixnum)

    the id of the resource to delete

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

    the list of prefix options (for nested resources)

Returns:

  • (Base, nil)

    the destroyed resource, or nil if the resource does not exist on the remote Chef Server


213
214
215
216
217
218
219
# File 'lib/chef-api/resources/base.rb', line 213

def destroy(id, prefix = {})
  resource = fetch(id, prefix)
  return nil if resource.nil?

  resource.destroy
  resource
end

.destroy_all(prefix = {}) ⇒ Array<Base>

Delete all remote resources of the given type from the Chef Server

Parameters:

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

    the list of prefix options (for nested resources)

Returns:

  • (Array<Base>)

    an array containing the list of resources that were deleted


229
230
231
# File 'lib/chef-api/resources/base.rb', line 229

def destroy_all(prefix = {})
  map { |resource| resource.destroy }
end

.each(prefix = {}, &block) ⇒ Object

(Lazy) iterate over each item in the collection, yielding the fully- built resource object. This method, coupled with the Enumerable module, provides us with other methods like first and map.

Examples:

get the first resource

Bacon.first #=> #<ChefAPI::Resource::Bacon>

get the first 3 resources

Bacon.first(3) #=> [#<ChefAPI::Resource::Bacon>, ...]

iterate over each resource

Bacon.each { |bacon| puts bacon.name }

get all the resource's names

Bacon.map(&:name) #=> ["ham", "sausage", "turkey"]

364
365
366
367
368
369
370
371
# File 'lib/chef-api/resources/base.rb', line 364

def each(prefix = {}, &block)
  collection(prefix).each do |resource, path|
    response = connection.get(path)
    result = from_json(response, prefix)

    block.call(result) if block
  end
end

.exists?(id, prefix = {}) ⇒ Boolean

Check if the given resource exists on the Chef Server.

Parameters:

  • id (String, Fixnum)

    the id of the resource to fetch

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

    the list of prefix options (for nested resources)

Returns:


314
315
316
# File 'lib/chef-api/resources/base.rb', line 314

def exists?(id, prefix = {})
  !fetch(id, prefix).nil?
end

.expanded_collection_path(prefix = {}) ⇒ String

Expand the collection path, “interpolating” any parameters. This syntax is heavily borrowed from Rails and it will make more sense by looking at an example.

Examples:

/bacon, {} #=> "foo"
/bacon/:type, { type: 'crispy' } #=> "bacon/crispy"

Parameters:

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

    the list of prefix options

Returns:

  • (String)

    the “interpolated” URL string

Raises:


506
507
508
509
510
511
512
513
514
515
516
517
# File 'lib/chef-api/resources/base.rb', line 506

def expanded_collection_path(prefix = {})
  collection_path.gsub(/:\w+/) do |param|
    key = param.delete(':')
    value = prefix[key] || prefix[key.to_sym]

    if value.nil?
      raise Error::MissingURLParameter.new(param: key)
    end

    URI.escape(value)
  end.sub(/^\//, '') # Remove leading slash
end

.fetch(id, prefix = {}) ⇒ Resource::Base?

Fetch a single resource in the remote collection.

Examples:

fetch a single client

Client.fetch('chef-webui') #=> #<Client name: 'chef-webui', ...>

Parameters:

  • id (String, Fixnum)

    the id of the resource to fetch

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

    the list of prefix options (for nested resources)

Returns:

  • (Resource::Base, nil)

    an instance of the resource, or nil if that given resource does not exist


248
249
250
251
252
253
254
255
256
# File 'lib/chef-api/resources/base.rb', line 248

def fetch(id, prefix = {})
  return nil if id.nil?

  path     = resource_path(id, prefix)
  response = connection.get(path)
  from_json(response, prefix)
rescue Error::HTTPNotFound
  nil
end

.from_file(path) ⇒ Object

Load the given resource from it's on-disk equivalent. This action only makes sense for some resources, and must be defined on a per-resource basis, since the logic varies between resources.

Parameters:

  • path (String)

    the path to the file on disk

Raises:


15
16
17
# File 'lib/chef-api/resources/base.rb', line 15

def from_file(path)
  raise Error::AbstractMethod.new(method: 'Resource::Base#from_file')
end

.from_json(response, prefix = {}) ⇒ Resource::Base

Construct the object from a JSON response. This method actually just delegates to the new method, but it removes some marshall data and whatnot from the response first.

Parameters:

  • response (String)

    the JSON response from the Chef Server

Returns:

  • (Resource::Base)

    an instance of the resource represented by this JSON


406
407
408
409
410
411
# File 'lib/chef-api/resources/base.rb', line 406

def from_json(response, prefix = {})
  response.delete('json_class')
  response.delete('chef_type')

  new(response, prefix)
end

.from_url(url, prefix = {}) ⇒ Object

TODO:

doc


22
23
24
# File 'lib/chef-api/resources/base.rb', line 22

def from_url(url, prefix = {})
  from_json(connection.get(url), prefix)
end

.has_many(method, options = {}) ⇒ Object

Create a nested relationship collection. The associated collection is cached on the class, reducing API requests.

Examples:

Create an association to environments


has_many :environments

Create an association with custom configuration


has_many :environments, class_name: 'Environment'

80
81
82
83
84
85
86
87
88
89
90
# File 'lib/chef-api/resources/base.rb', line 80

def has_many(method, options = {})
  class_name    = options[:class_name] || "Resource::#{Util.camelize(method).sub(/s$/, '')}"
  rest_endpoint = options[:rest_endpoint] || method

  class_eval <<-EOH, __FILE__, __LINE__ + 1
    def #{method}
      associations[:#{method}] ||=
        Resource::CollectionProxy.new(self, #{class_name}, '#{rest_endpoint}')
    end
  EOH
end

.inspectString

The detailed string representation of this class, including the full schema definition.

Examples:

for the Bacon class

Bacon.inspect #=> "Resource::Bacon(id, description, ...)"

Returns:

  • (String)

434
435
436
# File 'lib/chef-api/resources/base.rb', line 434

def inspect
  "#{classname}(#{schema.attributes.keys.join(', ')})"
end

.list(prefix = {}) ⇒ Array<String>

Get the “list” of items in this resource. This list contains the primary keys of all of the resources in this collection. This method is useful in CLI applications, because it only makes a single API request to gather this data.

Examples:

Get the list of all clients

Client.list #=> ['validator', 'chef-webui']

Parameters:

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

    the listof prefix options (for nested resources)

Returns:

  • (Array<String>)

196
197
198
199
# File 'lib/chef-api/resources/base.rb', line 196

def list(prefix = {})
  path = expanded_collection_path(prefix)
  connection.get(path).keys.sort
end

.post(body, prefix = {}) ⇒ String

Make an authenticated HTTP POST request using the connection object. This method returns a new object representing the response from the server, which should be merged with an existing object's attributes to reflect the newest state of the resource.

Parameters:

  • body (Hash)

    the request body to create the resource with (probably JSON)

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

    the list of prefix options (for nested resources)

Returns:

  • (String)

    the JSON response from the server


139
140
141
142
# File 'lib/chef-api/resources/base.rb', line 139

def post(body, prefix = {})
  path = expanded_collection_path(prefix)
  connection.post(path, body)
end

.protect(*ids) ⇒ Object

Protect one or more resources from being altered by the user. This is useful if there's an admin client or magical cookbook that you don't want users to modify.

Examples:

protect 'chef-webui', 'my-magical-validator'
protect ->(resource) { resource.name =~ /internal_(.+)/ }

Parameters:

  • ids (Array<String, Proc>)

    the list of “things” to protect


64
65
66
# File 'lib/chef-api/resources/base.rb', line 64

def protect(*ids)
  ids.each { |id| protected_resources << id }
end

.protected_resourcesObject

TODO:

doc


95
96
97
# File 'lib/chef-api/resources/base.rb', line 95

def protected_resources
  @protected_resources ||= []
end

.put(id, body, prefix = {}) ⇒ String

Perform a PUT request to the Chef Server against the given resource or resource identifier. The resource will be partially updated (this method doubles as PATCH) with the given parameters.

Parameters:

  • id (String, Resource::Base)

    a resource object or a string representing the unique identifier of the resource object to update

  • body (Hash)

    the request body to create the resource with (probably JSON)

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

    the list of prefix options (for nested resources)

Returns:

  • (String)

    the JSON response from the server


160
161
162
163
# File 'lib/chef-api/resources/base.rb', line 160

def put(id, body, prefix = {})
  path = resource_path(id, prefix)
  connection.put(path, body)
end

.resource_path(id, prefix = {}) ⇒ String

The path to an individual resource.

Parameters:

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

    the list of prefix options

Returns:

  • (String)

    the path to the resource


484
485
486
# File 'lib/chef-api/resources/base.rb', line 484

def resource_path(id, prefix = {})
  [expanded_collection_path(prefix), id].join('/')
end

.schema(&block) ⇒ Schema

Get or set the schema for the remote resource. You probably only want to call schema once with a block, because it will overwrite the existing schema (meaning entries are not merged). If a block is given, a new schema object is created, otherwise the current one is returned.

Examples:

schema do
  attribute :id, primary: true
  attribute :name, type: String, default: 'bacon'
  attribute :admin, type: Boolean, required: true
end

Returns:

  • (Schema)

    the schema object for this resource


42
43
44
45
46
47
48
# File 'lib/chef-api/resources/base.rb', line 42

def schema(&block)
  if block
    @schema = Schema.new(&block)
  else
    @schema
  end
end

.to_sString

The string representation of this class.

Examples:

for the Bacon class

Bacon.to_s #=> "Resource::Bacon"

Returns:

  • (String)

421
422
423
# File 'lib/chef-api/resources/base.rb', line 421

def to_s
  classname
end

.typeString

The type of this resource.

Examples:

bacon

Returns:

  • (String)

458
459
460
# File 'lib/chef-api/resources/base.rb', line 458

def type
  Util.underscore(name.split('::').last).gsub('_', ' ')
end

.update(id, attributes = {}, prefix = {}) ⇒ Resource::Base

Perform a PUT request to the Chef Server for the current resource, updating the given parameters. The parameters may be a full or partial resource update, as supported by the Chef Server.

Parameters:

  • id (String, Fixnum)

    the id of the resource to update

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

    the list of attributes to set on the new resource

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

    the list of prefix options (for nested resources)

Returns:

Raises:


336
337
338
339
340
341
342
343
344
345
# File 'lib/chef-api/resources/base.rb', line 336

def update(id, attributes = {}, prefix = {})
  resource = fetch(id, prefix)

  unless resource
    raise Error::ResourceNotFound.new(type: type, id: id)
  end

  resource.update(attributes).save
  resource
end

Instance Method Details

#_attributesHash<Symbol, Object>

The list of attributes on this resource.

Returns:

  • (Hash<Symbol, Object>)

609
610
611
# File 'lib/chef-api/resources/base.rb', line 609

def _attributes
  @_attributes ||= {}.merge(@schema.attributes)
end

#_prefixObject

TODO:

doc


600
601
602
# File 'lib/chef-api/resources/base.rb', line 600

def _prefix
  @_prefix
end

#attribute?(key) ⇒ Boolean

Determine if this resource has the given attribute.

Parameters:

  • key (Symbol, String)

    the attribute key to find

Returns:

  • (Boolean)

    true if the attribute exists, false otherwise


622
623
624
# File 'lib/chef-api/resources/base.rb', line 622

def attribute?(key)
  _attributes.has_key?(key.to_sym)
end

#destroyself

Remove the resource from the Chef Server.

Returns:

  • (self)

    the current instance of this object


718
719
720
721
# File 'lib/chef-api/resources/base.rb', line 718

def destroy
  self.class.delete(id, _prefix)
  self
end

#diffHash

Note:

This is a VERY expensive operation - use it sparringly!

Calculate a differential of the attributes on the local resource with it's remote Chef Server counterpart.

Examples:

when the local resource is in sync with the remote resource

bacon = Bacon.first
bacon.diff #=> {}

when the local resource differs from the remote resource

bacon = Bacon.first
bacon.description = "My new description"
bacon.diff #=> { :description => { :local => "My new description", :remote => "Old description" } }

Returns:

  • (Hash)

862
863
864
865
866
867
868
869
870
871
872
873
# File 'lib/chef-api/resources/base.rb', line 862

def diff
  diff = {}

  remote = self.class.fetch(id, _prefix) || self.class.new({}, _prefix)
  remote._attributes.each do |key, value|
    unless _attributes[key] == value
      diff[key] = { local: _attributes[key], remote: value }
    end
  end

  diff
end

#dirty?Boolean

Check if the local resource is in sync with the remote Chef Server. When a remote resource is updated, ChefAPI has no way of knowing it's cached resources are dirty unless additional requests are made against the remote Chef Server and diffs are compared.

Examples:

when the resource is out of sync with the remote Chef Server

bacon = Bacon.first
bacon.description = "I'm different, yeah, I'm different!"
bacon.dirty? #=> true

when the resource is in sync with the remote Chef Server

bacon = Bacon.first
bacon.dirty? #=> false

Returns:

  • (Boolean)

    true if the local resource has differing attributes from the same resource on the remote Chef Server, false otherwise


841
842
843
# File 'lib/chef-api/resources/base.rb', line 841

def dirty?
  new_resource? || !diff.empty?
end

#errorsErrorCollection

The collection of errors on the resource.

Returns:


907
908
909
# File 'lib/chef-api/resources/base.rb', line 907

def errors
  @errors ||= ErrorCollection.new
end

#idObject

The unique id for this resource.

Returns:

  • (Object)

593
594
595
# File 'lib/chef-api/resources/base.rb', line 593

def id
  _attributes[primary_key]
end

#ignore_attribute?(key) ⇒ Boolean

Determine if a given attribute should be ignored. Ignored attributes are defined at the schema level and are frozen.

Parameters:

  • key (Symbol)

    the attribute to check ignorance

Returns:


898
899
900
# File 'lib/chef-api/resources/base.rb', line 898

def ignore_attribute?(key)
  @schema.ignored_attributes.has_key?(key.to_sym)
end

#inspectString

Custom inspect method for easier readability.

Returns:

  • (String)

948
949
950
951
952
953
954
955
956
957
958
# File 'lib/chef-api/resources/base.rb', line 948

def inspect
  attrs = (_prefix).merge(_attributes).map do |key, value|
    if value.is_a?(String)
      "#{key}: #{Util.truncate(value, length: 50).inspect}"
    else
      "#{key}: #{value.inspect}"
    end
  end

  "#<#{self.class.classname} #{attrs.join(', ')}>"
end

#new_resource?Boolean

Check if this resource exists on the remote Chef Server. This is useful when determining if a resource should be saved or updated, since a resource must exist before it can be saved.

Examples:

when the resource does not exist on the remote Chef Server

bacon = Bacon.new
bacon.new_resource? #=> true

when the resource exists on the remote Chef Server

bacon = Bacon.first
bacon.new_resource? #=> false

Returns:

  • (Boolean)

    true if the resource exists on the remote Chef Server, false otherwise


818
819
820
# File 'lib/chef-api/resources/base.rb', line 818

def new_resource?
  !self.class.exists?(id, _prefix)
end

#primary_keySymbol

The primary key for the resource.

Returns:

  • (Symbol)

    the primary key for this resource


584
585
586
# File 'lib/chef-api/resources/base.rb', line 584

def primary_key
  @schema.primary_key
end

#protected?Boolean

Determine if this current resource is protected. Resources may be protected by name or by a Proc. A protected resource is one that should not be modified (i.e. created/updated/deleted) by the user. An example of a protected resource is the pivotal key or the chef-webui client.

Returns:


634
635
636
637
638
639
640
641
642
# File 'lib/chef-api/resources/base.rb', line 634

def protected?
  @protected ||= self.class.protected_resources.any? do |thing|
                   if thing.is_a?(Proc)
                     thing.call(self)
                   else
                     id == thing
                   end
                 end
end

#reload!self

Note:

This will remove any custom values you have set on the resource!

Reload (or reset) this object using the values currently stored on the remote server. This method will also clear any cached collection proxies so they will be reloaded the next time they are requested. If the remote record does not exist, no attributes are modified.

Returns:

  • (self)

    the instance of the reloaded record


655
656
657
658
659
660
661
662
663
664
665
666
# File 'lib/chef-api/resources/base.rb', line 655

def reload!
  associations.clear

  remote = self.class.fetch(id, _prefix)
  return self if remote.nil?

  remote._attributes.each do |key, value|
    update_attribute(key, value)
  end

  self
end

#resource_pathString

The URL for this resource on the Chef Server.

Examples:

Get the resource path for a resource

bacon = Bacon.first
bacon.resource_path #=> /bacons/crispy

Returns:

  • (String)

    the partial URL path segment


885
886
887
# File 'lib/chef-api/resources/base.rb', line 885

def resource_path
  self.class.resource_path(id, _prefix)
end

#saveBoolean

Commit the resource and any changes to the remote Chef Server. Any errors are gracefully handled and added to the resource's error collection for handling.

Returns:

  • (Boolean)

    true if the save was successfuly, false otherwise


706
707
708
709
710
# File 'lib/chef-api/resources/base.rb', line 706

def save
  save!
rescue
  false
end

#save!Boolean

Commit the resource and any changes to the remote Chef Server. Any errors will raise an exception in the main thread and the resource will not be committed back to the Chef Server.

Any response errors (such as server-side responses) that ChefAPI failed to account for in validations will also raise an exception.

Returns:

  • (Boolean)

    true if the resource was saved


679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
# File 'lib/chef-api/resources/base.rb', line 679

def save!
  validate!

  response = if new_resource?
               self.class.post(to_json, _prefix)
             else
               self.class.put(id, to_json, _prefix)
             end

  # Update our local copy with any partial information that was returned
  # from the server, ignoring an "bad" attributes that aren't defined in
  # our schema.
  response.each do |key, value|
    update_attribute(key, value) if attribute?(key)
  end

  true
end

#to_hashHash

The hash representation of this resource. All attributes are serialized and any values that respond to to_hash are also serialized.

Returns:

  • (Hash)

917
918
919
920
921
922
923
# File 'lib/chef-api/resources/base.rb', line 917

def to_hash
  {}.tap do |hash|
    _attributes.each do |key, value|
      hash[key] = value.respond_to?(:to_hash) ? value.to_hash : value
    end
  end
end

#to_jsonString

The JSON serialization of this resource.

Returns:

  • (String)

930
931
932
# File 'lib/chef-api/resources/base.rb', line 930

def to_json(*)
  JSON.fast_generate(to_hash)
end

#to_sString

Custom to_s method for easier readability.

Returns:

  • (String)

939
940
941
# File 'lib/chef-api/resources/base.rb', line 939

def to_s
  "#<#{self.class.classname} #{primary_key}: #{id.inspect}>"
end

#update(attributes = {}) ⇒ self

Update a subset of attributes on the current resource. This is a handy way to update multiple attributes at once.

Parameters:

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

    the list of attributes to update

Returns:

  • (self)

732
733
734
735
736
737
738
# File 'lib/chef-api/resources/base.rb', line 732

def update(attributes = {})
  attributes.each do |key, value|
    update_attribute(key, value)
  end

  self
end

#update_attribute(key, value) ⇒ Object

Update a single attribute in the attributes hash.

Raises:


745
746
747
748
749
750
751
# File 'lib/chef-api/resources/base.rb', line 745

def update_attribute(key, value)
  unless attribute?(key.to_sym)
    raise Error::UnknownAttribute.new(attribute: key)
  end

  _attributes[key.to_sym] = value
end

#valid?Boolean

Determine if the current resource is valid. This relies on the validations defined in the schema at initialization.

Returns:

  • (Boolean)

    true if the resource is valid, false otherwise


792
793
794
795
796
797
798
799
800
# File 'lib/chef-api/resources/base.rb', line 792

def valid?
  errors.clear

  validators.each do |validator|
    validator.validate(self)
  end

  errors.empty?
end

#validate!Boolean

Run all of this resource's validations, raising an exception if any validations fail.

Returns:

  • (Boolean)

    true if the validation was successful - this method will never return anything other than true because an exception is raised if validations fail

Raises:


776
777
778
779
780
781
782
783
# File 'lib/chef-api/resources/base.rb', line 776

def validate!
  unless valid?
    sentence = errors.full_messages.join(', ')
    raise Error::InvalidResource.new(errors: sentence)
  end

  true
end

#validatorsArray<~Validator::Base>

The list of validators for this resource. This is primarily set and managed by the underlying schema clean room.

Returns:


760
761
762
# File 'lib/chef-api/resources/base.rb', line 760

def validators
  @validators ||= @schema.validators
end