mirror of
https://github.com/hashicorp/packer.git
synced 2026-05-28 04:35:38 -04:00
added the parser for the enforced block
This commit is contained in:
parent
2c5d23b26a
commit
e9230b0b64
16 changed files with 1123 additions and 67 deletions
|
|
@ -150,6 +150,20 @@ func (c *BuildCommand) RunContext(buildCtx context.Context, cla *BuildArgs) int
|
|||
return ret
|
||||
}
|
||||
|
||||
// Fetch and inject enforced provisioners from HCP Packer (if configured)
|
||||
if !cla.SkipEnforcement {
|
||||
if err := hcpRegistry.FetchEnforcedBlocks(buildCtx); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Warning: failed to fetch enforced provisioners: %s", err))
|
||||
}
|
||||
|
||||
diags := hcpRegistry.InjectEnforcedProvisioners(builds)
|
||||
if diags.HasErrors() {
|
||||
return writeDiags(c.Ui, nil, diags)
|
||||
}
|
||||
} else {
|
||||
c.Ui.Say("Skipping HCP Packer enforced provisioners (--skip-enforcement flag set)")
|
||||
}
|
||||
|
||||
if cla.Debug {
|
||||
c.Ui.Say("Debug mode enabled. Builds will not be parallelized.")
|
||||
}
|
||||
|
|
@ -456,6 +470,7 @@ Options:
|
|||
-warn-on-undeclared-var Display warnings for user variable files containing undeclared variables.
|
||||
-ignore-prerelease-plugins Disable the loading of prerelease plugin binaries (x.y.z-dev).
|
||||
-use-sequential-evaluation Fallback to using a sequential approach for local/datasource evaluation.
|
||||
-skip-enforcement Skip injection of HCP Packer enforced provisioners.
|
||||
`
|
||||
|
||||
return strings.TrimSpace(helpText)
|
||||
|
|
|
|||
|
|
@ -101,6 +101,8 @@ func (ba *BuildArgs) AddFlagSets(flags *flag.FlagSet) {
|
|||
|
||||
flags.BoolVar(&ba.ReleaseOnly, "ignore-prerelease-plugins", false, "Disable the loading of prerelease plugin binaries (x.y.z-dev).")
|
||||
|
||||
flags.BoolVar(&ba.SkipEnforcement, "skip-enforcement", false, "Skip injection of HCP Packer enforced provisioners. Requires admin privileges.")
|
||||
|
||||
ba.MetaArgs.AddFlagSets(flags)
|
||||
}
|
||||
|
||||
|
|
@ -136,6 +138,7 @@ type BuildArgs struct {
|
|||
ParallelBuilds int64
|
||||
OnError string
|
||||
ReleaseOnly bool
|
||||
SkipEnforcement bool
|
||||
}
|
||||
|
||||
func (ia *InitArgs) AddFlagSets(flags *flag.FlagSet) {
|
||||
|
|
|
|||
52
go.mod
52
go.mod
|
|
@ -7,7 +7,7 @@ require (
|
|||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e
|
||||
github.com/dsnet/compress v0.0.1
|
||||
github.com/go-git/go-git/v5 v5.16.5
|
||||
github.com/go-openapi/runtime v0.26.2
|
||||
github.com/go-openapi/runtime v0.28.0
|
||||
github.com/gobwas/glob v0.2.3
|
||||
github.com/gofrs/flock v0.8.1 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||
|
|
@ -39,14 +39,14 @@ require (
|
|||
github.com/packer-community/winrmcp v0.0.0-20180921211025-c76d91c1e7db // indirect
|
||||
github.com/pkg/sftp v1.13.2 // indirect
|
||||
github.com/posener/complete v1.2.3
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/stretchr/testify v1.11.1
|
||||
github.com/ulikunitz/xz v0.5.15
|
||||
github.com/zclconf/go-cty v1.13.3
|
||||
github.com/zclconf/go-cty-yaml v1.0.1
|
||||
golang.org/x/crypto v0.46.0 // indirect
|
||||
golang.org/x/mod v0.30.0
|
||||
golang.org/x/net v0.47.0
|
||||
golang.org/x/oauth2 v0.27.0
|
||||
golang.org/x/oauth2 v0.30.0
|
||||
golang.org/x/sync v0.19.0
|
||||
golang.org/x/sys v0.39.0 // indirect
|
||||
golang.org/x/term v0.38.0 // indirect
|
||||
|
|
@ -56,7 +56,7 @@ require (
|
|||
|
||||
require (
|
||||
github.com/CycloneDX/cyclonedx-go v0.9.1
|
||||
github.com/go-openapi/strfmt v0.21.10
|
||||
github.com/go-openapi/strfmt v0.23.0
|
||||
github.com/oklog/ulid v1.3.1
|
||||
github.com/pierrec/lz4/v4 v4.1.18
|
||||
github.com/shirou/gopsutil/v3 v3.23.4
|
||||
|
|
@ -104,18 +104,29 @@ require (
|
|||
github.com/go-logr/logr v1.4.1 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-openapi/analysis v0.21.5 // indirect
|
||||
github.com/go-openapi/errors v0.21.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.20.1 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.3 // indirect
|
||||
github.com/go-openapi/loads v0.21.3 // indirect
|
||||
github.com/go-openapi/spec v0.20.12 // indirect
|
||||
github.com/go-openapi/swag v0.22.5 // indirect
|
||||
github.com/go-openapi/validate v0.22.4 // indirect
|
||||
github.com/go-openapi/analysis v0.23.0 // indirect
|
||||
github.com/go-openapi/errors v0.22.2 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||
github.com/go-openapi/loads v0.22.0 // indirect
|
||||
github.com/go-openapi/spec v0.21.0 // indirect
|
||||
github.com/go-openapi/swag v0.24.1 // indirect
|
||||
github.com/go-openapi/swag/cmdutils v0.24.0 // indirect
|
||||
github.com/go-openapi/swag/conv v0.24.0 // indirect
|
||||
github.com/go-openapi/swag/fileutils v0.24.0 // indirect
|
||||
github.com/go-openapi/swag/jsonname v0.24.0 // indirect
|
||||
github.com/go-openapi/swag/jsonutils v0.24.0 // indirect
|
||||
github.com/go-openapi/swag/loading v0.24.0 // indirect
|
||||
github.com/go-openapi/swag/mangling v0.24.0 // indirect
|
||||
github.com/go-openapi/swag/netutils v0.24.0 // indirect
|
||||
github.com/go-openapi/swag/stringutils v0.24.0 // indirect
|
||||
github.com/go-openapi/swag/typeutils v0.24.0 // indirect
|
||||
github.com/go-openapi/swag/yamlutils v0.24.0 // indirect
|
||||
github.com/go-openapi/validate v0.24.0 // indirect
|
||||
github.com/gofrs/uuid v4.4.0+incompatible // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/google/s2a-go v0.1.7 // indirect
|
||||
github.com/google/uuid v1.4.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
|
||||
github.com/hashicorp/consul/api v1.25.1 // indirect
|
||||
|
|
@ -150,7 +161,7 @@ require (
|
|||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||
github.com/kr/fs v0.1.0 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mailru/easyjson v0.9.0 // indirect
|
||||
github.com/masterzen/simplexml v0.0.0-20190410153822-31eea3082786 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
|
|
@ -182,11 +193,11 @@ require (
|
|||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
go.mongodb.org/mongo-driver v1.13.1 // indirect
|
||||
go.mongodb.org/mongo-driver v1.14.0 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/otel v1.17.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.17.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.17.0 // indirect
|
||||
go.opentelemetry.io/otel v1.24.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.24.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.24.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
||||
golang.org/x/time v0.11.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
|
|
@ -202,4 +213,7 @@ require (
|
|||
|
||||
go 1.24.12
|
||||
|
||||
replace github.com/zclconf/go-cty => github.com/nywilken/go-cty v1.13.3 // added by packer-sdc fix as noted in github.com/hashicorp/packer-plugin-sdk/issues/187
|
||||
replace github.com/zclconf/go-cty => github.com/nywilken/go-cty v1.13.3 // added by packer-sdc fix as noted in github.com/hashicorp/issues/187
|
||||
|
||||
// The internal Go SDK has the enforced block types not yet available in the public SDK.
|
||||
replace github.com/hashicorp/hcp-sdk-go => github.com/hashicorp/hcp-sdk-go-internal v0.0.0-20260304114239-45aa9349dd39
|
||||
|
|
|
|||
110
go.sum
110
go.sum
|
|
@ -136,8 +136,6 @@ github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UN
|
|||
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||
github.com/go-git/go-git/v5 v5.16.2 h1:fT6ZIOjE5iEnkzKyxTHK1W4HGAsPhqEqiSAssSO77hM=
|
||||
github.com/go-git/go-git/v5 v5.16.2/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8=
|
||||
github.com/go-git/go-git/v5 v5.16.5 h1:mdkuqblwr57kVfXri5TTH+nMFLNUxIj9Z7F5ykFbw5s=
|
||||
github.com/go-git/go-git/v5 v5.16.5/go.mod h1:QOMLpNf1qxuSY4StA/ArOdfFR2TrKEjJiye2kel2m+M=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
|
|
@ -154,26 +152,48 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
|||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-openapi/analysis v0.21.5 h1:3tHfEBh6Ia8eKc4M7khOGjPOAlWKJ10d877Cr9teujI=
|
||||
github.com/go-openapi/analysis v0.21.5/go.mod h1:25YcZosX9Lwz2wBsrFrrsL8bmjjXdlyP6zsr2AMy29M=
|
||||
github.com/go-openapi/errors v0.21.0 h1:FhChC/duCnfoLj1gZ0BgaBmzhJC2SL/sJr8a2vAobSY=
|
||||
github.com/go-openapi/errors v0.21.0/go.mod h1:jxNTMUxRCKj65yb/okJGEtahVd7uvWnuWfj53bse4ho=
|
||||
github.com/go-openapi/jsonpointer v0.20.1 h1:MkK4VEIEZMj4wT9PmjaUmGflVBr9nvud4Q4UVFbDoBE=
|
||||
github.com/go-openapi/jsonpointer v0.20.1/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs=
|
||||
github.com/go-openapi/jsonreference v0.20.3 h1:EjGcjTW8pD1mRis6+w/gmoBdqv5+RbE9B85D1NgDOVQ=
|
||||
github.com/go-openapi/jsonreference v0.20.3/go.mod h1:FviDZ46i9ivh810gqzFLl5NttD5q3tSlMLqLr6okedM=
|
||||
github.com/go-openapi/loads v0.21.3 h1:8sSH2FIm/SnbDUGv572md4YqVMFne/a9Eubvcd3anew=
|
||||
github.com/go-openapi/loads v0.21.3/go.mod h1:Y3aMR24iHbKHppOj91nQ/SHc0cuPbAr4ndY4a02xydc=
|
||||
github.com/go-openapi/runtime v0.26.2 h1:elWyB9MacRzvIVgAZCBJmqTi7hBzU0hlKD4IvfX0Zl0=
|
||||
github.com/go-openapi/runtime v0.26.2/go.mod h1:O034jyRZ557uJKzngbMDJXkcKJVzXJiymdSfgejrcRw=
|
||||
github.com/go-openapi/spec v0.20.12 h1:cgSLbrsmziAP2iais+Vz7kSazwZ8rsUZd6TUzdDgkVI=
|
||||
github.com/go-openapi/spec v0.20.12/go.mod h1:iSCgnBcwbMW9SfzJb8iYynXvcY6C/QFrI7otzF7xGM4=
|
||||
github.com/go-openapi/strfmt v0.21.10 h1:JIsly3KXZB/Qf4UzvzJpg4OELH/0ASDQsyk//TTBDDk=
|
||||
github.com/go-openapi/strfmt v0.21.10/go.mod h1:vNDMwbilnl7xKiO/Ve/8H8Bb2JIInBnH+lqiw6QWgis=
|
||||
github.com/go-openapi/swag v0.22.5 h1:fVS63IE3M0lsuWRzuom3RLwUMVI2peDH01s6M70ugys=
|
||||
github.com/go-openapi/swag v0.22.5/go.mod h1:Gl91UqO+btAM0plGGxHqJcQZ1ZTy6jbmridBTsDy8A0=
|
||||
github.com/go-openapi/validate v0.22.4 h1:5v3jmMyIPKTR8Lv9syBAIRxG6lY0RqeBPB1LKEijzk8=
|
||||
github.com/go-openapi/validate v0.22.4/go.mod h1:qm6O8ZIcPVdSY5219468Jv7kBdGvkiZLPOmqnqTUZ2A=
|
||||
github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU=
|
||||
github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo=
|
||||
github.com/go-openapi/errors v0.22.2 h1:rdxhzcBUazEcGccKqbY1Y7NS8FDcMyIRr0934jrYnZg=
|
||||
github.com/go-openapi/errors v0.22.2/go.mod h1:+n/5UdIqdVnLIJ6Q9Se8HNGUXYaY6CN8ImWzfi/Gzp0=
|
||||
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
||||
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
||||
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
|
||||
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
|
||||
github.com/go-openapi/loads v0.22.0 h1:ECPGd4jX1U6NApCGG1We+uEozOAvXvJSF4nnwHZ8Aco=
|
||||
github.com/go-openapi/loads v0.22.0/go.mod h1:yLsaTCS92mnSAZX5WWoxszLj0u+Ojl+Zs5Stn1oF+rs=
|
||||
github.com/go-openapi/runtime v0.28.0 h1:gpPPmWSNGo214l6n8hzdXYhPuJcGtziTOgUpvsFWGIQ=
|
||||
github.com/go-openapi/runtime v0.28.0/go.mod h1:QN7OzcS+XuYmkQLw05akXk0jRH/eZ3kb18+1KwW9gyc=
|
||||
github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY=
|
||||
github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk=
|
||||
github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c=
|
||||
github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4=
|
||||
github.com/go-openapi/swag v0.24.1 h1:DPdYTZKo6AQCRqzwr/kGkxJzHhpKxZ9i/oX0zag+MF8=
|
||||
github.com/go-openapi/swag v0.24.1/go.mod h1:sm8I3lCPlspsBBwUm1t5oZeWZS0s7m/A+Psg0ooRU0A=
|
||||
github.com/go-openapi/swag/cmdutils v0.24.0 h1:KlRCffHwXFI6E5MV9n8o8zBRElpY4uK4yWyAMWETo9I=
|
||||
github.com/go-openapi/swag/cmdutils v0.24.0/go.mod h1:uxib2FAeQMByyHomTlsP8h1TtPd54Msu2ZDU/H5Vuf8=
|
||||
github.com/go-openapi/swag/conv v0.24.0 h1:ejB9+7yogkWly6pnruRX45D1/6J+ZxRu92YFivx54ik=
|
||||
github.com/go-openapi/swag/conv v0.24.0/go.mod h1:jbn140mZd7EW2g8a8Y5bwm8/Wy1slLySQQ0ND6DPc2c=
|
||||
github.com/go-openapi/swag/fileutils v0.24.0 h1:U9pCpqp4RUytnD689Ek/N1d2N/a//XCeqoH508H5oak=
|
||||
github.com/go-openapi/swag/fileutils v0.24.0/go.mod h1:3SCrCSBHyP1/N+3oErQ1gP+OX1GV2QYFSnrTbzwli90=
|
||||
github.com/go-openapi/swag/jsonname v0.24.0 h1:2wKS9bgRV/xB8c62Qg16w4AUiIrqqiniJFtZGi3dg5k=
|
||||
github.com/go-openapi/swag/jsonname v0.24.0/go.mod h1:GXqrPzGJe611P7LG4QB9JKPtUZ7flE4DOVechNaDd7Q=
|
||||
github.com/go-openapi/swag/jsonutils v0.24.0 h1:F1vE1q4pg1xtO3HTyJYRmEuJ4jmIp2iZ30bzW5XgZts=
|
||||
github.com/go-openapi/swag/jsonutils v0.24.0/go.mod h1:vBowZtF5Z4DDApIoxcIVfR8v0l9oq5PpYRUuteVu6f0=
|
||||
github.com/go-openapi/swag/loading v0.24.0 h1:ln/fWTwJp2Zkj5DdaX4JPiddFC5CHQpvaBKycOlceYc=
|
||||
github.com/go-openapi/swag/loading v0.24.0/go.mod h1:gShCN4woKZYIxPxbfbyHgjXAhO61m88tmjy0lp/LkJk=
|
||||
github.com/go-openapi/swag/mangling v0.24.0 h1:PGOQpViCOUroIeak/Uj/sjGAq9LADS3mOyjznmHy2pk=
|
||||
github.com/go-openapi/swag/mangling v0.24.0/go.mod h1:Jm5Go9LHkycsz0wfoaBDkdc4CkpuSnIEf62brzyCbhc=
|
||||
github.com/go-openapi/swag/netutils v0.24.0 h1:Bz02HRjYv8046Ycg/w80q3g9QCWeIqTvlyOjQPDjD8w=
|
||||
github.com/go-openapi/swag/netutils v0.24.0/go.mod h1:WRgiHcYTnx+IqfMCtu0hy9oOaPR0HnPbmArSRN1SkZM=
|
||||
github.com/go-openapi/swag/stringutils v0.24.0 h1:i4Z/Jawf9EvXOLUbT97O0HbPUja18VdBxeadyAqS1FM=
|
||||
github.com/go-openapi/swag/stringutils v0.24.0/go.mod h1:5nUXB4xA0kw2df5PRipZDslPJgJut+NjL7D25zPZ/4w=
|
||||
github.com/go-openapi/swag/typeutils v0.24.0 h1:d3szEGzGDf4L2y1gYOSSLeK6h46F+zibnEas2Jm/wIw=
|
||||
github.com/go-openapi/swag/typeutils v0.24.0/go.mod h1:q8C3Kmk/vh2VhpCLaoR2MVWOGP8y7Jc8l82qCTd1DYI=
|
||||
github.com/go-openapi/swag/yamlutils v0.24.0 h1:bhw4894A7Iw6ne+639hsBNRHg9iZg/ISrOVr+sJGp4c=
|
||||
github.com/go-openapi/swag/yamlutils v0.24.0/go.mod h1:DpKv5aYuaGm/sULePoeiG8uwMpZSfReo1HR3Ik0yaG8=
|
||||
github.com/go-openapi/validate v0.24.0 h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3BumrGD58=
|
||||
github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
|
||||
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
||||
|
|
@ -201,7 +221,6 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
|
|||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
|
||||
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
||||
|
|
@ -229,8 +248,8 @@ github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
|
|||
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
|
||||
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
|
||||
github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas=
|
||||
|
|
@ -304,8 +323,8 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
|||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/hcl/v2 v2.19.1 h1://i05Jqznmb2EXqa39Nsvyan2o5XyMowW5fnCKW5RPI=
|
||||
github.com/hashicorp/hcl/v2 v2.19.1/go.mod h1:ThLC89FV4p9MPW804KVbe/cEXoQ8NZEh+JtMeeGErHE=
|
||||
github.com/hashicorp/hcp-sdk-go v0.136.0 h1:NNtb/dYoj7YrVQVvWZ2T7PY2Pwn8vQ5YKIAgaqaKk6A=
|
||||
github.com/hashicorp/hcp-sdk-go v0.136.0/go.mod h1:vQ4fzdL1AmhIAbCw+4zmFe5Hbpajj3NvRWkJoVuxmAk=
|
||||
github.com/hashicorp/hcp-sdk-go-internal v0.0.0-20260304114239-45aa9349dd39 h1:HtR5UFigB5Kj5KO0OiMbnsjimqyGlvZXOCsSFQQPgvc=
|
||||
github.com/hashicorp/hcp-sdk-go-internal v0.0.0-20260304114239-45aa9349dd39/go.mod h1:v2vbpNIrmgUTelW4Z+ur+aQuSPxeaVK3xytFdpEXvSg=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
|
||||
github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM=
|
||||
|
|
@ -374,8 +393,8 @@ github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3v
|
|||
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
|
||||
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
|
||||
github.com/masterzen/simplexml v0.0.0-20190410153822-31eea3082786 h1:2ZKn+w/BJeL43sCxI2jhPLRv73oVVOjEKZjKkflyqxg=
|
||||
github.com/masterzen/simplexml v0.0.0-20190410153822-31eea3082786/go.mod h1:kCEbxUJlNDEBNbdQMkPSp6yaKcRXVI6f4ddk8Riv4bc=
|
||||
github.com/masterzen/winrm v0.0.0-20250927112105-5f8e6c707321 h1:AKIJL2PfBX2uie0Mn5pxtG1+zut3hAVMZbRfoXecFzI=
|
||||
|
|
@ -438,7 +457,6 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ
|
|||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ=
|
||||
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U=
|
||||
|
|
@ -536,8 +554,8 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
|
|||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/terminalstatic/go-xsd-validate v0.1.5 h1:RqpJnf6HGE2CB/lZB1A8BYguk8uRtcvYAPLCF15qguo=
|
||||
github.com/terminalstatic/go-xsd-validate v0.1.5/go.mod h1:18lsvYFofBflqCrvo1umpABZ99+GneNTw2kEEc8UPJw=
|
||||
github.com/tidwall/transform v0.0.0-20201103190739-32f242e2dbde h1:AMNpJRc7P+GTwVbl8DkK2I9I8BBUzNiHuH/tlxrpan0=
|
||||
|
|
@ -560,16 +578,12 @@ github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAh
|
|||
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
|
||||
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
||||
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
|
||||
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
||||
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
|
|
@ -577,18 +591,18 @@ github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b h1:FosyBZYxY3
|
|||
github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8=
|
||||
github.com/zclconf/go-cty-yaml v1.0.1 h1:up11wlgAaDvlAGENcFDnZgkn0qUJurso7k6EpURKNF8=
|
||||
github.com/zclconf/go-cty-yaml v1.0.1/go.mod h1:IP3Ylp0wQpYm50IHK8OZWKMu6sPJIUgKa8XhiVHura0=
|
||||
go.mongodb.org/mongo-driver v1.13.1 h1:YIc7HTYsKndGK4RFzJ3covLz1byri52x0IoMB0Pt/vk=
|
||||
go.mongodb.org/mongo-driver v1.13.1/go.mod h1:wcDf1JBCXy2mOW0bWHwO/IOYqdca1MPCwDtFu/Z9+eo=
|
||||
go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80=
|
||||
go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/otel v1.17.0 h1:MW+phZ6WZ5/uk2nd93ANk/6yJ+dVrvNWUjGhnnFU5jM=
|
||||
go.opentelemetry.io/otel v1.17.0/go.mod h1:I2vmBGtFaODIVMBSTPVDlJSzBDNf93k60E6Ft0nyjo0=
|
||||
go.opentelemetry.io/otel/metric v1.17.0 h1:iG6LGVz5Gh+IuO0jmgvpTB6YVrCGngi8QGm+pMd8Pdc=
|
||||
go.opentelemetry.io/otel/metric v1.17.0/go.mod h1:h4skoxdZI17AxwITdmdZjjYJQH5nzijUUjm+wtPph5o=
|
||||
go.opentelemetry.io/otel/sdk v1.17.0 h1:FLN2X66Ke/k5Sg3V623Q7h7nt3cHXaW1FOvKKrW0IpE=
|
||||
go.opentelemetry.io/otel/sdk v1.17.0/go.mod h1:U87sE0f5vQB7hwUoW98pW5Rz4ZDuCFBZFNUBlSgmDFQ=
|
||||
go.opentelemetry.io/otel/trace v1.17.0 h1:/SWhSRHmDPOImIAetP1QAeMnZYiQXrTy4fMMYOdSKWQ=
|
||||
go.opentelemetry.io/otel/trace v1.17.0/go.mod h1:I/4vKTgFclIsXRVucpH25X0mpFSczM7aHeaz0ZBLWjY=
|
||||
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
|
||||
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
|
||||
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
|
||||
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
|
||||
go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw=
|
||||
go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg=
|
||||
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
|
||||
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
|
|
@ -639,8 +653,8 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
|||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M=
|
||||
golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
|
|
|||
111
hcl2template/enforced_provisioner.go
Normal file
111
hcl2template/enforced_provisioner.go
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
// Copyright IBM Corp. 2013, 2025
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package hcl2template
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
"github.com/hashicorp/hcl/v2/hclparse"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
var enforcedProvisionerSchema = &hcl.BodySchema{
|
||||
Blocks: []hcl.BlockHeaderSchema{
|
||||
{Type: buildProvisionerLabel, LabelNames: []string{"type"}},
|
||||
},
|
||||
}
|
||||
|
||||
// ParseProvisionerBlocks parses a partial HCL string that contains only
|
||||
// top-level provisioner blocks and returns the parsed ProvisionerBlock list.
|
||||
func ParseProvisionerBlocks(blockContent string) ([]*ProvisionerBlock, hcl.Diagnostics) {
|
||||
parser := &Parser{Parser: hclparse.NewParser()}
|
||||
file, diags := parser.ParseHCL([]byte(blockContent), "enforced_provisioner.pkr.hcl")
|
||||
if diags.HasErrors() {
|
||||
return nil, diags
|
||||
}
|
||||
|
||||
content, moreDiags := file.Body.Content(enforcedProvisionerSchema)
|
||||
diags = append(diags, moreDiags...)
|
||||
if diags.HasErrors() {
|
||||
return nil, diags
|
||||
}
|
||||
|
||||
ectx := &hcl.EvalContext{Variables: map[string]cty.Value{}}
|
||||
provisioners := make([]*ProvisionerBlock, 0, len(content.Blocks))
|
||||
|
||||
for _, block := range content.Blocks {
|
||||
prov, moreDiags := parser.decodeProvisioner(block, ectx)
|
||||
diags = append(diags, moreDiags...)
|
||||
if moreDiags.HasErrors() {
|
||||
continue
|
||||
}
|
||||
provisioners = append(provisioners, prov)
|
||||
}
|
||||
|
||||
return provisioners, diags
|
||||
}
|
||||
|
||||
// GetCoreBuildProvisionerFromBlock converts a ProvisionerBlock to a CoreBuildProvisioner.
|
||||
// This is used for enforced provisioners that need to be injected into builds.
|
||||
func (cfg *PackerConfig) GetCoreBuildProvisionerFromBlock(pb *ProvisionerBlock) (packer.CoreBuildProvisioner, hcl.Diagnostics) {
|
||||
var diags hcl.Diagnostics
|
||||
|
||||
// Get the provisioner plugin
|
||||
provisioner, err := cfg.parser.PluginConfig.Provisioners.Start(pb.PType)
|
||||
if err != nil {
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: fmt.Sprintf("Failed to start enforced provisioner %q", pb.PType),
|
||||
Detail: fmt.Sprintf("The provisioner plugin could not be loaded: %s", err.Error()),
|
||||
})
|
||||
return packer.CoreBuildProvisioner{}, diags
|
||||
}
|
||||
|
||||
// Create basic builder variables
|
||||
builderVars := map[string]interface{}{
|
||||
"packer_core_version": cfg.CorePackerVersionString,
|
||||
"packer_debug": strconv.FormatBool(cfg.debug),
|
||||
"packer_force": strconv.FormatBool(cfg.force),
|
||||
"packer_on_error": cfg.onError,
|
||||
"packer_sensitive_variables": []string{},
|
||||
}
|
||||
|
||||
// Create evaluation context
|
||||
ectx := cfg.EvalContext(BuildContext, nil)
|
||||
|
||||
// Create the HCL2Provisioner wrapper
|
||||
hclProvisioner := &HCL2Provisioner{
|
||||
Provisioner: provisioner,
|
||||
provisionerBlock: pb,
|
||||
evalContext: ectx,
|
||||
builderVariables: builderVars,
|
||||
}
|
||||
|
||||
// Prepare the provisioner
|
||||
err = hclProvisioner.HCL2Prepare(nil)
|
||||
if err != nil {
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: fmt.Sprintf("Failed to prepare enforced provisioner %q", pb.PType),
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return packer.CoreBuildProvisioner{}, diags
|
||||
}
|
||||
|
||||
// Wrap provisioner with any special behavior (pause, timeout, retry)
|
||||
wrappedProvisioner := packer.WrapProvisionerWithOptions(hclProvisioner, packer.ProvisionerWrapOptions{
|
||||
PauseBefore: pb.PauseBefore,
|
||||
Timeout: pb.Timeout,
|
||||
MaxRetries: pb.MaxRetries,
|
||||
})
|
||||
|
||||
return packer.CoreBuildProvisioner{
|
||||
PType: pb.PType,
|
||||
PName: pb.PName,
|
||||
Provisioner: wrappedProvisioner,
|
||||
}, diags
|
||||
}
|
||||
212
hcl2template/enforced_provisioner_test.go
Normal file
212
hcl2template/enforced_provisioner_test.go
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
// Copyright IBM Corp. 2013, 2025
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package hcl2template
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseProvisionerBlocks(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
blockContent string
|
||||
wantCount int
|
||||
wantTypes []string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "single shell provisioner",
|
||||
blockContent: `
|
||||
provisioner "shell" {
|
||||
inline = ["echo 'Hello from enforced provisioner'"]
|
||||
}
|
||||
`,
|
||||
wantCount: 1,
|
||||
wantTypes: []string{"shell"},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "multiple provisioners",
|
||||
blockContent: `
|
||||
provisioner "shell" {
|
||||
inline = ["echo 'First enforced provisioner'"]
|
||||
}
|
||||
|
||||
provisioner "shell" {
|
||||
name = "security-scan"
|
||||
inline = ["echo 'Security scan running...'"]
|
||||
}
|
||||
`,
|
||||
wantCount: 2,
|
||||
wantTypes: []string{"shell", "shell"},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "provisioner with pause_before",
|
||||
blockContent: `
|
||||
provisioner "shell" {
|
||||
pause_before = "10s"
|
||||
inline = ["echo 'Waiting before execution'"]
|
||||
}
|
||||
`,
|
||||
wantCount: 1,
|
||||
wantTypes: []string{"shell"},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "provisioner with max_retries",
|
||||
blockContent: `
|
||||
provisioner "shell" {
|
||||
max_retries = 3
|
||||
inline = ["echo 'Retry test'"]
|
||||
}
|
||||
`,
|
||||
wantCount: 1,
|
||||
wantTypes: []string{"shell"},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "provisioner with only filter",
|
||||
blockContent: `
|
||||
provisioner "shell" {
|
||||
only = ["amazon-ebs.ubuntu"]
|
||||
inline = ["echo 'Only for amazon-ebs.ubuntu'"]
|
||||
}
|
||||
`,
|
||||
wantCount: 1,
|
||||
wantTypes: []string{"shell"},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "provisioner with except filter",
|
||||
blockContent: `
|
||||
provisioner "shell" {
|
||||
except = ["null.test"]
|
||||
inline = ["echo 'Except for null.test'"]
|
||||
}
|
||||
`,
|
||||
wantCount: 1,
|
||||
wantTypes: []string{"shell"},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "empty block content",
|
||||
blockContent: "",
|
||||
wantCount: 0,
|
||||
wantTypes: nil,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "invalid HCL syntax",
|
||||
blockContent: "this is not valid { hcl }}}",
|
||||
wantCount: 0,
|
||||
wantTypes: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
blocks, diags := ParseProvisionerBlocks(tt.blockContent)
|
||||
|
||||
if tt.wantErr {
|
||||
if !diags.HasErrors() {
|
||||
t.Errorf("ParseProvisionerBlocks() expected error but got none")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if diags.HasErrors() {
|
||||
t.Errorf("ParseProvisionerBlocks() unexpected error: %v", diags)
|
||||
return
|
||||
}
|
||||
|
||||
if len(blocks) != tt.wantCount {
|
||||
t.Errorf("ParseProvisionerBlocks() got %d blocks, want %d", len(blocks), tt.wantCount)
|
||||
return
|
||||
}
|
||||
|
||||
for i, wantType := range tt.wantTypes {
|
||||
if blocks[i].PType != wantType {
|
||||
t.Errorf("ParseProvisionerBlocks() block[%d].PType = %q, want %q", i, blocks[i].PType, wantType)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseProvisionerBlocksWithPauseBefore(t *testing.T) {
|
||||
blockContent := `
|
||||
provisioner "shell" {
|
||||
pause_before = "30s"
|
||||
inline = ["echo 'test'"]
|
||||
}
|
||||
`
|
||||
blocks, diags := ParseProvisionerBlocks(blockContent)
|
||||
if diags.HasErrors() {
|
||||
t.Fatalf("ParseProvisionerBlocks() unexpected error: %v", diags)
|
||||
}
|
||||
|
||||
if len(blocks) != 1 {
|
||||
t.Fatalf("Expected 1 block, got %d", len(blocks))
|
||||
}
|
||||
|
||||
// pause_before should be parsed as 30 seconds
|
||||
if blocks[0].PauseBefore.Seconds() != 30 {
|
||||
t.Errorf("Expected PauseBefore=30s, got %v", blocks[0].PauseBefore)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseProvisionerBlocksWithMaxRetries(t *testing.T) {
|
||||
blockContent := `
|
||||
provisioner "shell" {
|
||||
max_retries = 5
|
||||
inline = ["echo 'test'"]
|
||||
}
|
||||
`
|
||||
blocks, diags := ParseProvisionerBlocks(blockContent)
|
||||
if diags.HasErrors() {
|
||||
t.Fatalf("ParseProvisionerBlocks() unexpected error: %v", diags)
|
||||
}
|
||||
|
||||
if len(blocks) != 1 {
|
||||
t.Fatalf("Expected 1 block, got %d", len(blocks))
|
||||
}
|
||||
|
||||
if blocks[0].MaxRetries != 5 {
|
||||
t.Errorf("Expected MaxRetries=5, got %d", blocks[0].MaxRetries)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseProvisionerBlocksWithOnlyExcept(t *testing.T) {
|
||||
blockContent := `
|
||||
provisioner "shell" {
|
||||
only = ["amazon-ebs.ubuntu", "azure-arm.windows"]
|
||||
inline = ["echo 'test'"]
|
||||
}
|
||||
`
|
||||
blocks, diags := ParseProvisionerBlocks(blockContent)
|
||||
if diags.HasErrors() {
|
||||
t.Fatalf("ParseProvisionerBlocks() unexpected error: %v", diags)
|
||||
}
|
||||
|
||||
if len(blocks) != 1 {
|
||||
t.Fatalf("Expected 1 block, got %d", len(blocks))
|
||||
}
|
||||
|
||||
// Check only filter
|
||||
if len(blocks[0].OnlyExcept.Only) != 2 {
|
||||
t.Errorf("Expected 2 only values, got %d", len(blocks[0].OnlyExcept.Only))
|
||||
}
|
||||
|
||||
// Skip should return true for sources not in the only list
|
||||
if !blocks[0].OnlyExcept.Skip("null.test") {
|
||||
t.Error("Skip() should return true for source not in only list")
|
||||
}
|
||||
|
||||
// Skip should return false for sources in the only list
|
||||
if blocks[0].OnlyExcept.Skip("amazon-ebs.ubuntu") {
|
||||
t.Error("Skip() should return false for source in only list")
|
||||
}
|
||||
}
|
||||
|
|
@ -6,9 +6,11 @@ package hcl2template
|
|||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
"github.com/hashicorp/hcl/v2/gohcl"
|
||||
"github.com/hashicorp/hcl/v2/hclwrite"
|
||||
)
|
||||
|
||||
type HCPPackerRegistryBlock struct {
|
||||
|
|
@ -97,3 +99,43 @@ func (p *Parser) decodeHCPRegistry(block *hcl.Block, cfg *PackerConfig) (*HCPPac
|
|||
|
||||
return par, diags
|
||||
}
|
||||
|
||||
// ExtractBuildProvisionerHCL extracts all provisioner blocks from the build
|
||||
// blocks in the configuration and returns them as raw HCL content.
|
||||
// This is used to publish provisioner configurations as enforced blocks
|
||||
// to HCP Packer, so that other builds against the same bucket will
|
||||
// automatically have these provisioners injected.
|
||||
func (cfg *PackerConfig) ExtractBuildProvisionerHCL() (string, error) {
|
||||
sourceFiles := cfg.parser.Files()
|
||||
|
||||
var buf strings.Builder
|
||||
|
||||
for filename, file := range sourceFiles {
|
||||
// hclwrite only supports HCL native syntax, skip JSON and variable files
|
||||
if !strings.HasSuffix(filename, hcl2FileExt) {
|
||||
continue
|
||||
}
|
||||
|
||||
wf, diags := hclwrite.ParseConfig(file.Bytes, filename, hcl.Pos{Line: 1, Column: 1})
|
||||
if diags.HasErrors() {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, block := range wf.Body().Blocks() {
|
||||
if block.Type() != buildLabel {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, inner := range block.Body().Blocks() {
|
||||
if inner.Type() != buildProvisionerLabel {
|
||||
continue
|
||||
}
|
||||
|
||||
buf.Write(inner.BuildTokens(nil).Bytes())
|
||||
buf.WriteString("\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return strings.TrimSpace(buf.String()), nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,11 @@ type MockPackerClientService struct {
|
|||
UpdateChannelCalled bool
|
||||
TrackCalledServiceMethods bool
|
||||
|
||||
// Enforced block tracking
|
||||
CreateEnforcedBlockCalled, GetEnforcedBlockCalled, ListEnforcedBlocksCalled bool
|
||||
CreateEnforcedBlockVersionCalled, GetEnforcedBlockVersionsCalled bool
|
||||
GetEnforcedBlocksByBucketCalled bool
|
||||
|
||||
// Mock Creates
|
||||
CreateBucketResp *hcpPackerModels.HashicorpCloudPacker20230101CreateBucketResponse
|
||||
CreateVersionResp *hcpPackerModels.HashicorpCloudPacker20230101CreateVersionResponse
|
||||
|
|
@ -33,6 +38,20 @@ type MockPackerClientService struct {
|
|||
// Mock Gets
|
||||
GetVersionResp *hcpPackerModels.HashicorpCloudPacker20230101GetVersionResponse
|
||||
|
||||
// Mock enforced blocks
|
||||
CreateEnforcedBlockResp *hcpPackerModels.HashicorpCloudPacker20230101CreateEnforcedBlockResponse
|
||||
CreateEnforcedBlockErr error
|
||||
GetEnforcedBlockResp *hcpPackerModels.HashicorpCloudPacker20230101GetEnforcedBlockResponse
|
||||
GetEnforcedBlockErr error
|
||||
ListEnforcedBlocksResp *hcpPackerModels.HashicorpCloudPacker20230101ListEnforcedBlocksResponse
|
||||
ListEnforcedBlocksErr error
|
||||
CreateEnforcedBlockVersionResp *hcpPackerModels.HashicorpCloudPacker20230101CreateEnforcedBlockVersionResponse
|
||||
CreateEnforcedBlockVersionErr error
|
||||
GetEnforcedBlockVersionsResp *hcpPackerModels.HashicorpCloudPacker20230101GetEnforcedBlockVersionsResponse
|
||||
GetEnforcedBlockVersionsErr error
|
||||
GetEnforcedBlocksByBucketResp *hcpPackerModels.HashicorpCloudPacker20230101GetEnforcedBlocksByBucketResponse
|
||||
GetEnforcedBlocksByBucketErr error
|
||||
|
||||
ExistingBuilds []string
|
||||
ExistingBuildLabels map[string]string
|
||||
|
||||
|
|
@ -321,3 +340,163 @@ func (svc *MockPackerClientService) PackerServiceUpdateChannel(
|
|||
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
func (svc *MockPackerClientService) PackerServiceCreateEnforcedBlock(
|
||||
params *hcpPackerService.PackerServiceCreateEnforcedBlockParams, _ runtime.ClientAuthInfoWriter,
|
||||
opts ...hcpPackerService.ClientOption,
|
||||
) (*hcpPackerService.PackerServiceCreateEnforcedBlockOK, error) {
|
||||
|
||||
if svc.TrackCalledServiceMethods {
|
||||
svc.CreateEnforcedBlockCalled = true
|
||||
}
|
||||
|
||||
if svc.CreateEnforcedBlockErr != nil {
|
||||
return nil, svc.CreateEnforcedBlockErr
|
||||
}
|
||||
|
||||
ok := &hcpPackerService.PackerServiceCreateEnforcedBlockOK{}
|
||||
if svc.CreateEnforcedBlockResp != nil {
|
||||
ok.Payload = svc.CreateEnforcedBlockResp
|
||||
} else {
|
||||
ok.Payload = &hcpPackerModels.HashicorpCloudPacker20230101CreateEnforcedBlockResponse{
|
||||
EnforcedBlock: &hcpPackerModels.HashicorpCloudPacker20230101EnforcedBlock{
|
||||
ID: "enforced-block-id",
|
||||
Name: params.Body.Name,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
func (svc *MockPackerClientService) PackerServiceGetEnforcedBlock(
|
||||
params *hcpPackerService.PackerServiceGetEnforcedBlockParams, _ runtime.ClientAuthInfoWriter,
|
||||
opts ...hcpPackerService.ClientOption,
|
||||
) (*hcpPackerService.PackerServiceGetEnforcedBlockOK, error) {
|
||||
|
||||
if svc.TrackCalledServiceMethods {
|
||||
svc.GetEnforcedBlockCalled = true
|
||||
}
|
||||
|
||||
if svc.GetEnforcedBlockErr != nil {
|
||||
return nil, svc.GetEnforcedBlockErr
|
||||
}
|
||||
|
||||
ok := &hcpPackerService.PackerServiceGetEnforcedBlockOK{}
|
||||
if svc.GetEnforcedBlockResp != nil {
|
||||
ok.Payload = svc.GetEnforcedBlockResp
|
||||
} else {
|
||||
ok.Payload = &hcpPackerModels.HashicorpCloudPacker20230101GetEnforcedBlockResponse{
|
||||
EnforcedBlock: &hcpPackerModels.HashicorpCloudPacker20230101EnforcedBlock{
|
||||
ID: params.EnforcedBlockID,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
func (svc *MockPackerClientService) PackerServiceListEnforcedBlocks(
|
||||
params *hcpPackerService.PackerServiceListEnforcedBlocksParams, _ runtime.ClientAuthInfoWriter,
|
||||
opts ...hcpPackerService.ClientOption,
|
||||
) (*hcpPackerService.PackerServiceListEnforcedBlocksOK, error) {
|
||||
|
||||
if svc.TrackCalledServiceMethods {
|
||||
svc.ListEnforcedBlocksCalled = true
|
||||
}
|
||||
|
||||
if svc.ListEnforcedBlocksErr != nil {
|
||||
return nil, svc.ListEnforcedBlocksErr
|
||||
}
|
||||
|
||||
ok := &hcpPackerService.PackerServiceListEnforcedBlocksOK{}
|
||||
if svc.ListEnforcedBlocksResp != nil {
|
||||
ok.Payload = svc.ListEnforcedBlocksResp
|
||||
} else {
|
||||
ok.Payload = &hcpPackerModels.HashicorpCloudPacker20230101ListEnforcedBlocksResponse{
|
||||
EnforcedBlocks: []*hcpPackerModels.HashicorpCloudPacker20230101EnforcedBlock{},
|
||||
}
|
||||
}
|
||||
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
func (svc *MockPackerClientService) PackerServiceCreateEnforcedBlockVersion(
|
||||
params *hcpPackerService.PackerServiceCreateEnforcedBlockVersionParams, _ runtime.ClientAuthInfoWriter,
|
||||
opts ...hcpPackerService.ClientOption,
|
||||
) (*hcpPackerService.PackerServiceCreateEnforcedBlockVersionOK, error) {
|
||||
|
||||
if svc.TrackCalledServiceMethods {
|
||||
svc.CreateEnforcedBlockVersionCalled = true
|
||||
}
|
||||
|
||||
if svc.CreateEnforcedBlockVersionErr != nil {
|
||||
return nil, svc.CreateEnforcedBlockVersionErr
|
||||
}
|
||||
|
||||
ok := &hcpPackerService.PackerServiceCreateEnforcedBlockVersionOK{}
|
||||
if svc.CreateEnforcedBlockVersionResp != nil {
|
||||
ok.Payload = svc.CreateEnforcedBlockVersionResp
|
||||
} else {
|
||||
ok.Payload = &hcpPackerModels.HashicorpCloudPacker20230101CreateEnforcedBlockVersionResponse{
|
||||
EnforcedBlockVersion: &hcpPackerModels.HashicorpCloudPacker20230101EnforcedBlockVersion{
|
||||
ID: "enforced-block-version-id",
|
||||
EnforcedBlockID: params.EnforcedBlockID,
|
||||
BlockContent: params.Body.BlockContent,
|
||||
Version: params.Body.Version,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
func (svc *MockPackerClientService) PackerServiceGetEnforcedBlockVersions(
|
||||
params *hcpPackerService.PackerServiceGetEnforcedBlockVersionsParams, _ runtime.ClientAuthInfoWriter,
|
||||
opts ...hcpPackerService.ClientOption,
|
||||
) (*hcpPackerService.PackerServiceGetEnforcedBlockVersionsOK, error) {
|
||||
|
||||
if svc.TrackCalledServiceMethods {
|
||||
svc.GetEnforcedBlockVersionsCalled = true
|
||||
}
|
||||
|
||||
if svc.GetEnforcedBlockVersionsErr != nil {
|
||||
return nil, svc.GetEnforcedBlockVersionsErr
|
||||
}
|
||||
|
||||
ok := &hcpPackerService.PackerServiceGetEnforcedBlockVersionsOK{}
|
||||
if svc.GetEnforcedBlockVersionsResp != nil {
|
||||
ok.Payload = svc.GetEnforcedBlockVersionsResp
|
||||
} else {
|
||||
ok.Payload = &hcpPackerModels.HashicorpCloudPacker20230101GetEnforcedBlockVersionsResponse{
|
||||
EnforcedBlockDetail: []*hcpPackerModels.HashicorpCloudPacker20230101EnforcedBlockDetail{},
|
||||
}
|
||||
}
|
||||
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
func (svc *MockPackerClientService) PackerServiceGetEnforcedBlocksByBucket(
|
||||
params *hcpPackerService.PackerServiceGetEnforcedBlocksByBucketParams, _ runtime.ClientAuthInfoWriter,
|
||||
opts ...hcpPackerService.ClientOption,
|
||||
) (*hcpPackerService.PackerServiceGetEnforcedBlocksByBucketOK, error) {
|
||||
|
||||
if svc.TrackCalledServiceMethods {
|
||||
svc.GetEnforcedBlocksByBucketCalled = true
|
||||
}
|
||||
|
||||
if svc.GetEnforcedBlocksByBucketErr != nil {
|
||||
return nil, svc.GetEnforcedBlocksByBucketErr
|
||||
}
|
||||
|
||||
ok := &hcpPackerService.PackerServiceGetEnforcedBlocksByBucketOK{}
|
||||
if svc.GetEnforcedBlocksByBucketResp != nil {
|
||||
ok.Payload = svc.GetEnforcedBlocksByBucketResp
|
||||
} else {
|
||||
ok.Payload = &hcpPackerModels.HashicorpCloudPacker20230101GetEnforcedBlocksByBucketResponse{
|
||||
EnforcedBlockDetail: []*hcpPackerModels.HashicorpCloudPacker20230101EnforcedBlockDetail{},
|
||||
}
|
||||
}
|
||||
|
||||
return ok, nil
|
||||
}
|
||||
|
|
|
|||
151
internal/hcp/api/service_enforced_provisioner.go
Normal file
151
internal/hcp/api/service_enforced_provisioner.go
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
// Copyright IBM Corp. 2013, 2025
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
hcpPackerService "github.com/hashicorp/hcp-sdk-go/clients/cloud-packer-service/stable/2023-01-01/client/packer_service"
|
||||
hcpPackerModels "github.com/hashicorp/hcp-sdk-go/clients/cloud-packer-service/stable/2023-01-01/models"
|
||||
)
|
||||
|
||||
// CreateEnforcedBlock creates a new enforced block in the HCP Packer registry.
|
||||
// The block content contains raw HCL provisioner configuration that will be
|
||||
// enforced on all builds for buckets linked to this enforced block.
|
||||
func (c *Client) CreateEnforcedBlock(
|
||||
ctx context.Context,
|
||||
name string,
|
||||
blockContent string,
|
||||
version string,
|
||||
templateType hcpPackerModels.HashicorpCloudPacker20230101TemplateType,
|
||||
description string,
|
||||
labels map[string]string,
|
||||
) (*hcpPackerModels.HashicorpCloudPacker20230101CreateEnforcedBlockResponse, error) {
|
||||
|
||||
params := hcpPackerService.NewPackerServiceCreateEnforcedBlockParamsWithContext(ctx)
|
||||
params.LocationOrganizationID = c.OrganizationID
|
||||
params.LocationProjectID = c.ProjectID
|
||||
params.Body = &hcpPackerModels.HashicorpCloudPacker20230101CreateEnforcedBlockBody{
|
||||
Name: name,
|
||||
BlockContent: blockContent,
|
||||
Version: version,
|
||||
TemplateType: &templateType,
|
||||
AdditionalDescription: description,
|
||||
Labels: labels,
|
||||
}
|
||||
|
||||
resp, err := c.Packer.PackerServiceCreateEnforcedBlock(params, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resp.Payload, nil
|
||||
}
|
||||
|
||||
// GetEnforcedBlock retrieves a single enforced block by its ID.
|
||||
func (c *Client) GetEnforcedBlock(
|
||||
ctx context.Context,
|
||||
enforcedBlockID string,
|
||||
) (*hcpPackerModels.HashicorpCloudPacker20230101GetEnforcedBlockResponse, error) {
|
||||
|
||||
params := hcpPackerService.NewPackerServiceGetEnforcedBlockParamsWithContext(ctx)
|
||||
params.LocationOrganizationID = c.OrganizationID
|
||||
params.LocationProjectID = c.ProjectID
|
||||
params.EnforcedBlockID = enforcedBlockID
|
||||
|
||||
resp, err := c.Packer.PackerServiceGetEnforcedBlock(params, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resp.Payload, nil
|
||||
}
|
||||
|
||||
// ListEnforcedBlocks lists all enforced blocks in the current project.
|
||||
func (c *Client) ListEnforcedBlocks(
|
||||
ctx context.Context,
|
||||
) (*hcpPackerModels.HashicorpCloudPacker20230101ListEnforcedBlocksResponse, error) {
|
||||
|
||||
params := hcpPackerService.NewPackerServiceListEnforcedBlocksParamsWithContext(ctx)
|
||||
params.LocationOrganizationID = c.OrganizationID
|
||||
params.LocationProjectID = c.ProjectID
|
||||
|
||||
resp, err := c.Packer.PackerServiceListEnforcedBlocks(params, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resp.Payload, nil
|
||||
}
|
||||
|
||||
// CreateEnforcedBlockVersion creates a new version of an existing enforced block.
|
||||
// This allows updating the block content while keeping a version history.
|
||||
func (c *Client) CreateEnforcedBlockVersion(
|
||||
ctx context.Context,
|
||||
enforcedBlockID string,
|
||||
blockContent string,
|
||||
version string,
|
||||
templateType hcpPackerModels.HashicorpCloudPacker20230101TemplateType,
|
||||
description string,
|
||||
) (*hcpPackerModels.HashicorpCloudPacker20230101CreateEnforcedBlockVersionResponse, error) {
|
||||
|
||||
params := hcpPackerService.NewPackerServiceCreateEnforcedBlockVersionParamsWithContext(ctx)
|
||||
params.LocationOrganizationID = c.OrganizationID
|
||||
params.LocationProjectID = c.ProjectID
|
||||
params.EnforcedBlockID = enforcedBlockID
|
||||
params.Body = &hcpPackerModels.HashicorpCloudPacker20230101CreateEnforcedBlockVersionBody{
|
||||
BlockContent: blockContent,
|
||||
Version: version,
|
||||
TemplateType: &templateType,
|
||||
AdditionalDescription: description,
|
||||
}
|
||||
|
||||
resp, err := c.Packer.PackerServiceCreateEnforcedBlockVersion(params, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resp.Payload, nil
|
||||
}
|
||||
|
||||
// GetEnforcedBlockVersions retrieves all versions of an enforced block.
|
||||
func (c *Client) GetEnforcedBlockVersions(
|
||||
ctx context.Context,
|
||||
enforcedBlockID string,
|
||||
) (*hcpPackerModels.HashicorpCloudPacker20230101GetEnforcedBlockVersionsResponse, error) {
|
||||
|
||||
params := hcpPackerService.NewPackerServiceGetEnforcedBlockVersionsParamsWithContext(ctx)
|
||||
params.LocationOrganizationID = c.OrganizationID
|
||||
params.LocationProjectID = c.ProjectID
|
||||
params.EnforcedBlockID = enforcedBlockID
|
||||
|
||||
resp, err := c.Packer.PackerServiceGetEnforcedBlockVersions(params, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resp.Payload, nil
|
||||
}
|
||||
|
||||
// GetEnforcedBlocksForBucket fetches all enforced blocks linked to a bucket.
|
||||
// This is the key method used during packer build to auto-inject provisioners.
|
||||
// The response includes EnforcedBlockDetail entries each with an active version
|
||||
// containing the raw HCL block_content to be parsed and injected.
|
||||
func (c *Client) GetEnforcedBlocksForBucket(
|
||||
ctx context.Context,
|
||||
bucketName string,
|
||||
) (*hcpPackerModels.HashicorpCloudPacker20230101GetEnforcedBlocksByBucketResponse, error) {
|
||||
|
||||
params := hcpPackerService.NewPackerServiceGetEnforcedBlocksByBucketParamsWithContext(ctx)
|
||||
params.LocationOrganizationID = c.OrganizationID
|
||||
params.LocationProjectID = c.ProjectID
|
||||
params.BucketName = bucketName
|
||||
|
||||
resp, err := c.Packer.PackerServiceGetEnforcedBlocksByBucket(params, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resp.Payload, nil
|
||||
}
|
||||
|
|
@ -43,6 +43,21 @@ func (h *HCLRegistry) PopulateVersion(ctx context.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// Extract provisioner blocks from the build and publish them as enforced
|
||||
// blocks to HCP Packer, so other builds against the same bucket will
|
||||
// automatically have these provisioners injected.
|
||||
blockContent, err := h.configuration.ExtractBuildProvisionerHCL()
|
||||
if err != nil {
|
||||
log.Printf("[WARN] failed to extract provisioner blocks for enforced publishing: %v", err)
|
||||
} else if blockContent != "" {
|
||||
blockName := h.bucket.Name + "-provisioners"
|
||||
if pubErr := h.bucket.PublishEnforcedBlocks(
|
||||
ctx, blockName, blockContent, hcpPackerModels.HashicorpCloudPacker20230101TemplateTypeHCL2,
|
||||
); pubErr != nil {
|
||||
log.Printf("[WARN] failed to publish enforced blocks for bucket %q: %v", h.bucket.Name, pubErr)
|
||||
}
|
||||
}
|
||||
|
||||
err = h.bucket.populateVersion(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -91,6 +106,67 @@ func (h *HCLRegistry) VersionStatusSummary() {
|
|||
h.bucket.Version.statusSummary(h.ui)
|
||||
}
|
||||
|
||||
// FetchEnforcedBlocks fetches enforced provisioner blocks from HCP Packer
|
||||
func (h *HCLRegistry) FetchEnforcedBlocks(ctx context.Context) error {
|
||||
return h.bucket.FetchEnforcedBlocks(ctx)
|
||||
}
|
||||
|
||||
// InjectEnforcedProvisioners injects enforced provisioners into the builds
|
||||
func (h *HCLRegistry) InjectEnforcedProvisioners(builds []*packer.CoreBuild) hcl.Diagnostics {
|
||||
enforcedBlocks := h.bucket.EnforcedBlocks
|
||||
if len(enforcedBlocks) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var allDiags hcl.Diagnostics
|
||||
|
||||
// Parse all enforced blocks into provisioner blocks
|
||||
for _, eb := range enforcedBlocks {
|
||||
if eb.BlockContent == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
provBlocks, diags := hcl2template.ParseProvisionerBlocks(eb.BlockContent)
|
||||
if diags.HasErrors() {
|
||||
allDiags = append(allDiags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagWarning,
|
||||
Summary: fmt.Sprintf("Failed to parse enforced block %q", eb.Name),
|
||||
Detail: diags.Error(),
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
if len(provBlocks) > 0 {
|
||||
h.ui.Say(fmt.Sprintf("Loaded %d enforced provisioner(s) from HCP block %q", len(provBlocks), eb.Name))
|
||||
}
|
||||
|
||||
// Inject into each build
|
||||
for _, build := range builds {
|
||||
for _, pb := range provBlocks {
|
||||
// Check if this provisioner should be skipped for this build
|
||||
if pb.OnlyExcept.Skip(build.Type) {
|
||||
log.Printf("[DEBUG] skipping enforced provisioner %q for build %q due to only/except rules",
|
||||
pb.PType, build.Name())
|
||||
continue
|
||||
}
|
||||
|
||||
coreProv, moreDiags := h.configuration.GetCoreBuildProvisionerFromBlock(pb)
|
||||
if moreDiags.HasErrors() {
|
||||
allDiags = append(allDiags, moreDiags...)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Printf("[INFO] injecting enforced provisioner %q from block %q into build %q",
|
||||
pb.PType, eb.Name, build.Name())
|
||||
|
||||
build.Provisioners = append(build.Provisioners, coreProv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return allDiags
|
||||
}
|
||||
|
||||
func NewHCLRegistry(config *hcl2template.PackerConfig, ui sdkpacker.Ui) (*HCLRegistry, hcl.Diagnostics) {
|
||||
var diags hcl.Diagnostics
|
||||
if len(config.Builds) > 1 {
|
||||
|
|
|
|||
|
|
@ -113,3 +113,17 @@ func (h *JSONRegistry) VersionStatusSummary() {
|
|||
func (h *JSONRegistry) Metadata() Metadata {
|
||||
return h.metadata
|
||||
}
|
||||
|
||||
// FetchEnforcedBlocks fetches enforced provisioner blocks from HCP Packer
|
||||
func (h *JSONRegistry) FetchEnforcedBlocks(ctx context.Context) error {
|
||||
return h.bucket.FetchEnforcedBlocks(ctx)
|
||||
}
|
||||
|
||||
// InjectEnforcedProvisioners injects enforced provisioners into the builds
|
||||
// Note: JSON templates don't support enforced provisioners as they are a legacy format
|
||||
func (h *JSONRegistry) InjectEnforcedProvisioners(builds []*packer.CoreBuild) hcl.Diagnostics {
|
||||
if len(h.bucket.EnforcedBlocks) > 0 {
|
||||
h.ui.Say("Warning: Enforced provisioners are not supported for legacy JSON templates")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ package registry
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
sdkpacker "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
)
|
||||
|
|
@ -35,3 +36,11 @@ func (r nullRegistry) VersionStatusSummary() {}
|
|||
func (r nullRegistry) Metadata() Metadata {
|
||||
return NilMetadata{}
|
||||
}
|
||||
|
||||
func (r nullRegistry) FetchEnforcedBlocks(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r nullRegistry) InjectEnforcedProvisioners(builds []*packer.CoreBuild) hcl.Diagnostics {
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,10 @@ type Registry interface {
|
|||
CompleteBuild(ctx context.Context, build *packer.CoreBuild, artifacts []sdkpacker.Artifact, buildErr error) ([]sdkpacker.Artifact, error)
|
||||
VersionStatusSummary()
|
||||
Metadata() Metadata
|
||||
// FetchEnforcedBlocks fetches enforced provisioner blocks from HCP Packer
|
||||
FetchEnforcedBlocks(ctx context.Context) error
|
||||
// InjectEnforcedProvisioners injects enforced provisioners into the builds
|
||||
InjectEnforcedProvisioners(builds []*packer.CoreBuild) hcl.Diagnostics
|
||||
}
|
||||
|
||||
// New instantiates the appropriate registry for the Packer configuration template type.
|
||||
|
|
|
|||
|
|
@ -29,6 +29,15 @@ import (
|
|||
// build is still alive.
|
||||
const HeartbeatPeriod = 2 * time.Minute
|
||||
|
||||
// EnforcedBlock represents an enforced provisioner block from HCP Packer
|
||||
type EnforcedBlock struct {
|
||||
ID string
|
||||
Name string
|
||||
BlockContent string // Raw HCL content containing provisioner blocks
|
||||
VersionID string
|
||||
Version string
|
||||
}
|
||||
|
||||
// Bucket represents a single bucket on the HCP Packer registry.
|
||||
type Bucket struct {
|
||||
Name string
|
||||
|
|
@ -40,6 +49,7 @@ type Bucket struct {
|
|||
SourceExternalIdentifierToParentVersions map[string]ParentVersion
|
||||
RunningBuilds map[string]chan struct{}
|
||||
Version *Version
|
||||
EnforcedBlocks []*EnforcedBlock
|
||||
client *hcpPackerAPI.Client
|
||||
}
|
||||
|
||||
|
|
@ -142,6 +152,115 @@ func (bucket *Bucket) Initialize(
|
|||
return bucket.initializeVersion(ctx, templateType)
|
||||
}
|
||||
|
||||
// FetchEnforcedBlocks retrieves all enforced blocks linked to this bucket from HCP Packer.
|
||||
// These blocks contain provisioner configurations that should be automatically injected
|
||||
// into builds for this bucket.
|
||||
func (bucket *Bucket) FetchEnforcedBlocks(ctx context.Context) error {
|
||||
if bucket.client == nil {
|
||||
return errors.New("bucket client not initialized, call Initialize first")
|
||||
}
|
||||
|
||||
resp, err := bucket.client.GetEnforcedBlocksForBucket(ctx, bucket.Name)
|
||||
if err != nil {
|
||||
// If the API doesn't support enforced blocks yet or returns not found, continue silently
|
||||
log.Printf("[DEBUG] fetching enforced blocks for bucket %q: %v", bucket.Name, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if resp == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
bucket.EnforcedBlocks = make([]*EnforcedBlock, 0, len(resp.EnforcedBlockDetail))
|
||||
for _, detail := range resp.EnforcedBlockDetail {
|
||||
if detail == nil || detail.Version == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
block := &EnforcedBlock{
|
||||
ID: detail.ID,
|
||||
Name: detail.Name,
|
||||
BlockContent: detail.Version.BlockContent,
|
||||
VersionID: detail.Version.ID,
|
||||
Version: detail.Version.Version,
|
||||
}
|
||||
bucket.EnforcedBlocks = append(bucket.EnforcedBlocks, block)
|
||||
}
|
||||
|
||||
log.Printf("[INFO] fetched %d enforced block(s) for bucket %q", len(bucket.EnforcedBlocks), bucket.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// PublishEnforcedBlocks publishes the given provisioner block content as an enforced block
|
||||
// on HCP Packer, linked to this bucket. If an enforced block with the given name already
|
||||
// exists and the content has changed, a new version is created. If it doesn't exist,
|
||||
// a new enforced block is created.
|
||||
func (bucket *Bucket) PublishEnforcedBlocks(
|
||||
ctx context.Context,
|
||||
blockName string,
|
||||
blockContent string,
|
||||
templateType hcpPackerModels.HashicorpCloudPacker20230101TemplateType,
|
||||
) error {
|
||||
if bucket.client == nil {
|
||||
return errors.New("bucket client not initialized, call Initialize first")
|
||||
}
|
||||
|
||||
if blockContent == "" {
|
||||
log.Printf("[DEBUG] no provisioner content to publish as enforced blocks for bucket %q", bucket.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// List existing enforced blocks to check for duplicates
|
||||
existingResp, err := bucket.client.ListEnforcedBlocks(ctx)
|
||||
if err != nil {
|
||||
log.Printf("[WARN] failed to list existing enforced blocks: %v", err)
|
||||
// Continue anyway — create will fail if there's a conflict
|
||||
}
|
||||
|
||||
// Build a map of existing enforced blocks by name for quick lookup
|
||||
existingByName := make(map[string]*hcpPackerModels.HashicorpCloudPacker20230101EnforcedBlock)
|
||||
if existingResp != nil {
|
||||
for _, eb := range existingResp.EnforcedBlocks {
|
||||
if eb != nil && eb.Name != "" {
|
||||
existingByName[eb.Name] = eb
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
version := "1"
|
||||
|
||||
existing, found := existingByName[blockName]
|
||||
if found {
|
||||
// Enforced block already exists — check if content changed
|
||||
if existing.LatestVersion != nil && existing.LatestVersion.BlockContent == blockContent {
|
||||
log.Printf("[INFO] enforced block %q already up-to-date, skipping", blockName)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Content changed — create a new version
|
||||
log.Printf("[INFO] updating enforced block %q with new version", blockName)
|
||||
_, err := bucket.client.CreateEnforcedBlockVersion(
|
||||
ctx, existing.ID, blockContent, version, templateType, "",
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create new version for enforced block %q: %w", blockName, err)
|
||||
}
|
||||
log.Printf("[INFO] created new version for enforced block %q", blockName)
|
||||
} else {
|
||||
// Create new enforced block
|
||||
log.Printf("[INFO] creating enforced block %q for bucket %q", blockName, bucket.Name)
|
||||
_, err := bucket.client.CreateEnforcedBlock(
|
||||
ctx, blockName, blockContent, version, templateType, "", nil,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create enforced block %q: %w", blockName, err)
|
||||
}
|
||||
log.Printf("[INFO] created enforced block %q", blockName)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bucket *Bucket) RegisterBuildForComponent(sourceName string) {
|
||||
if bucket == nil {
|
||||
return
|
||||
|
|
|
|||
|
|
@ -140,6 +140,43 @@ func (h *ProvisionHook) Run(ctx context.Context, name string, ui packersdk.Ui, c
|
|||
return nil
|
||||
}
|
||||
|
||||
// ProvisionerWrapOptions contains options for wrapping a provisioner with
|
||||
// additional behavior like pausing, timeouts, and retries.
|
||||
type ProvisionerWrapOptions struct {
|
||||
PauseBefore time.Duration
|
||||
Timeout time.Duration
|
||||
MaxRetries int
|
||||
}
|
||||
|
||||
// WrapProvisionerWithOptions wraps a provisioner with additional behavior
|
||||
// based on the provided options.
|
||||
func WrapProvisionerWithOptions(provisioner packersdk.Provisioner, opts ProvisionerWrapOptions) packersdk.Provisioner {
|
||||
wrapped := provisioner
|
||||
|
||||
if opts.PauseBefore != 0 {
|
||||
wrapped = &PausedProvisioner{
|
||||
PauseBefore: opts.PauseBefore,
|
||||
Provisioner: wrapped,
|
||||
}
|
||||
}
|
||||
|
||||
if opts.Timeout != 0 {
|
||||
wrapped = &TimeoutProvisioner{
|
||||
Timeout: opts.Timeout,
|
||||
Provisioner: wrapped,
|
||||
}
|
||||
}
|
||||
|
||||
if opts.MaxRetries != 0 {
|
||||
wrapped = &RetriedProvisioner{
|
||||
MaxRetries: opts.MaxRetries,
|
||||
Provisioner: wrapped,
|
||||
}
|
||||
}
|
||||
|
||||
return wrapped
|
||||
}
|
||||
|
||||
// PausedProvisioner is a Provisioner implementation that pauses before
|
||||
// the provisioner is actually run.
|
||||
type PausedProvisioner struct {
|
||||
|
|
|
|||
56
test.pkr.hcl
Normal file
56
test.pkr.hcl
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
packer {
|
||||
required_plugins {
|
||||
docker = {
|
||||
version = ">= 1.1.0"
|
||||
source = "github.com/hashicorp/docker"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# HCP Packer registry — provisioner blocks below will be
|
||||
# automatically published as enforced blocks to this bucket.
|
||||
hcp_packer_registry {
|
||||
bucket_name = "ubuntu-test"
|
||||
description = "Test Ubuntu image with enforced provisioners"
|
||||
|
||||
bucket_labels = {
|
||||
"team" = "platform"
|
||||
"os" = "ubuntu"
|
||||
"purpose" = "testing"
|
||||
}
|
||||
}
|
||||
|
||||
source "docker" "ubuntu" {
|
||||
image = "ubuntu:22.04"
|
||||
commit = true
|
||||
}
|
||||
|
||||
build {
|
||||
name = "ubuntu-test"
|
||||
|
||||
sources = ["source.docker.ubuntu"]
|
||||
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"apt-get update -y",
|
||||
"apt-get install -y curl wget jq"
|
||||
]
|
||||
}
|
||||
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"echo 'Creating app user...'",
|
||||
"useradd -m -s /bin/bash appuser",
|
||||
"mkdir -p /opt/app",
|
||||
"chown appuser:appuser /opt/app"
|
||||
]
|
||||
}
|
||||
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"echo 'Applying security hardening...'",
|
||||
"echo 'net.ipv4.ip_forward = 0' >> /etc/sysctl.conf",
|
||||
"echo 'Build complete!'"
|
||||
]
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue