Class: DopCommon::PlanStore

Inherits:
Object
  • Object
show all
Defined in:
lib/dop_common/plan_store.rb

Instance Method Summary collapse

Constructor Details

#initialize(plan_store_dir) ⇒ PlanStore

Returns a new instance of PlanStore.



18
19
20
21
22
23
24
# File 'lib/dop_common/plan_store.rb', line 18

def initialize(plan_store_dir)
  @plan_store_dir = plan_store_dir
  @lockfiles = {}

  # make sure the plan directory is created
  FileUtils.mkdir_p(@plan_store_dir) unless File.directory?(@plan_store_dir)
end

Instance Method Details

#add(raw_plan) ⇒ Object

Add a new plan to the plan store

Raises:



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/dop_common/plan_store.rb', line 27

def add(raw_plan)
  hash, yaml = read_plan_file(raw_plan)
  plan = DopCommon::Plan.new(hash)

  raise PlanExistsError, "There is already a plan with the name #{plan.name}" if plan_exists?(plan.name)
  raise StandardError, 'Plan not valid. Unable to add' unless plan.valid?
  raise StandardError, 'Some Nodes already exist. Unable to add' if node_duplicates?(plan)

  versions_dir = File.join(@plan_store_dir, plan.name, 'versions')
  FileUtils.mkdir_p(versions_dir) unless File.directory?(versions_dir)
  run_lock(plan.name) do
    save_plan_yaml(plan.name, yaml)
  end

  # make sure the state files are present
  dopi_state = File.join(@plan_store_dir, plan.name, 'dopi.yaml')
  dopv_state = File.join(@plan_store_dir, plan.name, 'dopv.yaml')
  FileUtils.touch(dopi_state)
  FileUtils.touch(dopv_state)

  DopCommon.log.info("New plan #{plan.name} was added")
  plan.name
end

#get_plan(plan_name, version = :latest) ⇒ Object

Get the plan object for the specified version directly



134
135
136
137
# File 'lib/dop_common/plan_store.rb', line 134

def get_plan(plan_name, version = :latest)
  hash = get_plan_hash(plan_name, version)
  DopCommon::Plan.new(hash)
end

#get_plan_hash(plan_name, version = :latest) ⇒ Object

return the hash for the plan in the store for a specific version. Returns the latest version if no version is specified



128
129
130
131
# File 'lib/dop_common/plan_store.rb', line 128

def get_plan_hash(plan_name, version = :latest)
  yaml = get_plan_yaml(plan_name, version)
  YAML.load(yaml)
end

#get_plan_hash_diff(plan_name, old_version, new_version = :latest) ⇒ Object



139
140
141
142
143
# File 'lib/dop_common/plan_store.rb', line 139

def get_plan_hash_diff(plan_name, old_version, new_version = :latest)
  old_hash = get_plan_hash(plan_name, old_version)
  new_hash = get_plan_hash(plan_name, new_version)
  HashDiff.best_diff(old_hash, new_hash)
end

#get_plan_yaml(plan_name, version = :latest) ⇒ Object

returns the yaml file content for the specified plan and version Returns the latest version if no version is specified

Raises:

  • (StandardError)


115
116
117
118
119
120
121
122
123
124
# File 'lib/dop_common/plan_store.rb', line 115

def get_plan_yaml(plan_name, version = :latest)
  raise StandardError, "Plan #{plan_name} does not exist" unless plan_exists?(plan_name)

  versions = show_versions(plan_name)
  version = versions.last if version == :latest
  raise StandardError, "Version #{version} of plan #{plan_name} not found" unless versions.include?(version)

  yaml_file = File.join(@plan_store_dir, plan_name, 'versions', version + '.yaml')
  File.read(yaml_file)
end

#listObject

return an array with all plan names in the plan store



96
97
98
99
100
101
102
103
104
# File 'lib/dop_common/plan_store.rb', line 96

def list
  Dir.entries(@plan_store_dir).select do |entry|
    versions_dir = File.join(@plan_store_dir, entry, "versions")
    add_entry = true
    add_entry = false if ['.', '..'].include?(entry)
    add_entry = false if Dir[versions_dir + '/*.yaml'].empty?
    add_entry
  end
end

#plan_exists?(plan_name) ⇒ Boolean

Returns true if a plan with that name already exists in the plan store.

Returns:

  • (Boolean)


170
171
172
173
# File 'lib/dop_common/plan_store.rb', line 170

def plan_exists?(plan_name)
  versions_dir = File.join(@plan_store_dir, plan_name, 'versions')
  Dir[versions_dir + '/*.yaml'].any?
end

#read_plan_file(raw_plan) ⇒ Object

returns an array with [hash, yaml] of the plan. The plans should always be loaded with this method to make sure the plan is parsed with the pre_processor



178
179
180
181
182
183
184
185
# File 'lib/dop_common/plan_store.rb', line 178

def read_plan_file(raw_plan)
  if raw_plan.kind_of?(Hash)
    [raw_plan, raw_plan.to_yaml]
  else
    parsed_plan = PreProcessor.load_plan(raw_plan)
    [YAML.load(parsed_plan), parsed_plan]
  end
end

#remove(plan_name, remove_dopi_state = true, remove_dopv_state = false) ⇒ Object

remove a plan from the plan store

Raises:

  • (StandardError)


68
69
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/dop_common/plan_store.rb', line 68

def remove(plan_name, remove_dopi_state = true, remove_dopv_state = false)
  raise StandardError, "Plan #{plan_name} does not exist" unless plan_exists?(plan_name)
  plan_dir = File.join(@plan_store_dir, plan_name)
  versions_dir = File.join(plan_dir, 'versions')

  # we have to remove the plan in two steps, so we don't
  # delete the lockfile too soon.
  run_lock(plan_name) do
    FileUtils.remove_entry_secure(versions_dir)
  end
  info_file = File.join(plan_dir, 'run_lock_info')
  FileUtils.remove_entry_secure(info_file)
  if remove_dopi_state
    dopi_state = File.join(plan_dir, 'dopi.yaml')
    FileUtils.remove_entry_secure(dopi_state)
  end
  if remove_dopv_state
    dopv_state = File.join(plan_dir, 'dopv.yaml')
    FileUtils.remove_entry_secure(dopv_state)
  end
  if (Dir.entries(plan_dir) - [ '.', '..' ]).empty?
    FileUtils.remove_entry_secure(plan_dir)
  end
  DopCommon.log.info("Plan #{plan_name} was removed")
  plan_name
end

#run_lock(plan_name) ⇒ Object

A run lock is used in all operations which change plans in the plan store.



146
147
148
149
150
151
152
153
154
155
156
# File 'lib/dop_common/plan_store.rb', line 146

def run_lock(plan_name)
  remove_stale_lock(plan_name)
  lockfile = run_lockfile(plan_name)
  lockfile.lock
  write_run_lock_info(plan_name, lockfile)
  yield
rescue Lockfile::TimeoutLockError
  raise StandardError, read_run_lock_info(plan_name)
ensure
  lockfile.unlock if run_lock?(plan_name)
end

#run_lock?(plan_name) ⇒ Boolean

return true if we have a run lock

Returns:

  • (Boolean)


159
160
161
# File 'lib/dop_common/plan_store.rb', line 159

def run_lock?(plan_name)
  run_lockfile(plan_name).locked?
end

#show_versions(plan_name) ⇒ Object

returns a sorted array of versions for a plan (oldest version first)

Raises:

  • (StandardError)


107
108
109
110
111
# File 'lib/dop_common/plan_store.rb', line 107

def show_versions(plan_name)
  raise StandardError, "Plan #{plan_name} does not exist" unless plan_exists?(plan_name)
  versions_dir = File.join(@plan_store_dir, plan_name, 'versions')
  Dir[versions_dir + '/*.yaml'].map {|yaml_file| File.basename(yaml_file, '.yaml')}.sort
end

#state_store(plan_name, app_name) ⇒ Object



163
164
165
166
# File 'lib/dop_common/plan_store.rb', line 163

def state_store(plan_name, app_name)
  state_file = File.join(@plan_store_dir, plan_name, app_name + '.yaml')
  DopCommon::StateStore.new(state_file, plan_name, self)
end

#update(raw_plan) ⇒ Object

Update a plan already in the plan store

Raises:

  • (StandardError)


52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/dop_common/plan_store.rb', line 52

def update(raw_plan)
  hash, yaml = read_plan_file(raw_plan)
  plan = DopCommon::Plan.new(hash)

  raise StandardError, "No plan with the name #{plan.name} found. Unable to update" unless plan_exists?(plan.name)
  raise StandardError, 'Plan not valid. Unable to update' unless plan.valid?
  raise StandardError, 'Some Nodes already exist in other plans. Unable to update' if node_duplicates?(plan)

  run_lock(plan.name) do
    save_plan_yaml(plan.name, yaml)
  end
  DopCommon.log.info("Plan #{plan.name} was updated")
  plan.name
end