Skip to content

Commit e840c2f

Browse files
authored
Go code review (#8)
* init commit * add comments * add getter interface, serverless struct, serverless constructor, and run method, additional comments/questions * add new package for refactoring to easily preserve old code * start working on rehash * add rehash function and apply to CustomizeDiff callback * add create * add read * add update * add delete * add provider * fix lint error * replace old code * rename resource back to deployment * remove temp comments and fix typo * refactor how serverles commands are run. Export a public API * remove uneeded iotas * add type assertion error handling for Servless struct
1 parent 3c3bdb2 commit e840c2f

File tree

3 files changed

+236
-161
lines changed

3 files changed

+236
-161
lines changed

serverless/resource_deployment.go

Lines changed: 20 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,9 @@
11
package serverless
22

33
import (
4-
"crypto/sha256"
5-
"encoding/hex"
6-
"encoding/json"
7-
"fmt"
8-
"os/exec"
9-
"path/filepath"
10-
"runtime"
4+
"errors"
115
"strings"
126

13-
"golang.org/x/mod/sumdb/dirhash"
14-
157
"github.com/aws/aws-sdk-go/aws"
168
"github.com/aws/aws-sdk-go/aws/awserr"
179
"github.com/aws/aws-sdk-go/aws/session"
@@ -20,104 +12,6 @@ import (
2012
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
2113
)
2214

23-
type serverlessConfig struct {
24-
Service string
25-
}
26-
27-
func getServerlessConfig(configDir string, serverlessBinDir string) ([]byte, error) {
28-
cmd := exec.Command(getServerlessBin(configDir, serverlessBinDir), "print", "--format", "json")
29-
cmd.Dir = configDir
30-
31-
output, err := cmd.CombinedOutput()
32-
if err != nil {
33-
return []byte{}, fmt.Errorf("%v\n%w", string(output), err)
34-
}
35-
36-
return output, nil
37-
}
38-
39-
func getServiceName(configJson []byte) (string, error) {
40-
config := serverlessConfig{}
41-
err := json.Unmarshal([]byte(configJson), &config)
42-
43-
return config.Service, err
44-
}
45-
46-
// Create a hash of the Serverless config and the Serverless zip archive.
47-
// Note that dirhash.HashZip ignores all zip metadata and correctly hashes
48-
// contents of the archive.
49-
func hashServerlessDir(
50-
configDir string,
51-
packagePath string,
52-
serviceName string,
53-
configJson []byte,
54-
) (string, error) {
55-
absolutePackagePath := filepath.Join(configDir, packagePath)
56-
zipPath := filepath.Join(absolutePackagePath, fmt.Sprintf("%s.zip", serviceName))
57-
58-
zipHash, err := dirhash.HashZip(zipPath, dirhash.Hash1)
59-
if err != nil {
60-
return "", err
61-
}
62-
63-
configHashBytes := sha256.Sum256(configJson)
64-
configHash := hex.EncodeToString(configHashBytes[:])
65-
66-
return strings.Join([]string{zipHash, configHash}, "-"), nil
67-
}
68-
69-
func getServerlessBin(configDir string, binPath string) string {
70-
if binPath == "" {
71-
binPath = filepath.Join(configDir, "node_modules", ".bin")
72-
}
73-
suffix := ""
74-
if runtime.GOOS == "windows" {
75-
suffix = ".cmd"
76-
}
77-
return filepath.Join(binPath, fmt.Sprintf("serverless%s", suffix))
78-
}
79-
80-
type serverlessParams struct {
81-
command string
82-
serverlessBinDir string
83-
configDir string
84-
packageDir string
85-
stage string
86-
args []interface{}
87-
}
88-
89-
func runServerless(params *serverlessParams) error {
90-
stringArgs := make([]string, len(params.args))
91-
for i, v := range stringArgs {
92-
stringArgs[i] = fmt.Sprint(v)
93-
}
94-
95-
requiredArgs := []string{
96-
params.command,
97-
"-s",
98-
params.stage,
99-
}
100-
101-
if params.command == "deploy" || params.command == "package" {
102-
requiredArgs = append(requiredArgs, "-p", params.packageDir)
103-
}
104-
105-
stringArgs = append(
106-
requiredArgs,
107-
stringArgs...,
108-
)
109-
110-
cmd := exec.Command(getServerlessBin(params.configDir, params.serverlessBinDir), stringArgs...)
111-
cmd.Dir = params.configDir
112-
113-
output, err := cmd.CombinedOutput()
114-
if err != nil {
115-
return fmt.Errorf("%v\n%w", string(output), err)
116-
}
117-
118-
return nil
119-
}
120-
12115
func resourceDeployment() *schema.Resource {
12216
return &schema.Resource{
12317
Create: resourceDeploymentCreate,
@@ -167,66 +61,46 @@ func resourceDeployment() *schema.Resource {
16761
},
16862

16963
// Only trigger a deploy if either the Serverless config or Serverless zip archive has changed.
170-
// `sls package` isn't deterministic according to experiments, so in practive this means that
64+
// `sls package` isn't deterministic according to experiments, so in practice this means that
17165
// we only deploy after the user has run `sls package` again.
17266
CustomizeDiff: customdiff.ComputedIf("package_hash", func(d *schema.ResourceDiff, meta interface{}) bool {
173-
configDir := d.Get("config_dir").(string)
174-
packageDir := d.Get("package_dir").(string)
175-
serverlessBinDir := d.Get("serverless_bin_dir").(string)
176-
currentHash := d.Get("package_hash").(string)
67+
serverless, err := NewServerless(d)
17768

178-
configJson, err := getServerlessConfig(configDir, serverlessBinDir)
17969
if err != nil {
18070
return false
18171
}
18272

183-
hash, err := hashServerlessDir(configDir, packageDir, d.Id(), configJson)
73+
changed, err := serverless.Hash()
74+
18475
if err != nil {
18576
return false
18677
}
18778

188-
return hash != currentHash
79+
return changed
18980
}),
19081
}
19182
}
19283

19384
func resourceDeploymentCreate(d *schema.ResourceData, m interface{}) error {
194-
configDir := d.Get("config_dir").(string)
195-
serverlessBinDir := d.Get("serverless_bin_dir").(string)
196-
packageDir := d.Get("package_dir").(string)
197-
stage := d.Get("stage").(string)
198-
args := d.Get("args").([]interface{})
85+
serverless, err := NewServerless(d)
19986

200-
configJson, err := getServerlessConfig(configDir, serverlessBinDir)
20187
if err != nil {
20288
return err
20389
}
20490

205-
id, err := getServiceName(configJson)
206-
if err != nil {
207-
return err
208-
}
209-
d.SetId(id)
91+
serviceName, ok := serverless.config["service"].(string)
21092

211-
hash, err := hashServerlessDir(configDir, packageDir, id, configJson)
212-
if err != nil {
213-
return err
93+
if !ok {
94+
return errors.New("service name was not found in serverless config")
21495
}
215-
err = d.Set("package_hash", hash)
216-
if err != nil {
96+
97+
d.SetId(serviceName)
98+
99+
if err := d.Set("package_hash", serverless.hash); err != nil {
217100
return err
218101
}
219102

220-
err = runServerless(&serverlessParams{
221-
command: "deploy",
222-
serverlessBinDir: serverlessBinDir,
223-
configDir: configDir,
224-
packageDir: packageDir,
225-
stage: stage,
226-
args: args,
227-
})
228-
229-
if err != nil {
103+
if err := serverless.Deploy(); err != nil {
230104
return err
231105
}
232106

@@ -273,24 +147,16 @@ func resourceDeploymentUpdate(d *schema.ResourceData, m interface{}) error {
273147
}
274148

275149
func resourceDeploymentDelete(d *schema.ResourceData, m interface{}) error {
276-
configDir := d.Get("config_dir").(string)
277-
serverlessBinDir := d.Get("serverless_bin_dir").(string)
278-
packageDir := d.Get("package_dir").(string)
279-
stage := d.Get("stage").(string)
280-
args := d.Get("args").([]interface{})
150+
serverless, err := NewServerless(d)
281151

282-
err := runServerless(&serverlessParams{
283-
command: "remove",
284-
serverlessBinDir: serverlessBinDir,
285-
configDir: configDir,
286-
packageDir: packageDir,
287-
stage: stage,
288-
args: args,
289-
})
290152
if err != nil {
291153
return err
292154
}
293155

156+
if err := serverless.Remove(); err != nil {
157+
return err
158+
}
159+
294160
d.SetId("")
295161

296162
return nil

serverless/resource_deployment_test.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,16 @@ func testAccPreCheck(t *testing.T) {
7373
t.Fatal(err)
7474
}
7575

76-
err = runServerless(&serverlessParams{
77-
command: "package",
78-
configDir: configDir,
79-
serverlessBinDir: serverlessBinDir,
80-
packageDir: ".terraform-serverless",
81-
stage: "sandbox",
82-
})
76+
s := &Serverless{
77+
configDir: configDir,
78+
binDir: serverlessBinDir,
79+
binPath: buildBinPath(configDir, serverlessBinDir),
80+
packageDir: ".terraform-serverless",
81+
stage: "sandbox",
82+
}
83+
84+
err = s.Package()
85+
8386
if err != nil {
8487
t.Fatal(err)
8588
}

0 commit comments

Comments
 (0)