Skip to content

Commit 7c5c9b3

Browse files
authored
refactor: replace go-fleetpkg with andrewkroh/go-package-spec (#108)
Replace the andrewkroh/go-fleetpkg dependency with andrewkroh/go-package-spec. The go-package-spec types are generated from the elastic/package-spec JSON schemas, and its YAML unmarshaling uses non-strict mode by default, silently ignoring unknown fields. This makes it more robust to changes in the integration package format over time, both because unknown fields won't cause parse failures and because the generated types should stay aligned with upstream package-spec changes. The go-package-spec API splits into separate pkgspec (types) and pkgreader (package loading) packages.
1 parent ccec5da commit 7c5c9b3

File tree

4 files changed

+101
-63
lines changed

4 files changed

+101
-63
lines changed

tools/go.mod

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ module github.com/elastic/terraform-module-fleet/tools
33
go 1.26.0
44

55
require (
6-
github.com/andrewkroh/go-fleetpkg v0.21.0
6+
github.com/andrewkroh/go-package-spec v0.0.0-20260226233412-507d7b7dfd56
77
github.com/go-git/go-billy/v5 v5.7.0
88
github.com/go-git/go-git/v5 v5.16.5
99
github.com/google/go-cmp v0.7.0
1010
github.com/spf13/cobra v1.10.2
1111
github.com/stretchr/testify v1.11.1
12-
golang.org/x/exp v0.0.0-20250808145144-a408d31f581a
12+
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa
1313
)
1414

1515
require (
@@ -36,7 +36,7 @@ require (
3636
go.yaml.in/yaml/v3 v3.0.4 // indirect
3737
golang.org/x/crypto v0.45.0 // indirect
3838
golang.org/x/net v0.47.0 // indirect
39-
golang.org/x/sys v0.38.0 // indirect
39+
golang.org/x/sys v0.41.0 // indirect
4040
gopkg.in/warnings.v0 v0.1.2 // indirect
4141
gopkg.in/yaml.v3 v3.0.1 // indirect
4242
)

tools/go.sum

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo
55
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
66
github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw=
77
github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE=
8-
github.com/andrewkroh/go-fleetpkg v0.21.0 h1:1PXkUvJVJkbLcoOnnccdche5Ru5Z+xW0DZJvkn1RIH4=
9-
github.com/andrewkroh/go-fleetpkg v0.21.0/go.mod h1:FOoPEq03FzRDkmcC6VlpH1leiTLLuec05DWQ3YlIgxM=
8+
github.com/andrewkroh/go-package-spec v0.0.0-20260226233412-507d7b7dfd56 h1:JOeFOpeSn5za0JNIVF4Ft1SrlpUWCI5Y3MUwAZtoEIM=
9+
github.com/andrewkroh/go-package-spec v0.0.0-20260226233412-507d7b7dfd56/go.mod h1:VYFYfQkXOAe7RIOtSSUNfB6k7bn7An3IKRxfJvTvA8g=
1010
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
1111
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
1212
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
@@ -85,8 +85,8 @@ go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
8585
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
8686
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
8787
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
88-
golang.org/x/exp v0.0.0-20250808145144-a408d31f581a h1:Y+7uR/b1Mw2iSXZ3G//1haIiSElDQZ8KWh0h+sZPG90=
89-
golang.org/x/exp v0.0.0-20250808145144-a408d31f581a/go.mod h1:rT6SFzZ7oxADUDx58pcaKFTcZ+inxAa9fTrYx/uVYwg=
88+
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0=
89+
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA=
9090
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
9191
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
9292
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
@@ -96,8 +96,8 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w
9696
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
9797
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
9898
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
99-
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
100-
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
99+
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
100+
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
101101
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
102102
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
103103
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=

tools/internal/module/generate.go

Lines changed: 75 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ import (
2727
"strings"
2828
"text/template"
2929

30-
"github.com/andrewkroh/go-fleetpkg"
30+
"github.com/andrewkroh/go-package-spec/pkgreader"
31+
"github.com/andrewkroh/go-package-spec/pkgspec"
3132
"github.com/google/go-cmp/cmp"
3233
"github.com/google/go-cmp/cmp/cmpopts"
3334
"golang.org/x/exp/maps"
@@ -45,37 +46,39 @@ type Terraform struct {
4546
// Generate generates a Terraform module.
4647
func Generate(path, policyTemplateName, dataStreamName, inputName string, ignoreVariableShadowing bool) (*Terraform, error) {
4748
// Read in the package metadata.
48-
pkg, err := fleetpkg.Read(path)
49+
pkg, err := pkgreader.Read(path)
4950
if err != nil {
5051
return nil, err
5152
}
5253

5354
var (
54-
manifest = pkg.Manifest
55-
policyTemplate *fleetpkg.PolicyTemplate
56-
policyTemplateInput *fleetpkg.Input
57-
dataStream *fleetpkg.DataStream
58-
stream *fleetpkg.Stream
55+
manifest = pkg.Manifest()
56+
policyTemplate *pkgspec.PolicyTemplate // integration only
57+
inputPolicyTemplate *pkgspec.InputPolicyTemplate // input only
58+
policyTemplateInput *pkgspec.PolicyTemplateInput // integration only
59+
dataStream *pkgreader.DataStream // integration only
60+
stream *pkgspec.DataStreamStream // integration only
5961
)
6062

6163
// Policy template.
6264

63-
if policyTemplateName == "" {
64-
policyTemplate = &pkg.Manifest.PolicyTemplates[0]
65-
policyTemplateName = policyTemplate.Name
66-
} else {
67-
for i, pt := range pkg.Manifest.PolicyTemplates {
68-
if pt.Name == policyTemplateName {
69-
policyTemplate = &pkg.Manifest.PolicyTemplates[i]
70-
break
65+
if manifest.Type != "input" {
66+
intManifest := pkg.IntegrationManifest()
67+
if policyTemplateName == "" {
68+
policyTemplate = &intManifest.PolicyTemplates[0]
69+
policyTemplateName = policyTemplate.Name
70+
} else {
71+
for i, pt := range intManifest.PolicyTemplates {
72+
if pt.Name == policyTemplateName {
73+
policyTemplate = &intManifest.PolicyTemplates[i]
74+
break
75+
}
76+
}
77+
if policyTemplate == nil {
78+
return nil, fmt.Errorf("policy template %q not found", policyTemplateName)
7179
}
7280
}
73-
if policyTemplate == nil {
74-
return nil, fmt.Errorf("policy template %q not found", policyTemplateName)
75-
}
76-
}
7781

78-
if pkg.Manifest.Type != "input" {
7982
for i, input := range policyTemplate.Inputs {
8083
if input.Type == inputName {
8184
policyTemplateInput = &policyTemplate.Inputs[i]
@@ -107,8 +110,24 @@ func Generate(path, policyTemplateName, dataStreamName, inputName string, ignore
107110
}
108111
}
109112
} else {
113+
inputManifest := pkg.InputManifest()
114+
if policyTemplateName == "" {
115+
inputPolicyTemplate = &inputManifest.PolicyTemplates[0]
116+
policyTemplateName = inputPolicyTemplate.Name
117+
} else {
118+
for i, pt := range inputManifest.PolicyTemplates {
119+
if pt.Name == policyTemplateName {
120+
inputPolicyTemplate = &inputManifest.PolicyTemplates[i]
121+
break
122+
}
123+
}
124+
if inputPolicyTemplate == nil {
125+
return nil, fmt.Errorf("policy template %q not found", policyTemplateName)
126+
}
127+
}
128+
110129
// Inject data_stream.dataset for input packages.
111-
injectDataStreamDatasetVar(policyTemplate)
130+
injectDataStreamDatasetVar(inputPolicyTemplate)
112131
}
113132

114133
tfVariables := map[string]moduleVariable{
@@ -149,18 +168,30 @@ func Generate(path, policyTemplateName, dataStreamName, inputName string, ignore
149168
"fleet_package_version": {
150169
Terraform: terraform.Variable{
151170
Type: "string",
152-
Description: "Version of the " + pkg.Manifest.Name + " package to use.",
153-
Default: &terraform.NullableValue{Value: pkg.Manifest.Version},
171+
Description: "Version of the " + manifest.Name + " package to use.",
172+
Default: &terraform.NullableValue{Value: manifest.Version},
154173
},
155174
},
156175
}
157176

158177
// Iterate over all variables in the package and create Terraform variables.
159-
packageLevelVarAssociations, err := addVariables(pkg.Manifest.Vars, tfVariables, ignoreVariableShadowing)
178+
var packageVars []pkgspec.Var
179+
if manifest.Type != "input" {
180+
packageVars = pkg.IntegrationManifest().Vars
181+
} else {
182+
packageVars = pkg.InputManifest().Vars
183+
}
184+
packageLevelVarAssociations, err := addVariables(packageVars, tfVariables, ignoreVariableShadowing)
160185
if err != nil {
161186
return nil, fmt.Errorf("error adding package level variables: %w", err)
162187
}
163-
policyTemplateLevelVarAssociations, err := addVariables(policyTemplate.Vars, tfVariables, ignoreVariableShadowing)
188+
var policyTemplateVars []pkgspec.Var
189+
if policyTemplate != nil {
190+
policyTemplateVars = policyTemplate.Vars
191+
} else if inputPolicyTemplate != nil {
192+
policyTemplateVars = inputPolicyTemplate.Vars
193+
}
194+
policyTemplateLevelVarAssociations, err := addVariables(policyTemplateVars, tfVariables, ignoreVariableShadowing)
164195
if err != nil {
165196
return nil, fmt.Errorf("error adding policy template level variables: %w", err)
166197
}
@@ -201,8 +232,8 @@ func Generate(path, policyTemplateName, dataStreamName, inputName string, ignore
201232
dataStreams := maps.Clone(pkg.DataStreams)
202233

203234
// If the policy template declares specific data streams, then honor that list.
204-
if len(policyTemplate.DataStreams) > 0 {
205-
maps.DeleteFunc(dataStreams, func(s string, _ *fleetpkg.DataStream) bool {
235+
if policyTemplate != nil && len(policyTemplate.DataStreams) > 0 {
236+
maps.DeleteFunc(dataStreams, func(s string, _ *pkgreader.DataStream) bool {
206237
return !slices.Contains(policyTemplate.DataStreams, s)
207238
})
208239
}
@@ -219,8 +250,8 @@ func Generate(path, policyTemplateName, dataStreamName, inputName string, ignore
219250

220251
// All "${policy_template.name}-${input.type}" combinations.
221252
allPolicyTemplateInputs := []string{} // Declare empty slice.
222-
{
223-
for _, p := range manifest.PolicyTemplates {
253+
if intManifest := pkg.IntegrationManifest(); intManifest != nil {
254+
for _, p := range intManifest.PolicyTemplates {
224255
for _, input := range p.Inputs {
225256
allPolicyTemplateInputs = append(allPolicyTemplateInputs, p.Name+"-"+input.Type)
226257
}
@@ -245,7 +276,7 @@ func Generate(path, policyTemplateName, dataStreamName, inputName string, ignore
245276
PackageVersion: "${var.fleet_package_version}",
246277
Namespace: "${var.fleet_data_stream_namespace}",
247278
Description: "${var.fleet_package_policy_description}",
248-
PolicyTemplate: policyTemplate.Name,
279+
PolicyTemplate: policyTemplateName,
249280
DataStream: datasetName(dataStreamName, dataStream),
250281
InputType: inputName,
251282
PackageVariablesJSON: packageLevelVarExpression,
@@ -265,7 +296,7 @@ func Generate(path, policyTemplateName, dataStreamName, inputName string, ignore
265296
},
266297
}
267298

268-
pkgType := manifest.Type
299+
pkgType := string(manifest.Type)
269300
if pkgType == "" {
270301
pkgType = "integration"
271302
}
@@ -283,14 +314,14 @@ func Generate(path, policyTemplateName, dataStreamName, inputName string, ignore
283314

284315
type moduleVariable struct {
285316
Terraform terraform.Variable // Terraform variable definition.
286-
Fleet *fleetpkg.Var // Source of the Terraform variable in Fleet package (optional).
317+
Fleet *pkgspec.Var // Source of the Terraform variable in Fleet package (optional).
287318
}
288319

289320
// addVariables adds the given Fleet package vars to the Terraform module variables in m.
290321
// It returns an error if a variable with the given name already exists in the Terraform
291322
// module. It returns an associations mapping that contains a mapping of Fleet variable
292323
// names to Terraform variable names.
293-
func addVariables(vars []fleetpkg.Var, m map[string]moduleVariable, ignoreShadowing bool) (associations map[string]string, err error) {
324+
func addVariables(vars []pkgspec.Var, m map[string]moduleVariable, ignoreShadowing bool) (associations map[string]string, err error) {
294325
associations = make(map[string]string, len(vars))
295326
for _, v := range vars {
296327
tfName, err := addVariable(v, m, ignoreShadowing)
@@ -303,7 +334,7 @@ func addVariables(vars []fleetpkg.Var, m map[string]moduleVariable, ignoreShadow
303334
return associations, nil
304335
}
305336

306-
func addVariable(v fleetpkg.Var, m map[string]moduleVariable, ignoreShadowing bool) (tfName string, err error) {
337+
func addVariable(v pkgspec.Var, m map[string]moduleVariable, ignoreShadowing bool) (tfName string, err error) {
307338
tfVar := terraform.Variable{
308339
Description: v.Description,
309340
}
@@ -343,14 +374,14 @@ func addVariable(v fleetpkg.Var, m map[string]moduleVariable, ignoreShadowing bo
343374
if existing, found := m[name]; found {
344375
if existing.Fleet != nil {
345376
msg := fmt.Sprintf("duplicate variable %q found at both\n\t%s:%d\n\t%s:%d", name,
346-
existing.Fleet.Path(), existing.Fleet.Line(),
347-
v.Path(), v.Line())
348-
if diff := cmp.Diff(*existing.Fleet, v, cmpopts.IgnoreFields(fleetpkg.Var{}, "FileMetadata")); diff != "" {
377+
existing.Fleet.FilePath(), existing.Fleet.Line(),
378+
v.FilePath(), v.Line())
379+
if diff := cmp.Diff(*existing.Fleet, v, cmpopts.IgnoreFields(pkgspec.Var{}, "FileMetadata")); diff != "" {
349380
return "", fmt.Errorf(msg+"\ndiff:\n%s", diff)
350381
}
351382
return "", errors.New(msg)
352383
}
353-
return "", fmt.Errorf("duplicate variable named %q found at %s:%d", name, v.Path(), v.Line())
384+
return "", fmt.Errorf("duplicate variable named %q found at %s:%d", name, v.FilePath(), v.Line())
354385
}
355386
}
356387
m[name] = moduleVariable{Fleet: &v, Terraform: tfVar}
@@ -365,7 +396,7 @@ func moduleVariableToTerraformVariable(in map[string]moduleVariable) map[string]
365396
return out
366397
}
367398

368-
func isSensitive(v fleetpkg.Var) bool {
399+
func isSensitive(v pkgspec.Var) bool {
369400
name := strings.ToLower(v.Name)
370401
switch {
371402
case v.Type == "password",
@@ -378,14 +409,14 @@ func isSensitive(v fleetpkg.Var) bool {
378409
}
379410
}
380411

381-
func dataType(v fleetpkg.Var) (string, error) {
412+
func dataType(v pkgspec.Var) (string, error) {
382413
var tfType string
383414
switch v.Type {
384415
case "bool":
385416
tfType = "bool"
386417
case "integer":
387418
tfType = "number"
388-
case "password", "email", "select", "text", "textarea", "time_zone", "url", "yaml":
419+
case "duration", "password", "email", "select", "text", "textarea", "time_zone", "url", "yaml":
389420
tfType = "string"
390421
default:
391422
// package-spec controls the allow types.
@@ -495,7 +526,7 @@ func moduleName(integration, policyTemplate, dataStream, input string) string {
495526
return strings.Join(name, ".")
496527
}
497528

498-
func datasetName(dataStreamDirName string, m *fleetpkg.DataStream) string {
529+
func datasetName(dataStreamDirName string, m *pkgreader.DataStream) string {
499530
if m != nil {
500531
if _, dataset, found := strings.Cut(m.Manifest.Dataset, "."); found {
501532
return dataset
@@ -518,15 +549,15 @@ func quoteIfNeeded(name string) string {
518549
// given policy_template if it does not exist.
519550
//
520551
// Reference: https://github.com/andrewkroh/terraform-module-fleet/issues/26
521-
func injectDataStreamDatasetVar(policy *fleetpkg.PolicyTemplate) {
552+
func injectDataStreamDatasetVar(policy *pkgspec.InputPolicyTemplate) {
522553
const datasetVarName = "data_stream.dataset"
523554
for _, v := range policy.Vars {
524555
if v.Name == datasetVarName {
525556
return
526557
}
527558
}
528559

529-
policy.Vars = append(policy.Vars, fleetpkg.Var{
560+
policy.Vars = append(policy.Vars, pkgspec.Var{
530561
Name: datasetVarName,
531562
Description: "Set the name for your dataset. Once selected a dataset cannot be changed without creating a new integration policy. You can't use - in the name of a dataset and only valid characters for Elasticsearch index names are permitted.",
532563
Type: "text",

0 commit comments

Comments
 (0)