Chris Roberts e958c6183a Adds initial HCP config support
Adds initial basic support for HCP based configuration in vagrant-go.
The initalization process has been updated to remove Vagrantfile parsing
from the client, moving it to the runner using init jobs for the basis
and the project (if there is one). Detection is done on the file based
on extension for Ruby based parsing or HCP based parsing.

Current HCP parsing is extremely simple and currently just a base to
build off. Config components will be able to implement an `Init`
function to handle receiving configuration data from a non-native source
file. This will be extended to include a default approach for injecting
defined data in the future.

Some cleanup was done in the state around validations. Some logging
adjustments were applied on the Ruby side for better behavior
consistency.

VirtualBox provider now caches locale detection to prevent multiple
checks every time the driver is initialized.
2023-09-07 17:26:10 -07:00

145 lines
5.0 KiB
Ruby

# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
require "optparse"
module VagrantPlugins
module CommandServe
autoload :Broker, Vagrant.source_root.join("plugins/commands/serve/broker").to_s
autoload :Client, Vagrant.source_root.join("plugins/commands/serve/client").to_s
autoload :Mappers, Vagrant.source_root.join("plugins/commands/serve/mappers").to_s
autoload :Service, Vagrant.source_root.join("plugins/commands/serve/service").to_s
autoload :Type, Vagrant.source_root.join("plugins/commands/serve/type").to_s
autoload :Util, Vagrant.source_root.join("plugins/commands/serve/util").to_s
autoload :SDK, Vagrant.source_root.join("plugins/commands/serve/constants").to_s
autoload :SRV, Vagrant.source_root.join("plugins/commands/serve/constants").to_s
autoload :Empty, Vagrant.source_root.join("plugins/commands/serve/constants").to_s
class << self
attr_accessor :broker
attr_accessor :server
attr_reader :cache
# Loads the required dependencies for this command. This is isolated
# into a method so that the dependencies can be loaded just in time when
# the command is actually executed.
def load_dependencies!
return if @dependencies_loaded
require 'grpc'
require 'grpc/health/checker'
require 'grpc/health/v1/health_services_pb'
# Add conversion patches
require Vagrant.source_root.join("plugins/commands/serve/util/direct_conversions.rb").to_s
# Mark dependencies as loaded
@dependencies_loaded = true
end
end
@cache = Util::Cacher.new
class Command < Vagrant.plugin("2", :command)
DEFAULT_BIND = "localhost"
DEFAULT_PORT_RANGE = 40000..50000
include Util::HasLogger
def self.synopsis
"start Vagrant server"
end
def execute
# Load dependencies before we start
CommandServe.load_dependencies!
options = {
bind: DEFAULT_BIND,
min_port: DEFAULT_PORT_RANGE.first,
max_port: DEFAULT_PORT_RANGE.last,
}
opts = OptionParser.new do |o|
o.banner = "Usage: vagrant serve"
o.separator ""
o.separator "Options:"
o.separator ""
o.on("--bind ADDR", "Bind to specific address. Default: #{DEFAULT_BIND}") do |addr|
options[:bind] = addr
end
o.on("--min-port PORT", "Minimum port number to use. Default: #{DEFAULT_PORT_RANGE.first}") do |port|
options[:min_port] = port
end
o.on("--max-port PORT", "Maximum port number to use. Default: #{DEFAULT_PORT_RANGE.last}") do |port|
options[:max_port] = port
end
end
# Parse the options
argv = parse_options(opts)
return if !argv
ports = options[:min_port].to_i .. options[:max_port].to_i
serve(options[:bind], ports)
end
private
def serve(bind_addr = "localhost", ports = DEFAULT_PORT_RANGE)
logger.info("Starting Vagrant GRPC service addr=#{bind_addr.inspect} ports=#{ports.inspect}")
s = GRPC::RpcServer.new
port = nil
ports.each do |p|
begin
port = s.add_http2_port("#{bind_addr}:#{p}", :this_port_is_insecure)
break
rescue RuntimeError
# Assuming port in use, trying next
end
end
raise "Failed to bind GRPC server listener" if port.nil?
health_checker = Grpc::Health::Checker.new
broker = Broker.new(bind: bind_addr, ports: ports)
CommandServe.broker = broker
logger.debug("vagrant grpc broker started for grpc service addr=#{bind_addr} ports=#{ports.inspect}")
[Broker::Streamer,
Service::CommandService,
Service::CommunicatorService,
Service::ConfigService,
Service::GuestService,
Service::HostService,
Service::InternalService,
Service::ProviderService,
Service::ProvisionerService,
Service::PushService,
Service::SyncedFolderService,
].each do |service_klass|
service = service_klass.new(broker: broker)
s.handle(service)
health_checker.add_status(service_klass,
Grpc::Health::V1::HealthCheckResponse::ServingStatus::SERVING)
logger.debug("enabled Vagrant GRPC service: #{service_klass.name.split('::').last}")
end
s.handle(health_checker)
logger.debug("writing connection information to stdout for go-plugin")
STDOUT.puts "1|1|tcp|#{bind_addr}:#{port}|grpc"
STDOUT.flush
logger.info("Vagrant GRPC service is now running addr=#{bind_addr.inspect} port=#{port.inspect}")
VagrantPlugins::CommandServe.server = s
s.run_till_terminated_or_interrupted(['EXIT', 'HUP', 'INT', 'QUIT', 'ABRT'])
0
ensure
VagrantPlugins::CommandServe.server = nil
logger.info("Vagrant GRPC service shut down")
end
end
end
end