From 255c75eeba841e1459ab1afc9452f06b6bd6c2d2 Mon Sep 17 00:00:00 2001 From: Chris Roberts Date: Mon, 13 Jun 2022 15:57:06 -0700 Subject: [PATCH] Load Vagrantfile from the client --- internal/client/basis.go | 41 ++++++++-------------- internal/client/client.go | 71 ++++++++++++++++++++++++++++++++++++-- internal/client/project.go | 51 +++++++++++++-------------- 3 files changed, 109 insertions(+), 54 deletions(-) diff --git a/internal/client/basis.go b/internal/client/basis.go index 1f52f60b0..b7df3720e 100644 --- a/internal/client/basis.go +++ b/internal/client/basis.go @@ -2,7 +2,6 @@ package client import ( "context" - "fmt" "io" "os" @@ -11,10 +10,10 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + "github.com/hashicorp/vagrant-plugin-sdk/config" "github.com/hashicorp/vagrant-plugin-sdk/helper/path" "github.com/hashicorp/vagrant-plugin-sdk/proto/vagrant_plugin_sdk" "github.com/hashicorp/vagrant-plugin-sdk/terminal" - configpkg "github.com/hashicorp/vagrant/internal/config" "github.com/hashicorp/vagrant/internal/server/proto/vagrant_server" "github.com/hashicorp/vagrant/internal/serverclient" ) @@ -32,7 +31,7 @@ type Basis struct { func (b *Basis) DetectProject() (p *Project, err error) { // look for a vagrantfile! - v, err := configpkg.FindPath(nil, "") + v, err := config.FindPath(nil, nil) // if an error was encountered, or no path was found, we return if err != nil || v == nil { return @@ -108,17 +107,17 @@ func (b *Basis) LoadProject(n string) (*Project, error) { // Finds the Vagrantfile associated with the basis func (b *Basis) LoadVagrantfile() error { - vpath := b.path.Join(configpkg.GetVagrantfileName()) + vpath, err := config.ExistingPath(b.path, config.GetVagrantfileName()) l := b.logger.With( "basis", b.basis.Name, "path", vpath, ) - l.Trace("attempting to load basis vagrantfile") - // If the path does not exist, no Vagrantfile was found - if _, err := os.Stat(vpath.String()); os.IsNotExist(err) { - l.Warn("basis vagrantfile does not exist") + if os.IsNotExist(err) { + l.Warn("basis vagrantfile does not exist", + "path", b.path.String(), + ) return nil } else if err != nil { @@ -129,37 +128,25 @@ func (b *Basis) LoadVagrantfile() error { return err } - raw, err := b.client.rubyRuntime.Dispense("vagrantrubyruntime") - if err != nil { - l.Warn("failed to load ruby runtime for vagrantfile parsing", - "error", err, - ) + l.Trace("attempting to load basis vagrantfile") + raw, err := b.VagrantRubyRuntime().Dispense("vagrantrubyruntime") + if err != nil { return err } - rvc, ok := raw.(serverclient.RubyVagrantClient) - if !ok { - l.Warn("failed to attach to ruby runtime for vagrantfile parsing", - "error", err, - ) - return fmt.Errorf("Couldn't attach to Ruby runtime") - } + p, err := LoadVagrantfile( + vpath, l, raw.(serverclient.RubyVagrantClient)) - // This is the Vagrantfile that exists in the Basis directory - vagrantfile, err := rvc.ParseVagrantfile(vpath.String()) if err != nil { - l.Error("failed to parse basis vagrantfile", - "error", err, - ) return err } l.Trace("storing updated basis configuration", - "configuration", vagrantfile, + "configuration", p.Unfinalized, ) - b.basis.Configuration = vagrantfile + b.basis.Configuration = p // Push Vagrantfile updates to basis result, err := b.vagrant.UpsertBasis( b.ctx, diff --git a/internal/client/client.go b/internal/client/client.go index e20014f6c..45b0c297b 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -3,18 +3,25 @@ package client import ( "context" "errors" + "io" + "os" + "path/filepath" "github.com/hashicorp/go-hclog" "github.com/hashicorp/go-multierror" "github.com/hashicorp/go-plugin" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + vconfig "github.com/hashicorp/vagrant-plugin-sdk/config" + "github.com/hashicorp/vagrant-plugin-sdk/helper/path" "github.com/hashicorp/vagrant-plugin-sdk/helper/paths" + "github.com/hashicorp/vagrant-plugin-sdk/proto/vagrant_plugin_sdk" "github.com/hashicorp/vagrant-plugin-sdk/terminal" "github.com/hashicorp/vagrant/internal/config" "github.com/hashicorp/vagrant/internal/runner" "github.com/hashicorp/vagrant/internal/server/proto/vagrant_server" "github.com/hashicorp/vagrant/internal/serverclient" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) var ( @@ -264,3 +271,63 @@ func WithConfig(cfg *config.Config) Option { return nil } } + +// Load a Vagrantfile +func LoadVagrantfile( + file path.Path, // path to the Vagrantfile + l hclog.Logger, // logger + c serverclient.RubyVagrantClient, // vagrant ruby runtime for ruby based Vagrantfiles +) (p *vagrant_server.Vagrantfile, err error) { + var v *vconfig.Vagrantfile + + p = &vagrant_server.Vagrantfile{} + format := vconfig.JSON + protoFormat := vagrant_server.Vagrantfile_JSON + + // We support three types of Vagrantfiles: + // * Ruby (original) + // * HCL + // * JSON (which is HCL in JSON form) + ext := filepath.Ext(file.String()) + if ext == ".hcl" { + format = vconfig.HCL + protoFormat = vagrant_server.Vagrantfile_HCL + } + + switch ext { + case ".hcl", ".json": + f, err := os.Open(file.String()) + if err != nil { + return nil, err + } + p.Raw, err = io.ReadAll(f) + if err != nil { + return nil, err + } + + v, err = vconfig.LoadVagrantfile(p.Raw, file.String(), format) + if err != nil { + return nil, err + } + if p.Unfinalized, err = vconfig.EncodeVagrantfile(v); err != nil { + return nil, err + } + default: + p.Unfinalized, err = c.ParseVagrantfile(file.String()) + if err != nil { + l.Error("failed to parse vagrantfile", + "error", err, + ) + return nil, err + } + l.Info("initial vagrantfile value set", + "path", file.String(), + "value", p.Unfinalized, + ) + protoFormat = vagrant_server.Vagrantfile_RUBY + } + p.Path = &vagrant_plugin_sdk.Args_Path{Path: file.String()} + p.Format = protoFormat + + return +} diff --git a/internal/client/project.go b/internal/client/project.go index 092bab733..ad8f6e3d4 100644 --- a/internal/client/project.go +++ b/internal/client/project.go @@ -7,6 +7,7 @@ import ( "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vagrant-plugin-sdk/config" "github.com/hashicorp/vagrant-plugin-sdk/helper/path" vagrant_plugin_sdk "github.com/hashicorp/vagrant-plugin-sdk/proto/vagrant_plugin_sdk" "github.com/hashicorp/vagrant-plugin-sdk/terminal" @@ -57,28 +58,15 @@ func (p *Project) LoadVagrantfile() error { return err } - rvc, ok := raw.(serverclient.RubyVagrantClient) - if !ok { - l.Warn("failed to attach to ruby runtime for vagrantfile parsing") - return fmt.Errorf("Couldn't attach to Ruby runtime") - } + vp, err := LoadVagrantfile( + p.vagrantfile, l, raw.(serverclient.RubyVagrantClient)) - // This is the Vagrantfile that exists in the Project directory - // Does this parse include the Vagrantfile that exists for the machine? - vagrantfile, err := rvc.ParseVagrantfile(p.vagrantfile.String()) if err != nil { - l.Error("failed to parse project vagrantfile", - "error", err, - ) return err } - l.Trace("storaing updated project configuration", - "configuration", vagrantfile, - ) - - p.project.Configuration = vagrantfile + p.project.Configuration = vp // Push Vagrantfile updates to project result, err := p.vagrant.UpsertProject( p.ctx, @@ -126,22 +114,35 @@ func (p *Project) LoadTarget(n string) (*Target, error) { }, nil } - // Doesn't exist so lets create it - // TODO(spox): do we actually want to create these? + v, err := config.DecodeVagrantfile(p.project.Configuration.Unfinalized) + if err != nil { + return nil, err + } - var machineConfig *vagrant_plugin_sdk.Vagrantfile_MachineConfig - for _, m := range p.project.Configuration.MachineConfigs { - if m.Name == n { - machineConfig = m + var vm *config.VM + for _, pvm := range v.ListVMs { + if true { + vm = pvm break } } + + // If the target hasn't been defined in the Vagrantfile configuration + // then we don't create it + if vm == nil { + return nil, fmt.Errorf("requested target '%s' is not defined", n) + } + + s, err := config.EncodeConfiguration(vm) + if err != nil { + return nil, err + } + uresult, err := p.vagrant.UpsertTarget(p.ctx, &vagrant_server.UpsertTargetRequest{ Target: &vagrant_server.Target{ - Name: n, - Project: p.Ref(), - Configuration: machineConfig, + Name: n, + Project: p.Ref(), }, }, )