Class: Vagrant::MachineIndex
- Inherits:
-
Object
- Object
- Vagrant::MachineIndex
- Includes:
- Enumerable
- Defined in:
- lib/vagrant/machine_index.rb,
lib/vagrant/machine_index/remote.rb
Overview
MachineIndex is able to manage the index of created Vagrant environments in a central location.
The MachineIndex stores a mapping of UUIDs to basic information about a machine. The UUIDs are stored with the Vagrant environment and are looked up in the machine index.
The MachineIndex stores information such as the name of a machine, the directory it was last seen at, its last known state, etc. Using this information, we can load the entire Machine object for a machine, or we can just display metadata if needed.
The internal format of the data file is currently JSON in the following structure:
{ "version": 1, "machines": { "uuid": { "name": "foo", "provider": "vmware_fusion", "architecture": "amd64", "data_path": "/path/to/data/dir", "vagrantfile_path": "/path/to/Vagrantfile", "state": "running", "updated_at": "2014-03-02 11:11:44 +0100" } } }
Defined Under Namespace
Modules: Remote Classes: Entry
Instance Method Summary collapse
-
#delete(entry) ⇒ Boolean
Deletes a machine by UUID.
-
#each(reload = false) ⇒ Object
Iterate over every machine in the index.
-
#get(uuid) ⇒ MachineIndex::Entry
Accesses a machine by UUID and returns a Entry.
-
#include?(uuid) ⇒ Boolean
Tests if the index has the given UUID.
-
#initialize(data_dir) ⇒ MachineIndex
constructor
Initializes a MachineIndex at the given file location.
-
#recover(entry) ⇒ Entry
Reinsert a machine into the global index if it has a valid existing uuid but does not currently exist in the index.
-
#release(entry) ⇒ Object
Releases an entry, unlocking it.
-
#set(entry) ⇒ Entry
Creates/updates an entry object and returns the resulting entry.
Constructor Details
#initialize(data_dir) ⇒ MachineIndex
Initializes a MachineIndex at the given file location.
51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/vagrant/machine_index.rb', line 51 def initialize(data_dir) @data_dir = data_dir @index_file = data_dir.join("index") @lock = Monitor.new @machines = {} @machine_locks = {} with_index_lock do unlocked_reload end end |
Instance Method Details
#delete(entry) ⇒ Boolean
Deletes a machine by UUID.
The machine being deleted with this UUID must either be locked by this index or must be unlocked.
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/vagrant/machine_index.rb', line 70 def delete(entry) return true if !entry.id @lock.synchronize do with_index_lock do return true if !@machines[entry.id] # If we don't have the lock, then we need to acquire it. if !@machine_locks[entry.id] raise "Unlocked delete on machine: #{entry.id}" end # Reload so we have the latest data, then delete and save unlocked_reload @machines.delete(entry.id) unlocked_save # Release access on this machine unlocked_release(entry.id) end end true end |
#each(reload = false) ⇒ Object
98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/vagrant/machine_index.rb', line 98 def each(reload=false) if reload @lock.synchronize do with_index_lock do unlocked_reload end end end @machines.each do |uuid, data| yield Entry.new(uuid, data.merge("id" => uuid)) end end |
#get(uuid) ⇒ MachineIndex::Entry
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/vagrant/machine_index.rb', line 122 def get(uuid) entry = nil @lock.synchronize do with_index_lock do # Reload the data unlocked_reload data = find_by_prefix(uuid) return nil if !data uuid = data["id"] entry = Entry.new(uuid, data) # Lock this machine lock_file = lock_machine(uuid) if !lock_file raise Errors::MachineLocked, name: entry.name, provider: entry.provider end @machine_locks[uuid] = lock_file end end entry end |
#include?(uuid) ⇒ Boolean
Tests if the index has the given UUID.
155 156 157 158 159 160 161 162 |
# File 'lib/vagrant/machine_index.rb', line 155 def include?(uuid) @lock.synchronize do with_index_lock do unlocked_reload return !!find_by_prefix(uuid) end end end |
#recover(entry) ⇒ Entry
Reinsert a machine into the global index if it has a valid existing uuid but does not currently exist in the index.
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
# File 'lib/vagrant/machine_index.rb', line 246 def recover(entry) @lock.synchronize do with_index_lock do # Reload the data unlocked_reload # Don't recover if entry already exists in the global return entry if find_by_prefix(entry.id) lock_file = lock_machine(entry.id) if !lock_file raise Errors::MachineLocked, name: entry.name, provider: entry.provider end @machine_locks[entry.id] = lock_file end end return set(entry) end |
#release(entry) ⇒ Object
Releases an entry, unlocking it.
This is an idempotent operation. It is safe to call this even if you're unsure if an entry is locked or not.
After calling this, the previous entry should no longer be used.
172 173 174 175 176 |
# File 'lib/vagrant/machine_index.rb', line 172 def release(entry) @lock.synchronize do unlocked_release(entry.id) end end |
#set(entry) ⇒ Entry
Creates/updates an entry object and returns the resulting entry.
If the entry was new (no UUID), then the UUID will be set on the resulting entry and can be used. Additionally, the a lock will be created for the resulting entry, so you must #release it if you want others to be able to access it.
If the entry isn't new (has a UUID). then this process must hold that entry's lock or else this set will fail.
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
# File 'lib/vagrant/machine_index.rb', line 190 def set(entry) # Get the struct and update the updated_at attribute struct = entry.to_json_struct # Set an ID if there isn't one already set id = entry.id @lock.synchronize do with_index_lock do # Reload so we have the latest machine data. This allows other # processes to update their own machines without conflicting # with our own. unlocked_reload # If we don't have a machine ID, try to look one up if !id self.each do |other| if entry.name == other.name && entry.provider == other.provider && entry.vagrantfile_path.to_s == other.vagrantfile_path.to_s id = other.id break end end # If we still don't have an ID, generate a random one id = SecureRandom.uuid.gsub("-", "") if !id # Get a lock on this machine lock_file = lock_machine(id) if !lock_file raise "Failed to lock new machine: #{entry.name}" end @machine_locks[id] = lock_file end if !@machine_locks[id] raise "Unlocked write on machine: #{id}" end # Set our machine and save @machines[id] = struct unlocked_save end end Entry.new(id, struct) end |