-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathpackage.go
More file actions
159 lines (144 loc) · 5.6 KB
/
Copy pathpackage.go
File metadata and controls
159 lines (144 loc) · 5.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package agent
import (
"fmt"
"os"
"path"
"regexp"
"strings"
"github.com/DataDog/test-infra-definitions/components/datadog/agentparams"
tifos "github.com/DataDog/test-infra-definitions/components/os"
)
// GetPackagePath retrieve the name of the package that should be installed.
// It will return the path to the package that should be installed for the given flavor and agent flavor.
// If the package is not found, it will return an error.
// If multiple packages are found, it will fail.
// Args:
// - localPath: either a path to a folder or a path to a file
// if a folder is provided, it should have a structure similar to what the agent CI exposes.
// pkg/
// | -- datadog-agent-<version>-<arch><fips?>.rpm
// | -- datadog-agent-<version>-<arch><fips?>.deb
// | -- suse/
// | | -- datadog-agent-<version>-<arch><fips?>.rpm
// - flavor: the flavor of the host
// - agentFlavor: the flavor of the agent
// - arch: the architecture of the host
// - pipelineID: the ID of the pipeline, if empty will be ignored, mainly used to avoid an issue with the Windows Runners, can be removed once CIEXE-143 is fixed
//
// Returns:
// - the path to the package that should be installed
// - an error if the package is not found or if there are multiple packages
func GetPackagePath(localPath string, flavor tifos.Flavor, agentFlavor string, arch tifos.Architecture, pipelineID string) (string, error) {
var wantedExt string
var subFolder string
switch flavor {
case tifos.AmazonLinux, tifos.CentOS, tifos.RedHat, tifos.AmazonLinuxECS, tifos.Fedora, tifos.RockyLinux:
wantedExt = ".rpm"
case tifos.Suse:
wantedExt = ".rpm"
subFolder = "suse"
case tifos.Debian, tifos.Ubuntu:
wantedExt = ".deb"
case tifos.WindowsServer:
wantedExt = ".msi"
case tifos.MacosOS, tifos.Unknown:
fallthrough
default:
return "", fmt.Errorf("unsupported flavor for local packages installation: %s", flavor)
}
pathInfo, err := os.Stat(localPath)
if err != nil {
return "", err
}
packagePath := localPath
matches := []string{}
if pathInfo.IsDir() {
packagePath = path.Join(packagePath, subFolder)
packagePath = path.Join(packagePath, "pkg")
if flavor == tifos.WindowsServer {
packagePath = path.Join(packagePath, "pipeline-"+pipelineID)
}
entries, err := os.ReadDir(packagePath)
if err != nil {
return "", err
}
// First match all packages with the correct extension
allPackagesPattern := `.*\.` + strings.TrimPrefix(wantedExt, ".") + `$`
fipsPattern := `.*fips.*\.` + strings.TrimPrefix(wantedExt, ".") + `$`
for _, entry := range entries {
if entry.IsDir() {
continue
}
// Exclude -dbg_ packages
if strings.Contains(entry.Name(), "-dbg_") || strings.Contains(entry.Name(), "-dbg-") {
continue
}
// Exclude datadog-agent-upgrade-test package on Windows
if flavor == tifos.WindowsServer && strings.Contains(entry.Name(), "upgrade-test") {
continue
}
// Skip architecture check for Windows packages
if flavor != tifos.WindowsServer {
archStr := string(arch)
if arch == tifos.AMD64Arch {
if !strings.Contains(entry.Name(), "x86_64") && !strings.Contains(entry.Name(), "amd64") {
continue
}
} else if !strings.Contains(entry.Name(), archStr) {
continue
}
}
// If we're on Windows, we need to check if the pipeline ID is in the package name, this is a workaround to avoid an issue with the Windows Runners
// where other pipelines packages can pollute the artifacts
if flavor == tifos.WindowsServer && pipelineID != "" {
// If the package name contains "pipeline." and the pipeline ID is not in the name, skip it
if strings.Contains(entry.Name(), "pipeline.") && !strings.Contains(entry.Name(), pipelineID) {
continue
}
}
// Arm64 is not supported for Windows
if flavor == tifos.WindowsServer && arch == tifos.ARM64Arch {
panic("arm64 is not supported for Windows")
}
// It would have been easier to use ^(?!.*fips).*\.deb$ with lookahead to match non-FIPS packages, but it is not supported by Go regex.
// Instead we get all the packages and filter out the FIPS ones if we're looking for non-FIPS packages.
if matched, _ := regexp.MatchString(allPackagesPattern, entry.Name()); matched {
// If we're looking for FIPS packages, only include those
if agentFlavor == agentparams.FIPSFlavor {
if matched, _ := regexp.MatchString(fipsPattern, entry.Name()); matched {
matches = append(matches, entry.Name())
}
} else {
// If we're looking for non-FIPS packages, exclude FIPS ones
if matched, _ := regexp.MatchString(fipsPattern, entry.Name()); !matched {
matches = append(matches, entry.Name())
}
}
}
}
if len(matches) == 0 {
if agentFlavor == agentparams.FIPSFlavor {
return "", fmt.Errorf("no FIPS package found in %s matching pattern %s", localPath, fipsPattern)
}
archInfo := ""
if flavor != tifos.WindowsServer {
if arch == tifos.AMD64Arch {
archInfo = " with architecture x86_64 or amd64"
} else {
archInfo = fmt.Sprintf(" with architecture %s", arch)
}
}
return "", fmt.Errorf("no package found in %s matching pattern %s without matching FIPS pattern %s%s", localPath, allPackagesPattern, fipsPattern, archInfo)
}
if len(matches) > 1 {
return "", fmt.Errorf("found multiple packages to install:\n%s", strings.Join(matches, "\n"))
}
packagePath = path.Join(packagePath, matches[0])
} else {
if strings.HasSuffix(localPath, wantedExt) {
return localPath, nil
}
return "", fmt.Errorf("local package %s does not have the expected extension %s", localPath, wantedExt)
}
return packagePath, nil
}