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 directory your package was extracted to (or where you manually set @app_dir).
-
#exit0r(code) ⇒ Object
Exit, needed for tests to not quit.
-
#extract(location = "") ⇒ Object
Extract the package to a location within staging path, optionally creating the named folder first and extract into it.
-
#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.
270 271 272 273 |
# File 'lib/apcera/stager/stager.rb', line 270 def complete upload done end |
#dependencies_add(type, name) ⇒ Object
Add dependencies to package.
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
# File 'lib/apcera/stager/stager.rb', line 184 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.
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/apcera/stager/stager.rb', line 201 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.
253 254 255 256 257 258 |
# File 'lib/apcera/stager/stager.rb', line 253 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.
137 138 139 140 141 142 143 144 145 146 |
# File 'lib/apcera/stager/stager.rb', line 137 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.
149 150 151 152 153 154 155 156 157 |
# File 'lib/apcera/stager/stager.rb', line 149 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.join(' ')}.\n") end result end rescue => e fail e end |
#execute_app(*cmd) ⇒ Object
Execute a command in the directory your package was extracted to (or where you manually set @app_dir). Useful helper.
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/apcera/stager/stager.rb', line 74 def execute_app(*cmd) raise_app_path_error if @run_path == nil Bundler.with_clean_env do Dir.chdir(@run_path) do |run_path| result = system(*cmd, @system_options) if !result raise Apcera::Error::ExecuteError.new("failed to execute: #{cmd.join(' ')}.\n") end result end end rescue => e fail e end |
#exit0r(code) ⇒ Object
Exit, needed for tests to not quit.
306 307 308 |
# File 'lib/apcera/stager/stager.rb', line 306 def exit0r(code) exit code end |
#extract(location = "") ⇒ Object
Extract the package to a location within staging path, optionally creating the named folder first and extract into it. If a location parameter is given, when upload is run the folder will be uploaded up along with the files. In either case, execute_app will run commands in the location where files were extracted to.
95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/apcera/stager/stager.rb', line 95 def extract(location="") @app_path=File.join(@root_path, "staging") Dir.mkdir(@app_path) unless Dir.exists?(@app_path) @run_path = location.empty? ? @app_path : File.join(@app_path, location) Dir.mkdir(@run_path) unless Dir.exists?(@run_path) execute_app("tar -zxf #{@pkg_path}") rescue => e fail e end |
#fail(error = nil) ⇒ Object
Fail the stager, something went wrong.
296 297 298 299 300 301 302 303 |
# File 'lib/apcera/stager/stager.rb', line 296 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.
244 245 246 247 248 249 250 |
# File 'lib/apcera/stager/stager.rb', line 244 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
316 317 318 |
# File 'lib/apcera/stager/stager.rb', line 316 def output(text) $stdout.puts text end |
#output_error(text) ⇒ Object
Output to stderr.
311 312 313 |
# File 'lib/apcera/stager/stager.rb', line 311 def output_error(text) $stderr.puts text end |
#provides_add(type, name) ⇒ Object
Add provides to package.
160 161 162 163 164 165 166 167 168 169 |
# File 'lib/apcera/stager/stager.rb', line 160 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.
172 173 174 175 176 177 178 179 180 181 |
# File 'lib/apcera/stager/stager.rb', line 172 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.
261 262 263 264 265 266 |
# File 'lib/apcera/stager/stager.rb', line 261 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.
130 131 132 133 134 |
# File 'lib/apcera/stager/stager.rb', line 130 def snapshot response = RestClient.post(@stager_url+"/snapshot", {}) rescue => e fail e end |
#start_command ⇒ Object
Returns the start command for the package.
276 277 278 |
# File 'lib/apcera/stager/stager.rb', line 276 def start_command self.["environment"]["START_COMMAND"] end |
#start_command=(val) ⇒ Object
Easily set the start command.
281 282 283 |
# File 'lib/apcera/stager/stager.rb', line 281 def start_command=(val) self.environment_add("START_COMMAND", val) end |
#start_path ⇒ Object
Returns the start path for the package.
286 287 288 |
# File 'lib/apcera/stager/stager.rb', line 286 def start_path self.["environment"]["START_PATH"] end |
#start_path=(val) ⇒ Object
Easily set the start path.
291 292 293 |
# File 'lib/apcera/stager/stager.rb', line 291 def start_path=(val) self.environment_add("START_PATH", val) end |
#templates_add(path, left_delimiter = "{{", right_delimiter = "}}") ⇒ Object
Add template to package.
218 219 220 221 222 223 224 225 226 227 228 |
# File 'lib/apcera/stager/stager.rb', line 218 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.
231 232 233 234 235 236 237 238 239 240 241 |
# File 'lib/apcera/stager/stager.rb', line 231 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 it is a noop.
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/apcera/stager/stager.rb', line 110 def upload if @app_path == nil unless File.exist?(@pkg_path) download end upload_file(@pkg_path) else # Use execute instead of execute_app so that if the user provided a dir # to extract into it results in the uploaded package being wrapped in # that directory. execute("cd #{@app_path} && tar czf #{@updated_pkg_path} ./*") upload_file(@updated_pkg_path) end rescue => e fail e end |