YaleUniversity / packer-plugin-goss

Goss Provisioner for Packer
MIT License
136 stars 45 forks source link

File error: open ./goss.yaml: no such file or directory #4

Closed michaelwittig closed 3 years ago

michaelwittig commented 6 years ago

Hi,

I use the goss provisioner with the following config:

./packer.json

{
  "provisioners": [
     ...
    {
      "type": "goss",
      "tests": [
        "./build/base2.yaml"
      ]
    }
  ]
}

The goss yaml seems to be uploaded, but for some reason goss is started and falls back to the goss.yaml file.

packer output:

1516710066,,ui,say,==> stag-base2: Provisioning with Goss
1516710066,,ui,message, stag-base2: Installing Goss from%!(PACKER_COMMA) https://github.com/aelsabbahy/goss/releases/download/v0.3.2/goss-linux-amd64
1516710066,,ui,message, stag-base2: Downloading Goss to /tmp/goss-0.3.2-linux-amd64
1516710066,,ui,message, stag-base2: % Total % Received % Xferd Average Speed Time Time Time Current
1516710066,,ui,message, stag-base2: Dload Upload Total Spent Left Speed
1516710066,,ui,message, stag-base2: 100 606 0 606 0 0 606 0 --:--:-- --:--:-- --:--:-- 3482
1516710076,,ui,message, stag-base2: 100 7970k 100 7970k 0 0 885k 0 0:00:09 0:00:09 --:--:-- 688k
1516710076,,ui,message, stag-base2: goss version v0.3.2
1516710076,,ui,say,==> stag-base2: Uploading goss tests...
1516710076,,ui,message, stag-base2: Creating directory: /tmp/goss
1516710076,,ui,message, stag-base2: Uploading ./build/base2.yaml
1516710076,,ui,say,==> stag-base2: Running goss tests...
1516710076,,ui,message, stag-base2: File error: open ./goss.yaml: no such file or directory
1516710076,,ui,say,==> stag-base2: Terminating the source AWS instance...
1516710132,,ui,say,==> stag-base2: Cleaning up any extra volumes...
1516710132,,ui,say,==> stag-base2: No volumes to clean up%!(PACKER_COMMA) skipping
1516710132,,ui,say,==> stag-base2: Deleting temporary security group...
1516710132,,ui,say,==> stag-base2: Deleting temporary keypair...
1516710132,,ui,error,Build 'stag-base2' errored: Error running Goss: goss non-zero exit status
1516710132,,error-count,1

It seems to me (not familiar with go), that the --gossfile flag is never set, so goss.yaml is always assumed.

michaelwittig commented 6 years ago

7 adds the ability to specify the goss_file. As far as I understand tests copies the files in the array onto the machine. By default, goss is started using the goss.yaml file. With the new goss_file I can now get it to use a different file name. e.g.:

{
  "type": "goss",
  "version": "0.3.5",
  "arch": "amd64",
  "tests": [
    "./path/to/base.yaml"
  ],
  "goss_file": "base.yaml"
}

So this kind of is enough for my use case. I'm still wondering why I have to define this twice and why I can upload multiple files but only run goss with a single file?

vamegh commented 6 years ago

Hi @michaelwittig:

I ran into this same issue as well, its how goss operates though, so you can for example upload your tests over several yaml files inside a directory and then have an initial goss.yaml which calls in all of the other yaml files.

Because as you mentioned the upload can upload an array of files - there is no set way of working out which yaml file is meant to be your master config file, hence why I added the goss_file key so that you can explicitly state what the master file is (the --gossfile flag to goss). I couldnt think up a better solution, you could in theory check the array if it contains only 1 value pass that through to the gossfile flag as well, but I thought this approach provides more control to you and allows for better control of the tests to goss.

berney commented 6 years ago

I like the solution you provided with the goss_file attribute. But I think that if the length of the test list is only one file and goss_file has not been defined, then it should default to the first and only entry. Although, this would need to strip the directories off.

fishnix commented 6 years ago

you could in theory check the array if it contains only 1 value pass that through to the gossfile flag as well

I think that if the length of the test list is only one file and goss_file has not been defined, then it should default to the first and only entry

I agree -- I can work on this. Thanks for pointing this out @michaelwittig, and thanks for all of your updates @vamegh!

vamegh commented 6 years ago

Hi @fishnix no probs, thanks for merging it I appreciate it.

Ive been thinking about this and think I have an easy solution.

for _, src := range p.config.Tests {
        s, err := os.Stat(src)
        if err != nil {
            return fmt.Errorf("Error stating file: %s", err)
        }
        if s.Mode().IsRegular() {
                     if (len(p.config.Tests) == 1) && if (p.config.GossFile == "") {
                              p.config.GossFile = fmt.Sprintf("--gossfile %s",filepath.Base(src))
                     }

This should do it - if its just a regular file and there is only 1 element in the array and gossfile hasnt been set then set the gossfile flag to call this file.

this keeps everything working and auto-adds a single file to be the gossfile. If you think this is a good solution feel free to use it, if you dont have the time if you want I can submit a pull request this weekend that adds this.

caarlos0 commented 5 years ago

I did this:

diff --git a/packer-provisioner-goss.go b/packer-provisioner-goss.go
index 102a03f..b866775 100644
--- a/packer-provisioner-goss.go
+++ b/packer-provisioner-goss.go
@@ -39,9 +39,6 @@ type GossConfig struct {
    // skip ssl check flag
    SkipSSLChk bool `mapstructure:"skip_ssl"`

-   // The --gossfile flag
-   GossFile string `mapstructure:"goss_file"`
-
    // The --vars flag
    // Optional file containing variables, used within GOSS templating.
    // Must be one of the files contained in the Tests array.
@@ -123,10 +120,6 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
        p.config.Tests = make([]string, 0)
    }

-   if p.config.GossFile != "" {
-       p.config.GossFile = fmt.Sprintf("--gossfile %s", p.config.GossFile)
-   }
-
    var errs *packer.MultiError
    if p.config.Format != "" {
        valid := false
@@ -216,9 +209,12 @@ func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error {
        }
    }

-   ui.Say("Running goss tests...")
-   if err := p.runGoss(ui, comm); err != nil {
-       return fmt.Errorf("Error running Goss: %s", err)
+   for _, file := range p.config.Tests {
+       file := filepath.Base(file)
+       ui.Say(fmt.Sprintf("Running goss tests (%s)...", file))
+       if err := p.runGoss(ui, comm, file); err != nil {
+           return fmt.Errorf("Error running Goss: %s", err)
+       }
    }

    return nil
@@ -255,11 +251,11 @@ func (p *Provisioner) installGoss(ui packer.Ui, comm packer.Communicator) error
 }

 // runGoss runs the Goss tests
-func (p *Provisioner) runGoss(ui packer.Ui, comm packer.Communicator) error {
+func (p *Provisioner) runGoss(ui packer.Ui, comm packer.Communicator, file string) error {
    cmd := &packer.RemoteCmd{
        Command: fmt.Sprintf(
-           "cd %s && %s %s %s %s %s validate --retry-timeout %s --sleep %s %s",
-           p.config.RemotePath, p.enableSudo(), p.config.DownloadPath, p.config.GossFile,
+           "cd %s && %s %s --gossfile %s %s %s validate --retry-timeout %s --sleep %s %s",
+           p.config.RemotePath, p.enableSudo(), p.config.DownloadPath, file,
            p.vars(), p.debug(), p.retryTimeout(), p.sleep(), p.format(),
        ),
    }

this way it also supports multiple test suites... 🤔

fishnix commented 3 years ago

closing old issues, reopen if still interested 👍