Class: FryCook::WorkTree

Inherits:
Object
  • Object
show all
Defined in:
lib/fry_cook/work_tree.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ WorkTree



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/fry_cook/work_tree.rb', line 13

def initialize(options)
  if options[:storage_path] && File.file?("#{options[:storage_path]}/config.json")
    existing_config = JSON.load(File.read("#{options[:storage_path]}/config.json"), nil, symbolize_names: true)
    options = existing_config.merge(options)
  end

  if options[:git_repo_remote]
    @mode = :git
    @git_remote = options[:git_repo_remote]
    @git_ref = options[:git_ref] || 'master'
    @storage_path = options[:storage_path] || raise("Must specify storage path for git mode.")
    @git_repo = "#{@storage_path}/git-repo"
  else
    @mode = :path
    @working_path = options[:working_path] || '.'
    @storage_path = options[:storage_path] || "#{@working_path}/.fry-cook"
  end

  FileUtils.mkdir_p(@storage_path)
  FileUtils.mkdir_p("#{@storage_path}/nodes")

  File.write("#{@storage_path}/config.json", JSON.dump(options))
end

Instance Attribute Details

#storage_pathObject (readonly)

Returns the value of attribute storage_path.



11
12
13
# File 'lib/fry_cook/work_tree.rb', line 11

def storage_path
  @storage_path
end

Instance Method Details

#build(force = false) ⇒ Object



154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/fry_cook/work_tree.rb', line 154

def build(force = false)
  current_link = "#{@storage_path}/current"
  old_version = File.symlink?(current_link) && File.readlink(current_link)

  new_version, source_path = pull_source()
  install_path = File.expand_path("#{@storage_path}/#{new_version}")

  if force || new_version != old_version
    begin
      install_cookbooks(new_version, source_path, install_path)
      install_environments(new_version, source_path, install_path)
      install_roles(new_version, source_path, install_path)
      install_data_bags(new_version, source_path, install_path)
    rescue
      # Clean up the probably broken deploy install path if it got created.
      # We don't care why it failed, so we pass the buck up.
      FileUtils.rmdir(install_path) if File.directory?(install_path)
      raise
    end

    tmplink = current_link + ".#{Process.pid}.lnk"
    FileUtils.ln_s(new_version, tmplink)
    File.rename(tmplink, current_link)

    if old_version && File.directory?("#{@storage_path}/#{old_version}")
      FileUtils.rm_rf("#{@storage_path}/#{old_version}")
    end
  end
end

#cmd(cmd) ⇒ Object



53
54
55
56
57
58
59
60
61
# File 'lib/fry_cook/work_tree.rb', line 53

def cmd(cmd)
  res = IO.popen(cmd, :err=>[:child, :out]) do |p|
    p.readlines.collect {|line| line.chomp }
  end
  if !$?.success?
    raise("Command #{cmd.join(' ')} failed:\n#{res.join("\n")}")
  end
  res
end

#cookbook_pathObject



40
41
42
# File 'lib/fry_cook/work_tree.rb', line 40

def cookbook_path
  "#{storage_path}/current/cookbooks"
end

#data_bag_pathObject



46
47
48
# File 'lib/fry_cook/work_tree.rb', line 46

def data_bag_path
  "#{storage_path}/current/data_bags"
end

#environment_pathObject



49
50
51
# File 'lib/fry_cook/work_tree.rb', line 49

def environment_path
  "#{storage_path}/current/environments"
end

#git(*cmd) ⇒ Object



62
63
64
# File 'lib/fry_cook/work_tree.rb', line 62

def git(*cmd)
  cmd(["git", "--git-dir", @git_repo, *cmd])
end

#git_in(work_path, *cmd) ⇒ Object



65
66
67
68
# File 'lib/fry_cook/work_tree.rb', line 65

def git_in(work_path, *cmd)
  FileUtils.mkdir_p(work_path)
  git("--work-tree", work_path, *cmd)
end

#git_refreshObject



70
71
72
73
74
75
# File 'lib/fry_cook/work_tree.rb', line 70

def git_refresh
  if !File.directory? @git_repo
    git("clone", "--bare", @git_remote, @git_repo)
  end
  git("fetch", '-f', @git_remote, 'refs/heads/*:refs/heads/*')
end

#install_cookbooks(new_version, source_path, install_path) ⇒ Object



97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/fry_cook/work_tree.rb', line 97

def install_cookbooks(new_version, source_path, install_path)
  case
  when File.file?("#{source_path}/Berksfile")
    # Note: Doesn't work properly without being in the directory of the berksfile.
    Dir.chdir(source_path) do
      berksfile = Berkshelf::Berksfile.from_file("Berksfile")
      berksfile.vendor("#{install_path}/cookbooks")
    end
  when File.directory?("#{source_path}/cookbooks")
    FileUtils.cp_r("#{source_path}/cookbooks", "#{install_path}/cookbooks")
  else
    raise("No cookbooks found.")
  end
end

#install_data_bags(new_version, source_path, install_path) ⇒ Object



140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/fry_cook/work_tree.rb', line 140

def install_data_bags(new_version, source_path, install_path)
  FileUtils.mkdir_p("#{install_path}/data_bags")
  Dir.glob("#{source_path}/data_bags/*").each do |data_bag|
    next if !File.directory? data_bag

    data_bag_name = File.basename(data_bag)
    FileUtils.mkdir_p("#{install_path}/data_bags/#{data_bag_name}")
    items = Dir.glob("#{data_bag}/*.json")
    if !items.empty?
      FileUtils.cp(items, "#{install_path}/data_bags/#{data_bag_name}")
    end
  end
end

#install_environments(new_version, source_path, install_path) ⇒ Object



112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/fry_cook/work_tree.rb', line 112

def install_environments(new_version, source_path, install_path)
  FileUtils.mkdir_p("#{install_path}/environments")
  environments = Dir.glob("#{source_path}/environments/*.json")
  if !environments.empty?
    FileUtils.cp(environments, "#{install_path}/environments")
  end
  Dir.glob("#{source_path}/environments/*.rb").each do |environment|
    environment_obj = Chef::Environment.new
    environment_obj.name File.basename(environment, ".rb")
    environment_obj.from_file(environment)
    File.write("#{install_path}/environments/#{File.basename(environment, ".rb")}.json", environment_obj.to_json)
  end
end

#install_roles(new_version, source_path, install_path) ⇒ Object



126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/fry_cook/work_tree.rb', line 126

def install_roles(new_version, source_path, install_path)
  FileUtils.mkdir_p("#{install_path}/roles")
  roles = Dir.glob("#{source_path}/roles/*.json")
  if !roles.empty?
    FileUtils.cp(roles, "#{install_path}/roles")
  end
  Dir.glob("#{source_path}/roles/*.rb").each do |role|
    role_obj = Chef::Role.new
    role_obj.name File.basename(role, ".rb")
    role_obj.from_file(role)
    File.write("#{install_path}/roles/#{File.basename(role, ".rb")}.json", role_obj.to_json)
  end
end

#node_pathObject



37
38
39
# File 'lib/fry_cook/work_tree.rb', line 37

def node_path
  "#{storage_path}/nodes"
end

#pull_sourceObject



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/fry_cook/work_tree.rb', line 77

def pull_source
  case @mode
  when :git
    git_refresh
    new_ref = git("rev-parse", @git_ref)
    if new_ref.length == 0
      raise("Didn't get a valid ref for #{@git_ref}")
    end
    new_version = "build-" + new_ref[0]
    source_path = "#{@storage_path}/#{new_version}/chef_repo"
    if !File.directory? source_path
      git_in(source_path, "checkout", "-f", @git_ref)
    end
  when :path
    new_version = "build-#{Time.now.to_i}"
    source_path = @working_path
  end
  return new_version, source_path
end

#role_pathObject



43
44
45
# File 'lib/fry_cook/work_tree.rb', line 43

def role_path
  "#{storage_path}/current/roles"
end