Skip to content

Commit 1671eb5

Browse files
mergify[bot]pchila
authored andcommitted
(backport #7690) Fips packaging (#7790)
* Make components in packages configurable (#7602) * Redefine ExpectedBinaries as YAML config * Move ExpectedBinaries closer to package spec file * Fix error formatting in downloadDRAArtifacts * add packageName template to ExpectedPackages * use a relaxed dependencies version for IAR releases * Remove FIPS hack introduced in PR #7486 * Allow for a looser match on relaxing dependencies versions * Add debug logging when packaging with EXTERNAL=true * move package tests to dedicated package * Fips packaging (#7690) * Add component list to specs * extract component dependencies from the packages to be built * Refactor component extraction from package specs * Fix package tests error handling * Inject dependencies and remove references to ExpectedBinaries * Remove ExpectedBinaries global * Add rootdir to components * Extract actual version matched on the package file and use it to render RootDir * Package elastic-agent FIPS specs when FIPS=true is specified * refactor ResolveManifestPackage * Move FIPS compile settings in packages.yml * Add more FIPS components * Properly handle dependenciesVersion when calling mage package * Refactor ChecksumsWithoutManifest to use list of dependencies instead of globbing files * Rework useDRAAgentBinaryForPackage for repackaging agent Define elastic-agent-core components (both FIPS and non-FIPS variants) and define package name and root dir templates. Implement some filtering on component list to extract the correct component definition according to the FIPSBuild flag. Refactor code that downloads pre-compiled elastic-agent binaries and places them in the golangCrossBuild directory to make use of the new component definition. * Write spec FIPS flag into manifest.yaml when packaging * Add FIPS elastic agent basic and cloud docker images * Build FIPS docker images in CI packaging * Fix FIPS .tar.gz package tests * Restructure package tests * Extend FIPS check to all binaries in components directory * Create FIPS elastic-agent-core artifacts in elastic-agent-binary-dra pipeline * Cleanup ChecksumsWithManifest and improve godoc * Improve godoc for BinarySpec * Correctly inject dependency list when packaging using DROP_PATH (#7795) * Restore qualifier=core for elastic-agent-core packaging specs (#7805) Restore qualifier for elastic-agent-core packaging specs to avoid changing the rootDir name of the archives. The qualifier had been removed in PR #7690 trying to use the spec name: this worked to get the desired file name but changed the root Dir name which uses '{{.BeatName}}{{if .Qualifier}}-{{.Qualifier}}{{end}}' in the template definition instead of '{{.Name}}' which would render the spec name. * Modify fips core spec qualifier and name (#7818) * Reintroduce cloud-defend component * Filter components by package-type --------- Co-authored-by: Paolo Chilà <[email protected]> # Conflicts: # .buildkite/integration.pipeline.yml # dev-tools/mage/checksums.go # dev-tools/mage/dockerbuilder.go # dev-tools/mage/manifest/manifest.go # dev-tools/mage/pkgtypes.go # dev-tools/mage/settings.go # dev-tools/packaging/packages.yml # dev-tools/packaging/testing/package_test.go # testing/integration/ess/upgrade_standalone_same_commit_test.go
1 parent 38738d2 commit 1671eb5

File tree

15 files changed

+1352
-1093
lines changed

15 files changed

+1352
-1093
lines changed

dev-tools/mage/build.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import (
1818
"github.com/magefile/mage/sh"
1919
"golang.org/x/text/cases"
2020
"golang.org/x/text/language"
21+
22+
"github.com/elastic/elastic-agent/dev-tools/packaging"
2123
)
2224

2325
// BuildArgs are the arguments used for the "build" target and they define how
@@ -73,6 +75,7 @@ func DefaultBuildArgs() BuildArgs {
7375
args := BuildArgs{
7476
Name: BeatName,
7577
CGO: build.Default.CgoEnabled,
78+
Env: map[string]string{},
7679
Vars: map[string]string{
7780
elasticAgentModulePath + "/version.buildTime": "{{ date }}",
7881
elasticAgentModulePath + "/version.commit": "{{ commit }}",
@@ -88,8 +91,16 @@ func DefaultBuildArgs() BuildArgs {
8891
}
8992

9093
if FIPSBuild {
91-
args.ExtraFlags = append(args.ExtraFlags, "-tags=requirefips")
92-
args.CGO = true
94+
95+
fipsConfig := packaging.Settings().FIPS
96+
97+
for _, tag := range fipsConfig.Compile.Tags {
98+
args.ExtraFlags = append(args.ExtraFlags, "-tags="+tag)
99+
}
100+
args.CGO = args.CGO || fipsConfig.Compile.CGO
101+
for varName, value := range fipsConfig.Compile.Env {
102+
args.Env[varName] = value
103+
}
93104
}
94105

95106
if DevBuild {
@@ -191,11 +202,6 @@ func Build(params BuildArgs) error {
191202
cgoEnabled = "1"
192203
}
193204

194-
if FIPSBuild {
195-
cgoEnabled = "1"
196-
env["GOEXPERIMENT"] = "systemcrypto"
197-
}
198-
199205
env["CGO_ENABLED"] = cgoEnabled
200206

201207
// Spec

dev-tools/mage/checksums.go

Lines changed: 106 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ import (
99
"log"
1010
"os"
1111
"path/filepath"
12-
"strings"
1312

1413
"github.com/magefile/mage/mg"
1514
"github.com/otiai10/copy"
1615

1716
"github.com/elastic/elastic-agent/dev-tools/mage/manifest"
17+
"github.com/elastic/elastic-agent/dev-tools/packaging"
1818
)
1919

2020
const ComponentSpecFileSuffix = ".spec.yml"
@@ -40,206 +40,153 @@ func CopyComponentSpecs(componentName, versionedDropPath string) (string, error)
4040
return GetSHA512Hash(targetPath)
4141
}
4242

43-
// This is a helper function for flattenDependencies that's used when not packaging from a manifest
44-
func ChecksumsWithoutManifest(versionedFlatPath string, versionedDropPath string, packageVersion string) map[string]string {
45-
globExpr := filepath.Join(versionedFlatPath, fmt.Sprintf("*%s*", packageVersion))
46-
if mg.Verbose() {
47-
log.Printf("Finding files to copy with %s", globExpr)
48-
}
49-
files, err := filepath.Glob(globExpr)
50-
if err != nil {
51-
panic(err)
52-
}
53-
if mg.Verbose() {
54-
log.Printf("Validating checksums for %+v", files)
55-
log.Printf("--- Copying into %s: %v", versionedDropPath, files)
56-
}
57-
43+
// ChecksumsWithoutManifest is a helper function for flattenDependencies that's used when not packaging from a manifest.
44+
// This function will iterate over the dependencies, resolve *exactly* the package name for each dependency and platform using the passed
45+
// dependenciesVersion, and it will copy the extracted files contained in the rootDir of each dependency from the versionedFlatPath
46+
// (a directory containing all the extracted dependencies per platform) to the versionedDropPath (a drop path by platform
47+
// that will be used to compose the package content)
48+
// ChecksumsWithoutManifest will accumulate the checksums of each component spec that is copied, and return it to the caller.
49+
func ChecksumsWithoutManifest(platform string, dependenciesVersion string, versionedFlatPath string, versionedDropPath string, dependencies []packaging.BinarySpec) map[string]string {
5850
checksums := make(map[string]string)
59-
for _, f := range files {
51+
52+
for _, dep := range dependencies {
53+
54+
if dep.PythonWheel {
55+
if mg.Verbose() {
56+
log.Printf(">>>>>>> Component %s/%s is a Python wheel, skipping", dep.ProjectName, dep.BinaryName)
57+
}
58+
continue
59+
}
60+
61+
if !dep.SupportsPlatform(platform) {
62+
if mg.Verbose() {
63+
log.Printf(">>>>>>> Component %s/%s does not support platform %s, skipping", dep.ProjectName, dep.BinaryName, platform)
64+
}
65+
continue
66+
}
67+
68+
atLeastOnePackageTypeSelected := false
69+
for _, pkgType := range dep.PackageTypes {
70+
if IsPackageTypeSelected(PackageType(pkgType)) {
71+
atLeastOnePackageTypeSelected = true
72+
break
73+
}
74+
}
75+
76+
if !atLeastOnePackageTypeSelected {
77+
if mg.Verbose() {
78+
log.Printf(">>>>>>> Component %s/%s supported package types %v do not overlap selected package types %v, skipping", dep.ProjectName, dep.BinaryName, dep.PackageTypes, SelectedPackageTypes)
79+
}
80+
continue
81+
}
82+
83+
srcDir := filepath.Join(versionedFlatPath, dep.GetRootDir(dependenciesVersion, platform))
84+
85+
if mg.Verbose() {
86+
log.Printf("Validating checksums for %+v", dep.BinaryName)
87+
log.Printf("--- Copying into %s: %v", versionedDropPath, srcDir)
88+
}
89+
6090
options := copy.Options{
6191
OnSymlink: func(_ string) copy.SymlinkAction {
6292
return copy.Shallow
6393
},
6494
Sync: true,
6595
}
6696
if mg.Verbose() {
67-
log.Printf("> prepare to copy %s into %s ", f, versionedDropPath)
97+
log.Printf("> prepare to copy %s into %s ", srcDir, versionedDropPath)
6898
}
6999

70-
err = copy.Copy(f, versionedDropPath, options)
100+
err := copy.Copy(srcDir, versionedDropPath, options)
71101
if err != nil {
72-
panic(err)
102+
panic(fmt.Errorf("copying dependency %s files from %q to %q: %w", dep.BinaryName, srcDir, versionedDropPath, err))
73103
}
74104

75105
// copy spec file for match
76-
specName := filepath.Base(f)
77-
idx := strings.Index(specName, "-"+packageVersion)
78-
if idx != -1 {
79-
specName = specName[:idx]
80-
}
81106
if mg.Verbose() {
82-
log.Printf(">>>> Looking to copy spec file: [%s]", specName)
107+
log.Printf(">>>> Looking to copy spec file: [%s]", dep.BinaryName)
83108
}
84109

85-
checksum, err := CopyComponentSpecs(specName, versionedDropPath)
110+
checksum, err := CopyComponentSpecs(dep.BinaryName, versionedDropPath)
86111
if err != nil {
87112
panic(err)
88113
}
89114

90-
checksums[specName+ComponentSpecFileSuffix] = checksum
115+
checksums[dep.BinaryName+ComponentSpecFileSuffix] = checksum
91116
}
92117

93118
return checksums
94119
}
95120

96-
// This is a helper function for flattenDependencies that's used when building from a manifest
97-
func ChecksumsWithManifest(requiredPackage string, versionedFlatPath string, versionedDropPath string, manifestResponse *manifest.Build) map[string]string {
121+
// ChecksumsWithManifest is a helper function for flattenDependencies that's used when building from a manifest.
122+
// This function will iterate over the dependencies, resolve the package name for each dependency and platform using the manifest,
123+
// (there may be some variability there in case the manifest does not include an exact match for the expected filename),
124+
// and it will copy the extracted files contained in the rootDir of each dependency from the versionedFlatPath
125+
// (a directory containing all the extracted dependencies per platform) to the versionedDropPath (a drop path by platform
126+
// that will be used to compose the package content)
127+
// ChecksumsWithManifest will accumulate the checksums of each component spec that is copied, and return it to the caller.
128+
func ChecksumsWithManifest(platform string, dependenciesVersion string, versionedFlatPath string, versionedDropPath string, manifestResponse *manifest.Build, dependencies []packaging.BinarySpec) map[string]string {
98129
checksums := make(map[string]string)
99130
if manifestResponse == nil {
100131
return checksums
101132
}
102133

103-
// Iterate over the component projects in the manifest
104-
projects := manifestResponse.Projects
105-
for componentName := range projects {
106-
// Iterate over the individual package files within each component project
107-
for pkgName := range projects[componentName].Packages {
108-
// Only care about packages that match the required package constraint (os/arch)
109-
if strings.Contains(pkgName, requiredPackage) {
110-
// Iterate over the external binaries that we care about for packaging agent
111-
for _, spec := range manifest.ExpectedBinaries {
112-
// If the individual package doesn't match the expected prefix, then continue
113-
if !strings.HasPrefix(pkgName, spec.BinaryName) {
114-
continue
115-
}
116-
117-
if mg.Verbose() {
118-
log.Printf(">>>>>>> Package [%s] matches requiredPackage [%s]", pkgName, requiredPackage)
119-
}
120-
121-
// Get the version from the component based on the version in the package name
122-
// This is useful in the case where it's an Independent Agent Release, where
123-
// the opted-in projects will be one patch version ahead of the rest of the
124-
// opted-out/previously-released projects
125-
componentVersion := getComponentVersion(componentName, requiredPackage, projects[componentName])
126-
if mg.Verbose() {
127-
log.Printf(">>>>>>> Component [%s]/[%s] version is [%s]", componentName, requiredPackage, componentVersion)
128-
}
129-
130-
// Combine the package name w/ the versioned flat path
131-
fullPath := filepath.Join(versionedFlatPath, pkgName)
132-
133-
// Eliminate the file extensions to get the proper directory
134-
// name that we need to copy
135-
var dirToCopy string
136-
if strings.HasSuffix(fullPath, ".tar.gz") {
137-
dirToCopy = fullPath[:strings.LastIndex(fullPath, ".tar.gz")]
138-
} else if strings.HasSuffix(fullPath, ".zip") {
139-
dirToCopy = fullPath[:strings.LastIndex(fullPath, ".zip")]
140-
} else {
141-
dirToCopy = fullPath
142-
}
143-
if mg.Verbose() {
144-
log.Printf(">>>>>>> Calculated directory to copy: [%s]", dirToCopy)
145-
}
146-
147-
// Set copy options
148-
options := copy.Options{
149-
OnSymlink: func(_ string) copy.SymlinkAction {
150-
return copy.Shallow
151-
},
152-
Sync: true,
153-
}
154-
if mg.Verbose() {
155-
log.Printf("> prepare to copy %s into %s ", dirToCopy, versionedDropPath)
156-
}
157-
158-
// Do the copy
159-
err := copy.Copy(dirToCopy, versionedDropPath, options)
160-
if err != nil {
161-
panic(err)
162-
}
163-
164-
// copy spec file for match
165-
specName := filepath.Base(dirToCopy)
166-
idx := strings.Index(specName, "-"+componentVersion)
167-
if idx != -1 {
168-
specName = specName[:idx]
169-
}
170-
if mg.Verbose() {
171-
log.Printf(">>>> Looking to copy spec file: [%s]", specName)
172-
}
173-
174-
checksum, err := CopyComponentSpecs(specName, versionedDropPath)
175-
if err != nil {
176-
panic(err)
177-
}
178-
179-
checksums[specName+ComponentSpecFileSuffix] = checksum
180-
}
134+
// Iterate over the external binaries that we care about for packaging agent
135+
for _, spec := range dependencies {
136+
137+
if spec.PythonWheel {
138+
if mg.Verbose() {
139+
log.Printf(">>>>>>> Component %s/%s is a Python wheel, skipping", spec.ProjectName, spec.BinaryName)
181140
}
141+
continue
182142
}
183-
}
184143

185-
return checksums
186-
}
144+
if !spec.SupportsPlatform(platform) {
145+
log.Printf(">>>>>>> Component %s/%s does not support platform %s, skipping", spec.ProjectName, spec.BinaryName, platform)
146+
continue
147+
}
187148

188-
// This function is used when building with a Manifest. In that manifest, it's possible
189-
// for projects in an Independent Agent Release to have different versions since the opted-in
190-
// ones will be one patch version higher than the opted-out/previously released projects.
191-
// This function tries to find the versions from the package name
192-
func getComponentVersion(componentName string, requiredPackage string, componentProject manifest.Project) string {
193-
var componentVersion string
194-
var foundIt bool
195-
// Iterate over all the packages in the component project
196-
for pkgName := range componentProject.Packages {
197-
// Only care about the external binaries that we want to package
198-
for _, spec := range manifest.ExpectedBinaries {
199-
// If the given component name doesn't match the external binary component, skip
200-
if componentName != spec.ProjectName {
201-
continue
149+
manifestPackage, err := manifest.ResolveManifestPackage(manifestResponse.Projects[spec.ProjectName], spec, dependenciesVersion, platform)
150+
if err != nil {
151+
if mg.Verbose() {
152+
log.Printf(">>>>>>> Error resolving package for [%s/%s]", spec.BinaryName, platform)
202153
}
154+
continue
155+
}
203156

204-
// Split the package name on the binary name prefix plus a dash
205-
firstSplit := strings.Split(pkgName, spec.BinaryName+"-")
206-
if len(firstSplit) < 2 {
207-
continue
208-
}
157+
rootDir := spec.GetRootDir(manifestPackage.ActualVersion, platform)
209158

210-
// Get the second part of the first split
211-
secondHalf := firstSplit[1]
212-
if len(secondHalf) < 2 {
213-
continue
214-
}
159+
// Combine the package name w/ the versioned flat path
160+
fullPath := filepath.Join(versionedFlatPath, rootDir)
215161

216-
// Make sure the second half matches the required package
217-
if strings.Contains(secondHalf, requiredPackage) {
218-
// ignore packages with names where this splitting doesn't results in proper version
219-
if strings.Contains(secondHalf, "docker-image") {
220-
continue
221-
}
222-
if strings.Contains(secondHalf, "oss-") {
223-
continue
224-
}
225-
226-
// The component version should be the first entry after splitting w/ the requiredPackage
227-
componentVersion = strings.Split(secondHalf, "-"+requiredPackage)[0]
228-
foundIt = true
229-
// break out of inner loop
230-
break
231-
}
162+
if mg.Verbose() {
163+
log.Printf(">>>>>>> Calculated directory to copy: [%s]", fullPath)
232164
}
233-
if foundIt {
234-
// break out of outer loop
235-
break
165+
166+
// Set copy options
167+
options := copy.Options{
168+
OnSymlink: func(_ string) copy.SymlinkAction {
169+
return copy.Shallow
170+
},
171+
Sync: true,
172+
}
173+
if mg.Verbose() {
174+
log.Printf("> prepare to copy %s into %s ", fullPath, versionedDropPath)
236175
}
237-
}
238176

239-
if componentVersion == "" {
240-
errMsg := fmt.Sprintf("Unable to determine component version for [%s]", componentName)
241-
panic(errMsg)
177+
// Do the copy
178+
err = copy.Copy(fullPath, versionedDropPath, options)
179+
if err != nil {
180+
panic(err)
181+
}
182+
183+
checksum, err := CopyComponentSpecs(spec.BinaryName, versionedDropPath)
184+
if err != nil {
185+
panic(err)
186+
}
187+
188+
checksums[spec.BinaryName+ComponentSpecFileSuffix] = checksum
242189
}
243190

244-
return componentVersion
191+
return checksums
245192
}

dev-tools/mage/crossbuild.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@ const defaultCrossBuildTarget = "golangCrossBuild"
3030
var Platforms = BuildPlatforms.Defaults()
3131

3232
// SelectedPackageTypes is the list of package types. If empty, all packages types
33-
// are considered to be selected (see isPackageTypeSelected).
33+
// are considered to be selected (see IsPackageTypeSelected).
3434
var SelectedPackageTypes []PackageType
3535

3636
// SelectedDockerVariants is the list of docker variants. If empty, all docker variants
37-
// are considered to be selected (see isDockerVariantSelected).
37+
// are considered to be selected (see IsDockerVariantSelected).
3838
var SelectedDockerVariants []DockerVariant
3939

4040
func init() {

0 commit comments

Comments
 (0)