Class: Chef::CouchDB

Inherits:
Object show all
Includes:
Mixin::ParamsValidate
Defined in:
lib/chef/couchdb.rb

Instance Method Summary collapse

Methods included from Mixin::ParamsValidate

#set_or_return, #validate

Constructor Details

#initialize(url = nil, db = Chef::Config[:couchdb_database]) ⇒ CouchDB

Returns a new instance of CouchDB.



36
37
38
39
40
# File 'lib/chef/couchdb.rb', line 36

def initialize(url=nil, db=Chef::Config[:couchdb_database])
  url ||= Chef::Config[:couchdb_url]
  @db = db
  @rest = Chef::REST.new(url, nil, nil)
end

Instance Method Details

#bulk_get(*to_fetch) ⇒ Object



225
226
227
228
# File 'lib/chef/couchdb.rb', line 225

def bulk_get(*to_fetch)
  response = @rest.post_rest("#{couchdb_database}/_all_docs?include_docs=true", { "keys" => to_fetch.flatten })
  response["rows"].collect { |r| r["doc"] }
end

#couchdb_database(args = nil) ⇒ Object



42
43
44
# File 'lib/chef/couchdb.rb', line 42

def couchdb_database(args=nil)
  @db = args || @db
end

#create_dbObject



72
73
74
75
76
77
78
# File 'lib/chef/couchdb.rb', line 72

def create_db
  @database_list = @rest.get_rest("_all_dbs")
  unless @database_list.detect { |db| db == couchdb_database }
    response = @rest.put_rest(couchdb_database, Hash.new)
  end
  couchdb_database
end

#create_design_document(name, data) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/chef/couchdb.rb', line 80

def create_design_document(name, data)
  create_db
  to_update = true
  begin
    old_doc = @rest.get_rest("#{couchdb_database}/_design/#{name}")
    if data["version"] != old_doc["version"]
      data["_rev"] = old_doc["_rev"]
      Chef::Log.debug("Updating #{name} views")
    else
      to_update = false
    end
  rescue 
    Chef::Log.debug("Creating #{name} views for the first time because: #{$!}")
  end
  if to_update
    @rest.put_rest("#{couchdb_database}/_design%2F#{name}", data)
  end
  true
end

#create_id_mapObject



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/chef/couchdb.rb', line 46

def create_id_map
  create_design_document(
    "id_map", 
    {
      "version" => 1,
      "language" => "javascript",
      "views" => {
        "name_to_id" => {
          "map" => <<-EOJS
            function(doc) {
              emit([ doc.chef_type, doc.name], doc._id);
            }
          EOJS
        },
        "id_to_name" => {
          "map" => <<-EOJS
            function(doc) { 
              emit(doc._id, [ doc.chef_type, doc.name ]);
            }
          EOJS
        }
      }
    }
  )
end

#delete(obj_type, name, rev = nil) ⇒ Object



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/chef/couchdb.rb', line 138

def delete(obj_type, name, rev=nil)
  validate(
    {
      :obj_type => obj_type,
      :name => name,
    },
    {
      :obj_type => { :kind_of => String },
      :name => { :kind_of => String },
    }
  )
  del_id = nil 
  object, uuid = find_by_name(obj_type, name, true)
  unless rev
    if object.respond_to?(:couchdb_rev)
      rev = object.couchdb_rev
    else
      rev = object['_rev']
    end
  end
  response = @rest.delete_rest("#{couchdb_database}/#{uuid}?rev=#{rev}")
  response.couchdb = self if response.respond_to?(:couchdb=)
  Chef::Log.info("Sending #{obj_type}(#{uuid}) to the index queue for deletion..")
  
  object.delete_from_index(:database => couchdb_database, :id => uuid, :type => obj_type)

  response
end

#find_by_name(obj_type, name, with_id = false) ⇒ Object



205
206
207
208
209
210
211
212
213
214
215
# File 'lib/chef/couchdb.rb', line 205

def find_by_name(obj_type, name, with_id=false)
  r = get_view("id_map", "name_to_id", :key => [ obj_type, name ], :include_docs => true)
  if r["rows"].length == 0
    raise Chef::Exceptions::CouchDBNotFound, "Cannot find #{obj_type} #{name} in CouchDB!"
  end
  if with_id
    [ r["rows"][0]["doc"], r["rows"][0]["id"] ]
  else
    r["rows"][0]["doc"] 
  end
end

#get_view(design, view, options = {}) ⇒ Object



217
218
219
220
221
222
223
# File 'lib/chef/couchdb.rb', line 217

def get_view(design, view, options={})
  view_string = view_uri(design, view)
  view_string << "?" if options.length != 0
  first = true;
  options.each { |k,v| view_string << "#{first ? '' : '&'}#{k}=#{URI.escape(v.to_json)}"; first = false }
  @rest.get_rest(view_string)
end

#has_key?(obj_type, name) ⇒ Boolean

Returns:

  • (Boolean)


186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/chef/couchdb.rb', line 186

def has_key?(obj_type, name)
  validate(
    {
      :obj_type => obj_type,
      :name => name,
    },
    {
      :obj_type => { :kind_of => String },
      :name => { :kind_of => String },
    }
  )
  begin
    find_by_name(obj_type, name)
    true
  rescue
    false
  end
end

#list(view, inflate = false) ⇒ Object



167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/chef/couchdb.rb', line 167

def list(view, inflate=false)
  validate(
    { 
      :view => view,
    },
    {
      :view => { :kind_of => String }
    }
  )
  if inflate
    r = @rest.get_rest(view_uri(view, "all"))
    r["rows"].each { |i| i["value"].couchdb = self if i["value"].respond_to?(:couchdb=) }
    r
  else
    r = @rest.get_rest(view_uri(view, "all_id"))
  end
  r
end

#load(obj_type, name) ⇒ Object



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/chef/couchdb.rb', line 122

def load(obj_type, name)
  validate(
    {
      :obj_type => obj_type,
      :name => name,
    },
    {
      :obj_type => { :kind_of => String },
      :name => { :kind_of => String },
    }
           )
  doc = find_by_name(obj_type, name)
  doc.couchdb = self if doc.respond_to?(:couchdb)
  doc 
end

#store(obj_type, name, object) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/chef/couchdb.rb', line 100

def store(obj_type, name, object)
  validate(
    {
      :obj_type => obj_type,
      :name => name,
      :object => object,
    },
    {
      :object => { :respond_to => :to_json },
    }
  )
  rows = get_view("id_map", "name_to_id", :key => [ obj_type, name ])["rows"]
  uuid    = rows.empty? ? UUIDTools::UUID.random_create.to_s : rows.first.fetch("id")
  
  db_put_response = @rest.put_rest("#{couchdb_database}/#{uuid}", object)
  
  Chef::Log.info("Sending #{obj_type}(#{uuid}) to the index queue for addition.")
  object.add_to_index(:database => couchdb_database, :id => uuid, :type => obj_type)
  
  db_put_response
end

#view_uri(design, view) ⇒ Object



230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'lib/chef/couchdb.rb', line 230

def view_uri(design, view)
  Chef::Config[:couchdb_version] ||= @rest.run_request(:GET,
                                                       URI.parse(@rest.url + "/"),
                                                       {},
                                                       10,
                                                       false)["version"].gsub(/-.+/,"").to_f
  case Chef::Config[:couchdb_version]
  when 0.8
    "#{couchdb_database}/_view/#{design}/#{view}"
  else
    "#{couchdb_database}/_design/#{design}/_view/#{view}"
  end
end