Provisioner Plugins
This commit is contained in:
parent
8b6ef27a0f
commit
ff86d86ac8
@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.18.0
|
||||
// protoc v3.15.8
|
||||
// source: vagrant-ruby/builtin/myplugin/proto/plugin.proto
|
||||
|
||||
package proto
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.19.4
|
||||
// protoc v3.15.8
|
||||
// source: proto/ruby_vagrant/ruby-server.proto
|
||||
|
||||
package ruby_vagrant
|
||||
|
||||
import (
|
||||
vagrant_plugin_sdk "github.com/hashicorp/vagrant-plugin-sdk/proto/vagrant_plugin_sdk"
|
||||
_ "google.golang.org/genproto/googleapis/rpc/errdetails"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
_ "google.golang.org/protobuf/types/known/anypb"
|
||||
@ -321,6 +322,8 @@ var file_proto_ruby_vagrant_ruby_server_proto_rawDesc = []byte{
|
||||
0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x65, 0x72,
|
||||
0x72, 0x6f, 0x72, 0x5f, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x1a, 0x0c, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22,
|
||||
0x49, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x07, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73,
|
||||
|
||||
@ -6,6 +6,7 @@ option go_package = "github.com/hashicorp/vagrant/internal/server/proto/ruby_vag
|
||||
|
||||
import "google/protobuf/empty.proto";
|
||||
import "google/protobuf/any.proto";
|
||||
import "google/rpc/error_details.proto";
|
||||
|
||||
import "plugin.proto";
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.19.4
|
||||
// protoc v3.15.8
|
||||
// source: proto/vagrant_server/server.proto
|
||||
|
||||
package vagrant_server
|
||||
@ -9610,7 +9610,8 @@ func (*GetJobStreamResponse_Terminal_Event_Raw_) isGetJobStreamResponse_Terminal
|
||||
|
||||
func (*GetJobStreamResponse_Terminal_Event_Table_) isGetJobStreamResponse_Terminal_Event_Event() {}
|
||||
|
||||
func (*GetJobStreamResponse_Terminal_Event_StepGroup_) isGetJobStreamResponse_Terminal_Event_Event() {}
|
||||
func (*GetJobStreamResponse_Terminal_Event_StepGroup_) isGetJobStreamResponse_Terminal_Event_Event() {
|
||||
}
|
||||
|
||||
func (*GetJobStreamResponse_Terminal_Event_Step_) isGetJobStreamResponse_Terminal_Event_Event() {}
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ module Vagrant
|
||||
autoload :Plugin, "vagrant/plugin/remote/plugin"
|
||||
autoload :Provider, "vagrant/plugin/remote/provider"
|
||||
autoload :Push, "vagrant/plugin/remote/push"
|
||||
autoload :Provisioner, "vagrant/plugin/remote/provisioner"
|
||||
autoload :SyncedFolder, "vagrant/plugin/remote/synced_folder"
|
||||
end
|
||||
end
|
||||
|
||||
@ -190,20 +190,20 @@ module Vagrant
|
||||
end
|
||||
end
|
||||
|
||||
# def provisioners
|
||||
# return real_manager.provisioners if plugin_manager.nil?
|
||||
#
|
||||
# Registry.new.tap do |result|
|
||||
# plugin_manager.list_plugins(:provisioner).each do |plg|
|
||||
# sf_class = Class.new(Remote::Provisioner, &WRAPPER_CLASS)
|
||||
# sf_class.plugin_name = plg[:name]
|
||||
# sf_class.type = plg[:type]
|
||||
# result.register(plg[:name].to_sym) do
|
||||
# sf_class
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
def provisioners
|
||||
return real_manager.provisioners if plugin_manager.nil?
|
||||
|
||||
Registry.new.tap do |result|
|
||||
plugin_manager.list_plugins(:provisioner).each do |plg|
|
||||
sf_class = Class.new(Remote::Provisioner, &WRAPPER_CLASS)
|
||||
sf_class.plugin_name = plg[:name]
|
||||
sf_class.type = plg[:type]
|
||||
result.register(plg[:name].to_sym) do
|
||||
sf_class
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def pushes
|
||||
return real_manager.pushes if plugin_manager.nil?
|
||||
|
||||
47
lib/vagrant/plugin/remote/provisioner.rb
Normal file
47
lib/vagrant/plugin/remote/provisioner.rb
Normal file
@ -0,0 +1,47 @@
|
||||
module Vagrant
|
||||
module Plugin
|
||||
module Remote
|
||||
class Provisioner < V2::Provisioner
|
||||
# Add an attribute accesor for the client
|
||||
attr_accessor :client
|
||||
|
||||
# Provisioner plugins receive machine and config on init that they
|
||||
# expect to set as instance variables and use later. When we're in
|
||||
# server mode, this instance is only a client, and the local plugin
|
||||
# is going to be reinstantiated over on the server side. We will still
|
||||
# needs these two pieces of state on the server side, so in order to
|
||||
# get them over there, we tack them onto the front as args for each
|
||||
# client method call. The server will then peel off those two args
|
||||
# and use them to initialize the plugin in local mode before it
|
||||
# dispatches the method call.
|
||||
#
|
||||
# @see Vagrant::Plugin::V2::Provisioner#initialize the local init
|
||||
# method we're overriding
|
||||
# @see Vagrant::CommandServe::Service::ProvisionerService where we
|
||||
# pop off the two args and reinitialize a local plugin
|
||||
def initialize(machine, config, **opts)
|
||||
@_machine = machine
|
||||
@_config = config
|
||||
if opts[:client].nil?
|
||||
raise ArgumentError,
|
||||
"Remote client is required for `#{self.class.name}`"
|
||||
end
|
||||
@client = opts[:client]
|
||||
super(machine, config)
|
||||
end
|
||||
|
||||
def cleanup
|
||||
client.provision(@_machine, @_config)
|
||||
end
|
||||
|
||||
def configure(root_config)
|
||||
client.configure(@_machine, @_config, root_config)
|
||||
end
|
||||
|
||||
def provision
|
||||
client.provision(@_machine, @_config)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -76,6 +76,20 @@ module Vagrant
|
||||
def method_missing(name, *args, &block)
|
||||
return super if @__finalized
|
||||
|
||||
# There are a few scenarios where ruby will attempt to implicity
|
||||
# coerce a given object into a certain type. Configs can end up
|
||||
# in some of these scenarios when they're being shipped around in
|
||||
# callbacks with splats. If method_missing allows these methods to be
|
||||
# called but continues to return Config back, Ruby will raise a
|
||||
# TypeError. Doing the normal thing of raising NoMethodError allows
|
||||
# Config to behave normally as its being passed through splats.
|
||||
#
|
||||
# For a bit more detail and some keywords for further searching, see:
|
||||
# https://ruby-doc.org/core-2.7.2/doc/implicit_conversion_rdoc.html
|
||||
if [:to_hash, :to_ary].include?(name)
|
||||
return super
|
||||
end
|
||||
|
||||
name = name.to_s
|
||||
name = name[0...-1] if name.end_with?("=")
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ require 'google/protobuf'
|
||||
|
||||
require 'google/protobuf/empty_pb'
|
||||
require 'google/protobuf/any_pb'
|
||||
require 'google/rpc/error_details_pb'
|
||||
require 'plugin_pb'
|
||||
Google::Protobuf::DescriptorPool.generated_pool.build do
|
||||
add_file("proto/ruby_vagrant/ruby-server.proto", :syntax => :proto3) do
|
||||
|
||||
@ -13,6 +13,7 @@ module VagrantPlugins
|
||||
autoload :PluginManager, Vagrant.source_root.join("plugins/commands/serve/client/plugin_manager").to_s
|
||||
autoload :Project, Vagrant.source_root.join("plugins/commands/serve/client/project").to_s
|
||||
autoload :Provider, Vagrant.source_root.join("plugins/commands/serve/client/provider").to_s
|
||||
autoload :Provisioner, Vagrant.source_root.join("plugins/commands/serve/client/provisioner").to_s
|
||||
autoload :Push, Vagrant.source_root.join("plugins/commands/serve/client/push").to_s
|
||||
autoload :Target, Vagrant.source_root.join("plugins/commands/serve/client/target").to_s
|
||||
autoload :Terminal, Vagrant.source_root.join("plugins/commands/serve/client/terminal").to_s
|
||||
|
||||
47
plugins/commands/serve/client/provisioner.rb
Normal file
47
plugins/commands/serve/client/provisioner.rb
Normal file
@ -0,0 +1,47 @@
|
||||
module VagrantPlugins
|
||||
module CommandServe
|
||||
class Client
|
||||
class Provisioner < Client
|
||||
prepend Util::ClientSetup
|
||||
prepend Util::HasLogger
|
||||
include Util::HasSeeds::Client
|
||||
|
||||
def cleanup_func
|
||||
spec = client.cleanup_spec(Empty.new)
|
||||
cb = proc do |args|
|
||||
client.cleanup(args)
|
||||
end
|
||||
[spec, cb]
|
||||
end
|
||||
|
||||
def cleanup(machine, config)
|
||||
run_func(machine, config)
|
||||
end
|
||||
|
||||
def configure_func
|
||||
spec = client.configure_spec(Empty.new)
|
||||
cb = proc do |args|
|
||||
client.configure(args)
|
||||
end
|
||||
[spec, cb]
|
||||
end
|
||||
|
||||
def configure(machine, config, root_config)
|
||||
run_func(machine, config, root_config, {})
|
||||
end
|
||||
|
||||
def provision_func
|
||||
spec = client.provision_spec(Empty.new)
|
||||
cb = proc do |args|
|
||||
client.provision(args)
|
||||
end
|
||||
[spec, cb]
|
||||
end
|
||||
|
||||
def provision(machine, config)
|
||||
run_func(machine, config)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -98,7 +98,7 @@ module VagrantPlugins
|
||||
|
||||
[Service::InternalService, Service::ProviderService, Service::GuestService,
|
||||
Service::HostService, Service::CommandService, Service::SyncedFolderService,
|
||||
Service::CommunicatorService, Service::PushService,
|
||||
Service::CommunicatorService, Service::PushService, Service::ProvisionerService,
|
||||
Broker::Streamer].each do |service_klass|
|
||||
service = service_klass.new(broker: broker)
|
||||
s.handle(service)
|
||||
|
||||
@ -363,6 +363,7 @@ require Vagrant.source_root.join("plugins/commands/serve/mappers/pathname.rb").t
|
||||
require Vagrant.source_root.join("plugins/commands/serve/mappers/plugin_manager.rb").to_s
|
||||
require Vagrant.source_root.join("plugins/commands/serve/mappers/project.rb").to_s
|
||||
require Vagrant.source_root.join("plugins/commands/serve/mappers/provider.rb").to_s
|
||||
require Vagrant.source_root.join("plugins/commands/serve/mappers/provisioner.rb").to_s
|
||||
require Vagrant.source_root.join("plugins/commands/serve/mappers/push.rb").to_s
|
||||
require Vagrant.source_root.join("plugins/commands/serve/mappers/state_bag.rb").to_s
|
||||
require Vagrant.source_root.join("plugins/commands/serve/mappers/synced_folder.rb").to_s
|
||||
|
||||
49
plugins/commands/serve/mappers/provisioner.rb
Normal file
49
plugins/commands/serve/mappers/provisioner.rb
Normal file
@ -0,0 +1,49 @@
|
||||
module VagrantPlugins
|
||||
module CommandServe
|
||||
class Mappers
|
||||
# Build a guest client from a proto instance
|
||||
class ProvisionerFromProto < Mapper
|
||||
def initialize
|
||||
inputs = [].tap do |i|
|
||||
i << Input.new(type: SDK::Args::Provisioner)
|
||||
i << Input.new(type: Broker)
|
||||
end
|
||||
super(inputs: inputs, output: Client::Provisioner, func: method(:converter))
|
||||
end
|
||||
|
||||
def converter(proto, broker)
|
||||
Client::Provisioner.load(proto, broker: broker)
|
||||
end
|
||||
end
|
||||
|
||||
class GeneralConfigFromSpec < Mapper
|
||||
def initialize
|
||||
inputs = [].tap do |i|
|
||||
i << Input.new(type: SDK::FuncSpec::Value) { |arg|
|
||||
arg.type == "hashicorp.vagrant.sdk.Vagrantfile.GeneralConfig" &&
|
||||
!arg&.value&.value.nil?
|
||||
}
|
||||
end
|
||||
super(inputs: inputs, output: SDK::Vagrantfile::GeneralConfig, func: method(:converter))
|
||||
end
|
||||
|
||||
def converter(proto)
|
||||
proto.value.unpack(SDK::Vagrantfile::GeneralConfig)
|
||||
end
|
||||
end
|
||||
|
||||
class ConfigToProto < Mapper
|
||||
def initialize
|
||||
inputs = [].tap do |i|
|
||||
i << Input.new(type: Vagrant::Plugin::V2::Config)
|
||||
end
|
||||
super(inputs: inputs, output: SDK::Vagrantfile::GeneralConfig, func: method(:converter))
|
||||
end
|
||||
|
||||
def converter(config)
|
||||
config.to_proto(config.class.to_s)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -10,6 +10,7 @@ module VagrantPlugins
|
||||
autoload :HostService, Vagrant.source_root.join("plugins/commands/serve/service/host_service").to_s
|
||||
autoload :InternalService, Vagrant.source_root.join("plugins/commands/serve/service/internal_service").to_s
|
||||
autoload :ProviderService, Vagrant.source_root.join("plugins/commands/serve/service/provider_service").to_s
|
||||
autoload :ProvisionerService, Vagrant.source_root.join("plugins/commands/serve/service/provisioner_service").to_s
|
||||
autoload :SyncedFolderService, Vagrant.source_root.join("plugins/commands/serve/service/synced_folder_service").to_s
|
||||
autoload :PushService, Vagrant.source_root.join("plugins/commands/serve/service/push_service").to_s
|
||||
|
||||
|
||||
130
plugins/commands/serve/service/provisioner_service.rb
Normal file
130
plugins/commands/serve/service/provisioner_service.rb
Normal file
@ -0,0 +1,130 @@
|
||||
module VagrantPlugins
|
||||
module CommandServe
|
||||
module Service
|
||||
class ProvisionerService < Hashicorp::Vagrant::Sdk::ProvisionerService::Service
|
||||
prepend Util::HasMapper
|
||||
prepend Util::HasBroker
|
||||
prepend Util::HasLogger
|
||||
|
||||
include Util::ServiceInfo
|
||||
include Util::HasSeeds::Service
|
||||
include Util::ExceptionTransformer
|
||||
|
||||
def cleanup(req, ctx)
|
||||
machine, plugin_config = _process_args(req)
|
||||
|
||||
provisioner =_lookup_or_instantiate_provisioner(req, ctx, machine, plugin_config)
|
||||
|
||||
provisioner.cleanup
|
||||
end
|
||||
|
||||
def cleanup_spec(*_)
|
||||
SDK::FuncSpec.new(
|
||||
name: "cleanup_spec",
|
||||
args: [
|
||||
SDK::FuncSpec::Value.new(
|
||||
type: "hashicorp.vagrant.sdk.Args.Target.Machine",
|
||||
name: "",
|
||||
),
|
||||
SDK::FuncSpec::Value.new(
|
||||
type: "hashicorp.vagrant.sdk.Vagrantfile.GeneralConfig",
|
||||
name: "",
|
||||
)
|
||||
],
|
||||
result: [],
|
||||
)
|
||||
end
|
||||
|
||||
def configure(req, ctx)
|
||||
machine, plugin_config = _process_args(req)
|
||||
|
||||
provisioner =_lookup_or_instantiate_provisioner(req, ctx, machine, plugin_config)
|
||||
|
||||
provisioner.configure(machine.config)
|
||||
|
||||
Empty.new
|
||||
end
|
||||
|
||||
def configure_spec(*_)
|
||||
SDK::FuncSpec.new(
|
||||
name: "configure_spec",
|
||||
args: [
|
||||
SDK::FuncSpec::Value.new(
|
||||
type: "hashicorp.vagrant.sdk.Args.Target.Machine",
|
||||
name: "",
|
||||
),
|
||||
SDK::FuncSpec::Value.new(
|
||||
type: "hashicorp.vagrant.sdk.Vagrantfile.GeneralConfig",
|
||||
name: "",
|
||||
)
|
||||
],
|
||||
result: [],
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
def provision(req, ctx)
|
||||
machine, plugin_config = _process_args(req)
|
||||
|
||||
provisioner =_lookup_or_instantiate_provisioner(req, ctx, machine, plugin_config)
|
||||
|
||||
provisioner.provision
|
||||
|
||||
Empty.new
|
||||
end
|
||||
|
||||
def provision_spec(*_)
|
||||
SDK::FuncSpec.new(
|
||||
name: "provision_spec",
|
||||
args: [
|
||||
SDK::FuncSpec::Value.new(
|
||||
type: "hashicorp.vagrant.sdk.Args.Target.Machine",
|
||||
name: "",
|
||||
),
|
||||
SDK::FuncSpec::Value.new(
|
||||
type: "hashicorp.vagrant.sdk.Vagrantfile.GeneralConfig",
|
||||
name: "",
|
||||
)
|
||||
],
|
||||
result: [],
|
||||
)
|
||||
end
|
||||
|
||||
# All of the methods here take the same args, so they have the same
|
||||
# args processing which can be shared
|
||||
#
|
||||
# @param req the request
|
||||
# @return [Array(Vagrant::Machine, Vagrant::Plugin::V2::Config)]
|
||||
def _process_args(req)
|
||||
machine, config = mapper.funcspec_map(
|
||||
req, mapper, broker, expect: [
|
||||
Vagrant::Machine, SDK::Vagrantfile::GeneralConfig
|
||||
]
|
||||
)
|
||||
config_klass = config.type.split('::').inject(Kernel) { |memo, obj|
|
||||
memo.const_get(obj)
|
||||
}
|
||||
config_data = config.config.unpack(Google::Protobuf::Struct).to_h
|
||||
plugin_config = config_klass.new
|
||||
plugin_config.set_options(config_data)
|
||||
return machine, plugin_config
|
||||
end
|
||||
|
||||
def _lookup_or_instantiate_provisioner(req, ctx, machine, plugin_config)
|
||||
@_provisioner_cache ||= {}
|
||||
key = ctx.metadata["plugin_name"]
|
||||
if @_provisioner_cache[key] != nil
|
||||
return @_provisioner_cache[key]
|
||||
else
|
||||
plugins = Vagrant.plugin("2").local_manager.provisioners
|
||||
with_plugin(ctx, plugins, broker: broker) do |plugin|
|
||||
provisioner = plugin.new(machine, plugin_config)
|
||||
@_provisioner_cache[key] = provisioner
|
||||
return provisioner
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -35,7 +35,7 @@ module VagrantPlugins
|
||||
def with_plugin(context, plugins, broker:, &block)
|
||||
with_info(context, broker: broker) do |info|
|
||||
plugin_name = info.plugin_name
|
||||
plugin = plugins[plugin_name.to_s.to_sym].to_a.first
|
||||
plugin = Array(plugins[plugin_name.to_s.to_sym]).first
|
||||
if !plugin
|
||||
raise NameError, "Failed to locate plugin named #{plugin_name}"
|
||||
end
|
||||
|
||||
@ -72,5 +72,12 @@ describe Vagrant::Plugin::V2::Config do
|
||||
expect { subject.i_should_not_exist }.
|
||||
to raise_error(NoMethodError)
|
||||
end
|
||||
|
||||
it "should survive being the last arg to a method that captures kwargs without a ruby conversion error" do
|
||||
arg_capturer = lambda { |*args, **kwargs| }
|
||||
expect {
|
||||
arg_capturer.call(subject)
|
||||
}.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user