1
1
package terragrunt
2
2
3
3
import (
4
+ "crypto/sha256"
4
5
"errors"
5
6
"fmt"
6
7
"io"
@@ -9,12 +10,10 @@ import (
9
10
"os/exec"
10
11
"path/filepath"
11
12
"runtime"
13
+ "strings"
12
14
13
15
"github.com/padok-team/burrito/internal/runner/terraform"
14
- )
15
-
16
- const (
17
- BinWorkDir = "/runner/bin"
16
+ log "github.com/sirupsen/logrus"
18
17
)
19
18
20
19
type Terragrunt struct {
@@ -23,13 +22,15 @@ type Terragrunt struct {
23
22
version string
24
23
workingDir string
25
24
terraform * terraform.Terraform
25
+ runnerBinaryPath string
26
26
}
27
27
28
- func NewTerragrunt (terraformExec * terraform.Terraform , terragruntVersion , planArtifactPath string ) * Terragrunt {
28
+ func NewTerragrunt (terraformExec * terraform.Terraform , terragruntVersion , planArtifactPath string , runnerBinaryPath string ) * Terragrunt {
29
29
return & Terragrunt {
30
30
version : terragruntVersion ,
31
31
terraform : terraformExec ,
32
32
planArtifactPath : planArtifactPath ,
33
+ runnerBinaryPath : runnerBinaryPath ,
33
34
}
34
35
}
35
36
@@ -43,7 +44,8 @@ func (t *Terragrunt) Install() error {
43
44
if err != nil {
44
45
return err
45
46
}
46
- path , err := downloadTerragrunt (t .version )
47
+
48
+ path , err := ensureTerragrunt (t .version , t .runnerBinaryPath )
47
49
if err != nil {
48
50
return err
49
51
}
@@ -115,7 +117,94 @@ func (t *Terragrunt) Show(mode string) ([]byte, error) {
115
117
return output , nil
116
118
}
117
119
118
- func downloadTerragrunt (version string ) (string , error ) {
120
+ func ensureTerragrunt (version string , runnerBinaryPath string ) (string , error ) {
121
+ files , err := os .ReadDir (runnerBinaryPath )
122
+ if err != nil {
123
+ return "" , err
124
+ }
125
+
126
+ trustedHash , err := getTerragruntSHA256 (version )
127
+ if err != nil {
128
+ return "" , err
129
+ }
130
+
131
+ for _ , file := range files {
132
+ if ! file .IsDir () {
133
+ runnerBinaryFullPath := filepath .Join (runnerBinaryPath , file .Name ())
134
+ hash , err := calculateFileSHA256 (runnerBinaryFullPath )
135
+ if err != nil {
136
+ return "" , err
137
+ }
138
+
139
+ if hash == trustedHash {
140
+ err = os .Chmod (runnerBinaryFullPath , 0755 )
141
+ if err != nil {
142
+ return "" , err
143
+ }
144
+ log .Infof ("Terragrunt binary found at %s, using it" , runnerBinaryFullPath )
145
+ return filepath .Abs (runnerBinaryFullPath )
146
+ }
147
+
148
+ }
149
+ }
150
+
151
+ log .Infof ("Terragrunt binary not found, downloading it... (Consider packaging binaries within your runner image to mitigate eventual network expenses)" )
152
+ path , err := downloadTerragrunt (version , runnerBinaryPath )
153
+ log .Infof ("Downloaded terragrunt binaries to %s" , path )
154
+ if err != nil {
155
+ return "" , err
156
+ }
157
+
158
+ return path , nil
159
+ }
160
+
161
+ func calculateFileSHA256 (filename string ) (string , error ) {
162
+ file , err := os .Open (filename )
163
+ if err != nil {
164
+ return "" , err
165
+ }
166
+ defer file .Close ()
167
+
168
+ hash := sha256 .New ()
169
+
170
+ if _ , err := io .Copy (hash , file ); err != nil {
171
+ return "" , err
172
+ }
173
+
174
+ return fmt .Sprintf ("%x" , hash .Sum (nil )), nil
175
+ }
176
+
177
+ func getTerragruntSHA256 (version string ) (string , error ) {
178
+ cpuArch := runtime .GOARCH
179
+ response , err := http .Get (fmt .Sprintf ("https://github.com/gruntwork-io/terragrunt/releases/download/v%s/SHA256SUMS" , version ))
180
+ if err != nil {
181
+ return "" , err
182
+ }
183
+ defer response .Body .Close ()
184
+
185
+ body , err := io .ReadAll (response .Body )
186
+ if err != nil {
187
+ return "" , err
188
+ }
189
+
190
+ lines := strings .Split (string (body ), "\n " )
191
+ for _ , line := range lines {
192
+ parts := strings .Fields (line )
193
+ if len (parts ) != 2 {
194
+ continue
195
+ }
196
+ sha := parts [0 ]
197
+ filename := parts [1 ]
198
+
199
+ if strings .Contains (filename , fmt .Sprintf ("linux_%s" , cpuArch )) {
200
+ return sha , nil
201
+ }
202
+ }
203
+
204
+ return "" , errors .New ("could not find a hash for this architecture in SHA256SUMS file" )
205
+ }
206
+
207
+ func downloadTerragrunt (version string , runnerBinaryPath string ) (string , error ) {
119
208
cpuArch := runtime .GOARCH
120
209
121
210
url := fmt .Sprintf ("https://github.com/gruntwork-io/terragrunt/releases/download/v%s/terragrunt_linux_%s" , version , cpuArch )
@@ -126,7 +215,7 @@ func downloadTerragrunt(version string) (string, error) {
126
215
}
127
216
defer response .Body .Close ()
128
217
129
- filename := fmt .Sprintf ("%s/terragrunt_%s" , BinWorkDir , cpuArch )
218
+ filename := fmt .Sprintf ("%s/terragrunt_%s" , runnerBinaryPath , cpuArch )
130
219
file , err := os .Create (filename )
131
220
if err != nil {
132
221
return "" , err
0 commit comments