178 lines
6.2 KiB
Ruby
178 lines
6.2 KiB
Ruby
# Copyright (c) HashiCorp, Inc.
|
|
# SPDX-License-Identifier: BUSL-1.1
|
|
|
|
require "vagrant/plugin/v2/plugin"
|
|
require "vagrant/vagrantfile"
|
|
require "vagrant/box_collection"
|
|
require "vagrant/config"
|
|
require "pathname"
|
|
|
|
require 'google/protobuf/well_known_types'
|
|
|
|
module VagrantPlugins
|
|
module CommandServe
|
|
module Service
|
|
class InternalService < ProtoService(Hashicorp::Vagrant::RubyVagrant::Service)
|
|
|
|
def get_plugins(req, _)
|
|
plugins = []
|
|
plugin_manager = Vagrant::Plugin::V2::Plugin.local_manager
|
|
globalized_plugins = Vagrant::Plugin::Manager.instance.globalize!
|
|
Vagrant::Plugin::Manager.instance.load_plugins(globalized_plugins)
|
|
plugins = [[:commands, :COMMAND],
|
|
[:communicators, :COMMUNICATOR],
|
|
[:config, :CONFIG],
|
|
[:guests, :GUEST],
|
|
[:hosts, :HOST],
|
|
[:provider_configs, :CONFIG],
|
|
[:providers, :PROVIDER],
|
|
[:provisioner_configs, :CONFIG],
|
|
[:provisioners, :PROVISIONER],
|
|
[:push_configs, :CONFIG],
|
|
[:pushes, :PUSH],
|
|
[:synced_folders, :SYNCEDFOLDER]].map do |method, const|
|
|
plugin_manager.send(method).map do |k, v|
|
|
Hashicorp::Vagrant::Plugin.new(
|
|
name: k,
|
|
type: Hashicorp::Vagrant::Plugin::Type.const_get(const),
|
|
options: Google::Protobuf::Any.pack(
|
|
_convert_options_to_proto(const, v)
|
|
)
|
|
)
|
|
end
|
|
end.flatten
|
|
Hashicorp::Vagrant::GetPluginsResponse.new(
|
|
plugins: plugins
|
|
)
|
|
end
|
|
|
|
def stop(_, _)
|
|
if !VagrantPlugins::CommandServe.server.nil?
|
|
logger.info("stopping the Vagrant Ruby runtime service")
|
|
# We want to hop into a separate thread and pause for a moment
|
|
# so we can send our response, then stop the server.
|
|
Thread.new do
|
|
sleep(0.05)
|
|
VagrantPlugins::CommandServe.server.stop
|
|
end
|
|
else
|
|
logger.warn("cannot stop Vagrant Ruby runtime service, not running")
|
|
end
|
|
Empty.new
|
|
end
|
|
|
|
def parse_vagrantfile(req, _)
|
|
parse_item_to_proto(req.path.to_s)
|
|
end
|
|
|
|
def parse_vagrantfile_proc(req, _)
|
|
callable = mapper.map(req.proc, to: Proc)
|
|
|
|
parse_item_to_proto([["2", callable]])
|
|
end
|
|
|
|
def parse_vagrantfile_subvm(req, _)
|
|
subvm = mapper.map(req.subvm)
|
|
# If the subvm has no custom configuration, just return an empty result
|
|
if subvm.config_procs.empty?
|
|
return Hashicorp::Vagrant::ParseVagrantfileResponse.new(
|
|
data: SDK::Args::Hash.new(entries: [])
|
|
)
|
|
end
|
|
|
|
parse_item_to_proto(subvm.config_procs)
|
|
end
|
|
|
|
def parse_vagrantfile_provider(req, _)
|
|
subvm = mapper.map(req.subvm)
|
|
provider = req.provider.to_sym
|
|
|
|
# If the subvm has no custom configuration, just return an empty result
|
|
if subvm.config_procs.empty?
|
|
return Hashicorp::Vagrant::ParseVagrantfileResponse.new(
|
|
data: SDK::Args::Hash.new(entries: [])
|
|
)
|
|
end
|
|
|
|
config = parse_item(subvm.config_procs)
|
|
overrides = config.vm.get_provider_overrides(provider)
|
|
|
|
# If the overrides are empty then no overrides were provided, just return
|
|
# an empty result
|
|
if overrides.empty?
|
|
return Hashicorp::Vagrant::ParseVagrantfileResponse.new(
|
|
data: SDK::Args::Hash.new(entries: [])
|
|
)
|
|
end
|
|
|
|
parse_item_to_proto(overrides)
|
|
end
|
|
|
|
def parse_item(item)
|
|
loader = Vagrant::Config::Loader.new(
|
|
Vagrant::Config::VERSIONS,
|
|
Vagrant::Config::VERSIONS_ORDER
|
|
)
|
|
loader.set(:item, item)
|
|
loader.partial_load(:item)
|
|
end
|
|
|
|
def parse_item_to_proto(item)
|
|
config = parse_item(item)
|
|
Hashicorp::Vagrant::ParseVagrantfileResponse.new(
|
|
data: config.to_proto,
|
|
)
|
|
end
|
|
|
|
def _convert_options_to_proto(type, class_or_tuple_with_class_and_options)
|
|
case type
|
|
when :COMMAND
|
|
_, opts = class_or_tuple_with_class_and_options
|
|
return SDK::PluginInfo::CommandOptions.new(
|
|
# Primary is always set in V2::Plugin.command
|
|
primary: opts[:primary],
|
|
)
|
|
when :COMMUNICATOR
|
|
# No options for communicators
|
|
return Google::Protobuf::Empty.new
|
|
when :CONFIG
|
|
# No options for configs
|
|
return Google::Protobuf::Empty.new
|
|
when :GUEST
|
|
# No options for guests
|
|
return Google::Protobuf::Empty.new
|
|
when :HOST
|
|
# _, parent = class_or_tuple_with_class_and_options
|
|
return Google::Protobuf::Empty.new
|
|
when :PROVIDER
|
|
_, popts = class_or_tuple_with_class_and_options
|
|
return SDK::PluginInfo::ProviderOptions.new(
|
|
# Priority is always set in V2::Plugin.provider
|
|
priority: popts[:priority],
|
|
# Parallel is defaults to falsy when its passed along as an arg to Environment#batch.
|
|
parallel: popts.fetch(:parallel, false),
|
|
# BoxOptional defaults to falsy when it's used in Kernel_V2::VMConfig
|
|
box_optional: popts.fetch(:box_optional, false),
|
|
# Defaultable is considered true when it is not specified in Environment#default_provider
|
|
defaultable: popts.fetch(:defaultable, true),
|
|
)
|
|
when :PROVISIONER
|
|
# No options for provisioners
|
|
return Google::Protobuf::Empty.new
|
|
when :PUSH
|
|
# Push plugins accept an options hash but it's never used.
|
|
return Google::Protobuf::Empty.new
|
|
when :SYNCEDFOLDER
|
|
_, sf_priority = class_or_tuple_with_class_and_options
|
|
return SDK::PluginInfo::SyncedFolderOptions.new(
|
|
priority: sf_priority,
|
|
)
|
|
else
|
|
raise "Cannot convert options for unknown component type: #{type}"
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|