class Asteroid::Instance
Attributes
id[R]
ip_address[R]
logger[RW]
name[R]
namespace[R]
provider[R]
server[R]
type[R]
Public Class Methods
all()
click to toggle source
# File lib/asteroid/instance.rb, line 76 def self.all instances = Provider.all.instances instances = instances.map do |info| new info end if Config.namespace instances = instances.delete_if do |i| i.namespace != Config.namespace end end instances end
all_with_type(type)
click to toggle source
# File lib/asteroid/instance.rb, line 95 def self.all_with_type(type) all.select{|i| i.type == type} end
find(id)
click to toggle source
# File lib/asteroid/instance.rb, line 119 def self.find(id) all.select{|i| i.id == id || i.id.to_s == id.to_s}.first end
first(type)
click to toggle source
# File lib/asteroid/instance.rb, line 91 def self.first(type) all_with_type(type).first end
new(options = {})
click to toggle source
# File lib/asteroid/instance.rb, line 34 def initialize(options = {}) options = options.dup o = options.dup @server = options.delete :server @type = options.delete :type @id = options.delete :id @name = options.delete :name @ip_address = options.delete :ip_address if @name =~ /:/ @namespace, @name = @name.split(':', 2) end if @name && @type.nil? @type = name.split('-').first.to_sym end if @server.nil? && @type.nil? raise "Instance must have a server type :type attribute" elsif @server.nil? @server = Server.named @type end if @provider end @attributes = options server.provider.required_instance_attributes.each do |att| require_attribute att end # The type is added on the name @attributes[:type] ||= if @attributes[:name] @attributes[:name].match(/[a-z]+/)[0].to_sym end end
Public Instance Methods
[](k)
click to toggle source
# File lib/asteroid/instance/vars.rb, line 7 def [](k) val = config_get k val.nil? ? server_defaults[k] : val end
[]=(k, v)
click to toggle source
# File lib/asteroid/instance/vars.rb, line 12 def []=(k, v) config_set k, v end
aster_environment()
click to toggle source
# File lib/asteroid/instance/command.rb, line 82 def aster_environment @aster_environment ||= Aster::Environment.new.tap do |e| self.server.commands.each_pair do |name, data| data = case data when Array {args: [], steps: data} when Object data else raise "Commands should be Arrays or arguments or Objects" end commands = Aster::Parser.new.send :parse_lines, data[:steps] e.define_function name, data[:args], commands end e.define_function :run, [:"..."] do |arguments| command_run(arguments.join(' ')) end e.define_function :upload, [:"..."] do |(from, to, _)| if command_upload from, to "yes" else "no" end end e.define_function :exec, [:"..."] do |arguments| command_exec(arguments.join(' ')) end end end
command_command(cmd, args, env)
click to toggle source
# File lib/asteroid/instance/command.rb, line 46 def command_command(cmd, args, env) raise "Not here" env ||= template_data command = server.commands[cmd] env = if command["args"] command["args"].inject({}) do |r, k| r[k] = args.shift r end end env = template_data.merge({ args: env }) command["steps"].map do |step| eval_command step, env end.last end
command_config(set_or_get, var, val)
click to toggle source
# File lib/asteroid/instance/command.rb, line 172 def command_config(set_or_get, var, val) if set_or_get.to_s == "set" self.config_set(var, val) elsif set_or_get == "get" self.config_get(var) end end
command_exec(command, env = nil)
click to toggle source
# File lib/asteroid/instance/command.rb, line 168 def command_exec(command, env = nil) self.ssh_exec command end
command_run(script_name, env = nil)
click to toggle source
# File lib/asteroid/instance/command.rb, line 124 def command_run(script_name, env = nil) env ||= template_data script = Script.named(script_name) # touch ssh self.ssh if script.nil? raise "No script named #{script_name}" end # Return early if we're running a script if script.yml? # TODO: send the fucking script obj command_run_yml_script(script_name) return elsif script.aster? command_run_aster_script(script_name) return end if script.template? script.set_data env end rendered_script = script.render puts rendered_script puts self.ssh_exec rendered_script end
command_run_aster_script(aster_script, env = nil)
click to toggle source
# File lib/asteroid/instance/command.rb, line 118 def command_run_aster_script(aster_script, env = nil) filename = File.join(Asteroid::Config.script_dir, '/', aster_script) script = File.read(filename) aster_environment.eval script end
command_run_yml_script(yml_script, env = nil)
click to toggle source
# File lib/asteroid/instance/command.rb, line 67 def command_run_yml_script(yml_script, env = nil) env ||= template_data filename = File.join(Asteroid::Config.script_dir, '/', yml_script) script = File.read(filename) yml = Template.new(:erb, script).render(env) data = YAML::load yml unless data["steps"] raise "No steps in #{filenbame}" else data["steps"].each do |step| eval_command step, env end end end
command_upload(from, to, env = nil)
click to toggle source
# File lib/asteroid/instance/command.rb, line 155 def command_upload(from, to, env = nil) env ||= template_data from = FileReference.new(from) if from.template? from.data = env end puts from.rendered_filename self.scp_upload from.rendered_filename, to end
config_filename()
click to toggle source
# File lib/asteroid/instance/vars.rb, line 28 def config_filename unless File.directory?(Asteroid::Config.secret_instance_dir) FileUtils.mkdir Asteroid::Config.secret_instance_dir end File.join(Asteroid::Config.secret_instance_dir, "/instance_#{@id}.yml") end
config_get(k)
click to toggle source
# File lib/asteroid/instance/vars.rb, line 16 def config_get(k) data = load_config_data data && data[k] end
config_set(k, v)
click to toggle source
# File lib/asteroid/instance/vars.rb, line 21 def config_set(k, v) data = load_config_data data[k] = v save_config_data data v end
destroy()
click to toggle source
# File lib/asteroid/instance.rb, line 133 def destroy server.provider.destroy_instance self end
env()
click to toggle source
# File lib/asteroid/instance.rb, line 123 def env { "INSTANCE_PRIVATE_KEY" => self.server.ssh_key_filename, "INSTANCE_SSH_PORT" => self["ssh.port"].to_i, "INSTANCE_SSH_LOGIN" => self["login.username"], "INSTANCE_IP_ADDRESS" => self.ip_address, "INSTANCE_ID" => self.id, } end
eval_command(cmd)
click to toggle source
# File lib/asteroid/instance/command.rb, line 9 def eval_command(cmd) return aster_environment.eval(cmd) # env ||= template_data # cmd = Template.new(:erb, cmd).render(env) # cmd, *rest = cmd.split(" ") # case cmd.to_sym # when :run # command_run(rest.first, env) # when :upload # from, to, _ = rest # command_upload(from, to, env) # when :"upload-private-key" # name, _ = rest # command_upload_private_key(name, env) # when :exec # script = rest.join(" ") # command_exec(script, env) # when :config # set_or_get, var, val, _ = rest # command_config(set_or_get, var, val) # else # if server.commands[cmd] # command_command(cmd, rest, env) # else # end # end end
load_config_data()
click to toggle source
# File lib/asteroid/instance/vars.rb, line 35 def load_config_data begin YAML::load_file config_filename rescue {} end end
mock_file_system()
click to toggle source
# File lib/asteroid/instance/scp.rb, line 23 def mock_file_system @mock_file_system ||= {} end
password(username = nil)
click to toggle source
# File lib/asteroid/instance.rb, line 99 def password(username = nil) username ||= self["login.username"] password_filename = File.join(Asteroid::Config.password_dir, "/instance_#{@id}-user_#{username}") if File.exists? password_filename File.read(password_filename) else password = SecureRandom.hex(64) File.open(password_filename, 'w'){|f| f.write password} password end end
render_erb(string, env)
click to toggle source
# File lib/asteroid/instance/command.rb, line 5 def render_erb(string, env) Template.new(:erb, string).render(env) end
save_config_data(data)
click to toggle source
# File lib/asteroid/instance/vars.rb, line 43 def save_config_data(data) File.open(config_filename, 'w') {|f| f.write data.to_yaml } end
scp()
click to toggle source
# File lib/asteroid/instance/scp.rb, line 27 def scp if server.provider.type == :mock return @mock_scp ||= MockSCP.new(mock_file_system) end if @scp && (@scp.session.transport.port.to_s != self["ssh.port"] || (@scp.session.transport.options[:user] != self["login.username"])) @scp = nil end @scp ||= Net::SCP.start( ip_address, self["login.username"], port: self["ssh.port"].to_i, :keys => [server.ssh_key_filename] ) end
scp_upload(from, to)
click to toggle source
# File lib/asteroid/instance/scp.rb, line 19 def scp_upload(from, to) scp.upload! from, to end
server_defaults()
click to toggle source
# File lib/asteroid/instance.rb, line 111 def server_defaults server.instance_config end
ssh()
click to toggle source
# File lib/asteroid/instance/ssh.rb, line 16 def ssh if @ssh && (@ssh.transport.port.to_s != self["ssh.port"] || (@ssh.transport.options[:user] != self["login.username"])) @ssh = nil end @ssh ||= Net::SSH.start( ip_address, self["login.username"], port: self["ssh.port"].to_i, :keys => [server.ssh_key.private.filename] ) end
ssh_exec(command)
click to toggle source
# File lib/asteroid/instance/ssh.rb, line 6 def ssh_exec(command) ssh.exec!(command) do |channel, stream, data| if stream == :stdout puts data else puts data end end end
template_data()
click to toggle source
# File lib/asteroid/instance/command.rb, line 40 def template_data { instance: self, server: server } end
Private Instance Methods
require_attribute(name)
click to toggle source
# File lib/asteroid/instance.rb, line 139 def require_attribute(name) if @attributes[name].nil? raise MissingAttributeError.new(name) end end