require "google/protobuf/well_known_types" module VagrantPlugins module CommandServe module Service class CommunicatorService < ProtoService(SDK::CommunicatorService::Service) def ready_spec(*_) logger.debug("generating ready spec") funcspec( args: [ SDK::Args::Target::Machine, ], result: SDK::Communicator::ReadyResp, ) end def ready(req, ctx) with_plugin(ctx, :communicators, broker: broker) do |plugin| machine = mapper.funcspec_map( req, mapper, broker, expect: [Vagrant::Machine] ) communicator = load_communicator(plugin, machine) ready = communicator.ready? SDK::Communicator::ReadyResp.new( ready: ready ) end end def wait_for_ready_spec(*_) funcspec( args: [ SDK::Args::Target::Machine, SDK::Args::TimeDuration, ], result: SDK::Communicator::ReadyResp, ) end def wait_for_ready(req, ctx) with_plugin(ctx, :communicators, broker: broker) do |plugin| machine, wait_duration = mapper.funcspec_map( req, mapper, broker, expect: [Vagrant::Machine, SDK::Args::TimeDuration] ) communicator = load_communicator(plugin, machine) begin ready = communicator.wait_for_ready(wait_duration.duration) rescue => err logger.error(err) logger.debug("#{err.class}: #{err}\n#{err.backtrace.join("\n")}") raise end logger.debug("ready? #{ready}") SDK::Communicator::ReadyResp.new( ready: ready ) end end def download_spec(*_) funcspec( args: [ SDK::Args::Target::Machine, ], named: { source: SDK::Args::Path, destination: SDK::Args::Path, }, ) end def download(req, ctx) logger.debug("Downloading") with_plugin(ctx, :communicators, broker: broker) do |plugin| dest_proto = req.args.select{ |a| a.name == "destination" }.first to = mapper.map(dest_proto.value, to: Pathname).to_s source_proto = req.args.select{ |a| a.name == "source" }.first from = mapper.map(source_proto.value, to: Pathname).to_s req.args.reject!{ |a| a.name == "source" || a.name == "destination" } machine = mapper.funcspec_map( req, mapper, broker, expect: [Vagrant::Machine] ) communicator = load_communicator(plugin, machine) communicator.download(from, to) Empty.new end end def upload_spec(*_) funcspec( args: [ SDK::Args::Target::Machine, ], named: { source: SDK::Args::Path, destination: SDK::Args::Path, } ) end def upload(req, ctx) logger.debug("Uploading") with_plugin(ctx, :communicators, broker: broker) do |plugin| dest_proto = req.args.select{ |a| a.name == "destination" }.first to = mapper.map(dest_proto.value, to: Pathname).to_s source_proto = req.args.select{ |a| a.name == "source" }.first from = mapper.map(source_proto.value, to: Pathname).to_s req.args.reject!{ |a| a.name == "source" || a.name == "destination" } machine = mapper.funcspec_map( req, mapper, broker, expect: [Vagrant::Machine] ) communicator = load_communicator(plugin, machine) communicator.upload(from, to) Empty.new end end def execute_spec(*_) funcspec( args: [ SDK::Args::Target::Machine, SDK::Communicator::Command, SDK::Args::Options, ], result: SDK::Communicator::ExecuteResp, ) end def execute(req, ctx) with_plugin(ctx, :communicators, broker: broker) do |plugin| machine, cmd, opts = mapper.funcspec_map( req, mapper, broker, expect: [Vagrant::Machine, SDK::Communicator::Command, Type::Options] ) communicator = load_communicator(plugin, machine) output = {stdout: '', stderr: ''} exit_code = communicator.execute(cmd.command, opts.value) { |type, data| output[type] << data if output[type] } SDK::Communicator::ExecuteResp.new( exit_code: exit_code, stdout: output[:stdout], stderr: output[:stderr] ) end end def privileged_execute_spec(*_) funcspec( args: [ SDK::Args::Target::Machine, SDK::Communicator::Command, SDK::Args::Options, ], result: SDK::Communicator::ExecuteResp, ) end def privileged_execute(req, ctx) with_plugin(ctx, :communicators, broker: broker) do |plugin| machine, cmd, opts = mapper.funcspec_map( req, mapper, broker, expect: [Vagrant::Machine, SDK::Communicator::Command, Type::Options] ) communicator = load_communicator(plugin, machine) output = {stdout: '', stderr: ''} exit_code = communicator.sudo(cmd.command, opts.value) { |type, data| output[type] << data if output[type] } SDK::Communicator::ExecuteResp.new( exit_code: exit_code, stdout: output[:stdout], stderr: output[:stderr] ) end end def test_spec(*_) funcspec( args: [ SDK::Args::Target::Machine, SDK::Communicator::Command, SDK::Args::Options, ], result: SDK::Communicator::TestResp, ) end def test(req, ctx) with_plugin(ctx, :communicators, broker: broker) do |plugin| machine, cmd, opts = mapper.funcspec_map( req, mapper, broker, expect: [Vagrant::Machine, SDK::Communicator::Command, Type::Options] ) communicator = load_communicator(plugin, machine) valid = communicator.test(cmd.command, opts.value) logger.debug("command is valid?: #{valid}") SDK::Communicator::TestResp.new( valid: valid ) end end def reset_spec(*_) funcspec( args: [ SDK::Args::Target::Machine, ], ) end def reset(req, ctx) with_plugin(ctx, :communicators, broker: broker) do |plugin| machine = mapper.funcspec_map( req, mapper, broker, expect: [Vagrant::Machine] ) communicator = load_communicator(plugin, machine) communicator.reset Empty.new end end def load_communicator(klass, machine) key = cache.key(klass, machine) return cache.get(key) if cache.registered?(key) klass.new(machine).tap do |i| cache.register(key, i) end end end end end end