mirror of
https://github.com/coder/coder.git
synced 2025-07-03 16:13:58 +00:00
Addresses https://github.com/coder/nexus/issues/35. This PR: - Adds a `workspace_modules` table to track modules used by the Terraform provisioner in provisioner jobs. - Adds a `module_path` column to the `workspace_resources` table, allowing to identify which module a resource originates from. - Starts pushing this new information into telemetry. For the person reviewing this PR, do not fret about the 1,500 new lines - ~1,000 of them are auto-generated.
65 lines
1.7 KiB
Go
65 lines
1.7 KiB
Go
package terraform
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"golang.org/x/xerrors"
|
|
|
|
"github.com/coder/coder/v2/provisionersdk/proto"
|
|
)
|
|
|
|
type module struct {
|
|
Source string `json:"Source"`
|
|
Version string `json:"Version"`
|
|
Key string `json:"Key"`
|
|
}
|
|
|
|
type modulesFile struct {
|
|
Modules []*module `json:"Modules"`
|
|
}
|
|
|
|
func getModulesFilePath(workdir string) string {
|
|
return filepath.Join(workdir, ".terraform", "modules", "modules.json")
|
|
}
|
|
|
|
func parseModulesFile(filePath string) ([]*proto.Module, error) {
|
|
modules := &modulesFile{}
|
|
data, err := os.ReadFile(filePath)
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("read modules file: %w", err)
|
|
}
|
|
if err := json.Unmarshal(data, modules); err != nil {
|
|
return nil, xerrors.Errorf("unmarshal modules file: %w", err)
|
|
}
|
|
protoModules := make([]*proto.Module, len(modules.Modules))
|
|
for i, m := range modules.Modules {
|
|
protoModules[i] = &proto.Module{Source: m.Source, Version: m.Version, Key: m.Key}
|
|
}
|
|
return protoModules, nil
|
|
}
|
|
|
|
// getModules returns the modules from the modules file if it exists.
|
|
// It returns nil if the file does not exist.
|
|
// Modules become available after terraform init.
|
|
func getModules(workdir string) ([]*proto.Module, error) {
|
|
filePath := getModulesFilePath(workdir)
|
|
if _, err := os.Stat(filePath); os.IsNotExist(err) {
|
|
return nil, nil
|
|
}
|
|
modules, err := parseModulesFile(filePath)
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("parse modules file: %w", err)
|
|
}
|
|
filteredModules := []*proto.Module{}
|
|
for _, m := range modules {
|
|
// Empty string means root module. It's always present, so we skip it.
|
|
if m.Source == "" {
|
|
continue
|
|
}
|
|
filteredModules = append(filteredModules, m)
|
|
}
|
|
return filteredModules, nil
|
|
}
|