Class: Apcera::Stager
- Inherits:
-
Object
- Object
- Apcera::Stager
- Defined in:
- lib/apcera/stager/stager.rb
Constant Summary collapse
- PKG_NAME =
"pkg.tar.gz"
- UPDATED_PKG_NAME =
"updated.tar.gz"
Instance Attribute Summary collapse
-
#app_path ⇒ Object
Returns the value of attribute app_path.
-
#pkg_path ⇒ Object
Returns the value of attribute pkg_path.
-
#root_path ⇒ Object
Returns the value of attribute root_path.
-
#stager_url ⇒ Object
Returns the value of attribute stager_url.
-
#system_options ⇒ Object
Returns the value of attribute system_options.
-
#updated_pkg_path ⇒ Object
Returns the value of attribute updated_pkg_path.
Instance Method Summary collapse
-
#complete ⇒ Object
Finish staging, compress your app dir and send to the staging coordinator.
-
#dependencies_add(type, name) ⇒ Object
Add dependencies to package.
-
#dependencies_remove(type, name) ⇒ Object
Delete dependencies from package.
-
#done ⇒ Object
Tell the staging coordinator you are done.
-
#download ⇒ Object
Download a package from the staging coordinator.
-
#environment_add(key, value) ⇒ Object
Add environment variable to package.
-
#environment_remove(key) ⇒ Object
Delete environment variable from package.
-
#execute(cmd) ⇒ Object
Execute a command in the shell.
-
#execute_app(cmd) ⇒ Object
Execute a command in the app dir.
-
#exit0r(code) ⇒ Object
Exit, needed for tests to not quit.
-
#extract(location) ⇒ Object
Extract the package to a given location.
-
#fail(error = nil) ⇒ Object
Fail the stager, something went wrong.
-
#initialize(options = {}) ⇒ Stager
constructor
A new instance of Stager.
-
#meta ⇒ Object
Get metadata for the package being staged.
-
#output(text) ⇒ Object
Output to stdout.
-
#output_error(text) ⇒ Object
Output to stderr.
-
#provides_add(type, name) ⇒ Object
Add provides to package.
-
#provides_remove(type, name) ⇒ Object
Delete provides from package.
-
#relaunch ⇒ Object
Tell the staging coordinator you need to relaunch.
-
#setup_chroot ⇒ Object
Setup /stagerfs chroot environment so it is ready to run commands from pulled in dependencies.
-
#snapshot ⇒ Object
Snapshot the stager filesystem for app.
-
#start_command ⇒ Object
Returns the start command for the package.
-
#start_command=(val) ⇒ Object
Easily set the start command.
-
#start_path ⇒ Object
Returns the start path for the package.
-
#start_path=(val) ⇒ Object
Easily set the start path.
-
#templates_add(path, left_delimiter = "{{", right_delimiter = "}}") ⇒ Object
Add template to package.
-
#templates_remove(path, left_delimiter = "{{", right_delimiter = "}}") ⇒ Object
Delete template from package.
-
#upload ⇒ Object
Upload the new package to the staging coordinator.
Constructor Details
#initialize(options = {}) ⇒ Stager
Returns a new instance of Stager.
8 9 10 11 12 13 14 15 |
# File 'lib/apcera/stager/stager.rb', line 8 def initialize( = {}) # Require stager url. Needed to talk to the Staging Coordinator. @stager_url = [:stager_url] || ENV["STAGER_URL"] raise Apcera::Error::StagerURLRequired.new("stager_url required") unless @stager_url # Setup the environment, some test items here. setup_environment end |
Instance Attribute Details
#app_path ⇒ Object
Returns the value of attribute app_path.
3 4 5 |
# File 'lib/apcera/stager/stager.rb', line 3 def app_path @app_path end |
#pkg_path ⇒ Object
Returns the value of attribute pkg_path.
3 4 5 |
# File 'lib/apcera/stager/stager.rb', line 3 def pkg_path @pkg_path end |
#root_path ⇒ Object
Returns the value of attribute root_path.
3 4 5 |
# File 'lib/apcera/stager/stager.rb', line 3 def root_path @root_path end |
#stager_url ⇒ Object
Returns the value of attribute stager_url.
3 4 5 |
# File 'lib/apcera/stager/stager.rb', line 3 def stager_url @stager_url end |
#system_options ⇒ Object
Returns the value of attribute system_options.
3 4 5 |
# File 'lib/apcera/stager/stager.rb', line 3 def @system_options end |
#updated_pkg_path ⇒ Object
Returns the value of attribute updated_pkg_path.
3 4 5 |
# File 'lib/apcera/stager/stager.rb', line 3 def updated_pkg_path @updated_pkg_path end |
Instance Method Details
#complete ⇒ Object
Finish staging, compress your app dir and send to the staging coordinator. Then tell the staging coordinator we are done.
260 261 262 263 |
# File 'lib/apcera/stager/stager.rb', line 260 def complete upload done end |
#dependencies_add(type, name) ⇒ Object
Add dependencies to package.
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/apcera/stager/stager.rb', line 174 def dependencies_add(type, name) exists = self.["dependencies"].detect { |dep| dep["type"] == type && dep["name"] == name } return false if exists response = RestClient.put(, { :resource => "dependencies", :action => "add", :type => type, :name => name }) true rescue => e fail e end |
#dependencies_remove(type, name) ⇒ Object
Delete dependencies from package.
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
# File 'lib/apcera/stager/stager.rb', line 191 def dependencies_remove(type, name) exists = self.["dependencies"].detect { |dep| dep["type"] == type && dep["name"] == name} return false if !exists response = RestClient.put(, { :resource => "dependencies", :action => "remove", :type => type, :name => name }) true rescue => e fail e end |
#done ⇒ Object
Tell the staging coordinator you are done.
243 244 245 246 247 248 |
# File 'lib/apcera/stager/stager.rb', line 243 def done response = RestClient.post(@stager_url+"/done", {}) exit0r 0 rescue => e fail e end |
#download ⇒ Object
Download a package from the staging coordinator. We use Net::HTTP here because it supports streaming downloads.
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/apcera/stager/stager.rb', line 35 def download uri = URI(@stager_url + "/data") Net::HTTP.start(uri.host.to_s, uri.port.to_s) do |http| request = Net::HTTP::Get.new uri.request_uri http.request request do |response| if response.code.to_i == 200 open @pkg_path, 'wb' do |io| response.read_body do |chunk| io.write chunk end end else raise Apcera::Error::DownloadError.new("package download failed.\n") end end end rescue => e fail e end |
#environment_add(key, value) ⇒ Object
Add environment variable to package.
127 128 129 130 131 132 133 134 135 136 |
# File 'lib/apcera/stager/stager.rb', line 127 def environment_add(key, value) response = RestClient.put(, { :resource => "environment", :action => "add", :key => key, :value => value }) rescue => e fail e end |
#environment_remove(key) ⇒ Object
Delete environment variable from package.
139 140 141 142 143 144 145 146 147 |
# File 'lib/apcera/stager/stager.rb', line 139 def environment_remove(key) response = RestClient.put(, { :resource => "environment", :action => "remove", :key => key }) rescue => e fail e end |
#execute(cmd) ⇒ Object
Execute a command in the shell. We don’t want real commands in tests.
59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/apcera/stager/stager.rb', line 59 def execute(cmd) Bundler.with_clean_env do result = system(cmd, @system_options) if !result raise Apcera::Error::ExecuteError.new("failed to execute: #{cmd}.\n") end result end rescue => e fail e end |
#execute_app(cmd) ⇒ Object
Execute a command in the app dir. Useful helper.
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/apcera/stager/stager.rb', line 73 def execute_app(cmd) raise_app_path_error if @app_path == nil Bundler.with_clean_env do Dir.chdir(@app_path) do |app_path| result = system(cmd, @system_options) if !result raise Apcera::Error::ExecuteError.new("failed to execute: #{cmd}.\n") end result end end rescue => e fail e end |
#exit0r(code) ⇒ Object
Exit, needed for tests to not quit.
296 297 298 |
# File 'lib/apcera/stager/stager.rb', line 296 def exit0r(code) exit code end |
#extract(location) ⇒ Object
Extract the package to a given location.
90 91 92 93 94 95 96 97 |
# File 'lib/apcera/stager/stager.rb', line 90 def extract(location) @app_path = File.join(@root_path, location) Dir.mkdir(@app_path) unless Dir.exists?(@app_path) execute_app("tar -zxf #{@pkg_path}") rescue => e fail e end |
#fail(error = nil) ⇒ Object
Fail the stager, something went wrong.
286 287 288 289 290 291 292 293 |
# File 'lib/apcera/stager/stager.rb', line 286 def fail(error = nil) output_error "Error: #{error.}.\n" if error RestClient.post(@stager_url+"/failed", {}) rescue => e output_error "Error: #{e.}.\n" ensure exit0r 1 end |
#meta ⇒ Object
Get metadata for the package being staged.
234 235 236 237 238 239 240 |
# File 'lib/apcera/stager/stager.rb', line 234 def response = RestClient.get() return JSON.parse(response.to_s) rescue => e output_error "Error: #{e.}.\n" raise e end |
#output(text) ⇒ Object
Output to stdout
306 307 308 |
# File 'lib/apcera/stager/stager.rb', line 306 def output(text) $stdout.puts text end |
#output_error(text) ⇒ Object
Output to stderr
301 302 303 |
# File 'lib/apcera/stager/stager.rb', line 301 def output_error(text) $stderr.puts text end |
#provides_add(type, name) ⇒ Object
Add provides to package.
150 151 152 153 154 155 156 157 158 159 |
# File 'lib/apcera/stager/stager.rb', line 150 def provides_add(type, name) response = RestClient.put(, { :resource => "provides", :action => "add", :type => type, :name => name }) rescue => e fail e end |
#provides_remove(type, name) ⇒ Object
Delete provides from package.
162 163 164 165 166 167 168 169 170 171 |
# File 'lib/apcera/stager/stager.rb', line 162 def provides_remove(type, name) response = RestClient.put(, { :resource => "provides", :action => "remove", :type => type, :name => name }) rescue => e fail e end |
#relaunch ⇒ Object
Tell the staging coordinator you need to relaunch.
251 252 253 254 255 256 |
# File 'lib/apcera/stager/stager.rb', line 251 def relaunch response = RestClient.post(@stager_url+"/relaunch", {}) exit0r 0 rescue => e fail e end |
#setup_chroot ⇒ Object
Setup /stagerfs chroot environment so it is ready to run commands from pulled in dependencies. This does the following:
-
Setup working resolv.conf
-
Bind mounts /proc to /stagerfs/proc
-
Recursively bind mounts /dev to /stagerfs/dev
22 23 24 25 26 27 28 29 30 31 |
# File 'lib/apcera/stager/stager.rb', line 22 def setup_chroot execute("sudo mkdir -p /stagerfs/etc") execute("sudo cp /etc/resolv.conf /stagerfs/etc/resolv.conf") execute("sudo mkdir -p /stagerfs/proc") execute("sudo mount --bind /proc /stagerfs/proc") execute("sudo mkdir -p /stagerfs/dev") execute("sudo mount --rbind /dev /stagerfs/dev") end |
#snapshot ⇒ Object
Snapshot the stager filesystem for app
120 121 122 123 124 |
# File 'lib/apcera/stager/stager.rb', line 120 def snapshot response = RestClient.post(@stager_url+"/snapshot", {}) rescue => e fail e end |
#start_command ⇒ Object
Returns the start command for the package.
266 267 268 |
# File 'lib/apcera/stager/stager.rb', line 266 def start_command self.["environment"]["START_COMMAND"] end |
#start_command=(val) ⇒ Object
Easily set the start command
271 272 273 |
# File 'lib/apcera/stager/stager.rb', line 271 def start_command=(val) self.environment_add("START_COMMAND", val) end |
#start_path ⇒ Object
Returns the start path for the package.
276 277 278 |
# File 'lib/apcera/stager/stager.rb', line 276 def start_path self.["environment"]["START_PATH"] end |
#start_path=(val) ⇒ Object
Easily set the start path
281 282 283 |
# File 'lib/apcera/stager/stager.rb', line 281 def start_path=(val) self.environment_add("START_PATH", val) end |
#templates_add(path, left_delimiter = "{{", right_delimiter = "}}") ⇒ Object
Add template to package.
208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/apcera/stager/stager.rb', line 208 def templates_add(path, left_delimiter = "{{", right_delimiter = "}}") response = RestClient.put(, { :resource => "templates", :action => "add", :path => path, :left_delimiter => left_delimiter, :right_delimiter => right_delimiter }) rescue => e fail e end |
#templates_remove(path, left_delimiter = "{{", right_delimiter = "}}") ⇒ Object
Delete template from package.
221 222 223 224 225 226 227 228 229 230 231 |
# File 'lib/apcera/stager/stager.rb', line 221 def templates_remove(path, left_delimiter = "{{", right_delimiter = "}}") response = RestClient.put(, { :resource => "templates", :action => "remove", :path => path, :left_delimiter => left_delimiter, :right_delimiter => right_delimiter }) rescue => e fail e end |
#upload ⇒ Object
Upload the new package to the staging coordinator. If we have an app extracted we send that to the staging coordinator. If no app was ever extracted we just upload the unmodified app.
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/apcera/stager/stager.rb', line 102 def upload if @app_path == nil unless File.exist?(@pkg_path) download end upload_file(@pkg_path) else app_dir = Pathname.new(@app_path).relative_path_from(Pathname.new(@root_path)).to_s execute_app("cd #{app_path}/.. && tar czf #{@updated_pkg_path} #{app_dir}") upload_file(@updated_pkg_path) end rescue => e fail e end |