-
Notifications
You must be signed in to change notification settings - Fork 145
Expand file tree
/
Copy pathimages.go
More file actions
287 lines (250 loc) · 9.8 KB
/
images.go
File metadata and controls
287 lines (250 loc) · 9.8 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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2016-present Datadog, Inc.
package images
import (
"fmt"
"regexp"
"strings"
"github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1"
"github.com/DataDog/datadog-operator/pkg/utils"
)
const (
// AgentLatestVersion corresponds to the latest stable agent release
AgentLatestVersion = "7.78.1"
// ClusterAgentLatestVersion corresponds to the latest stable cluster-agent release
ClusterAgentLatestVersion = "7.78.1"
// DdotCollectorLatestVersion corresponds to the latest stable ddot-collector release
DdotCollectorLatestVersion = "7.78.1"
// FIPSProxyLatestVersion corresponds to the latest stable fips-proxy release
FIPSProxyLatestVersion = "1.1.23"
// DDOTFIPSMinimumVersion is the minimum version at which ddot-collector publishes a -fips variant.
// Note: the regular agent -fips image predates this; this constant only applies to ddot-collector.
// Add "-0" so that pre-release versions are considered sufficient. https://github.com/Masterminds/semver#working-with-prerelease-versions
DDOTFIPSMinimumVersion = "7.78.0-0"
// CSILatestImageVersion corresponds to the latest stable Datadog CSIDriver release
CSILatestImageVersion = "1.2.2"
// DefaultRegistrarImageVersion corresponds to the default CSI registrar image used
DefaultRegistrarImageVersion = "v2.0.1"
// Datadog container registry
DatadogContainerRegistry = "registry.datadoghq.com"
// GCRContainerRegistry corresponds to the datadoghq GCR registry
GCRContainerRegistry = "gcr.io/datadoghq"
// DockerHubContainerRegistry corresponds to the datadoghq docker.io registry
DockerHubContainerRegistry = "docker.io/datadog"
// PublicECSContainerRegistry corresponds to the datadoghq PublicECSContainerRegistry registry
PublicECSContainerRegistry = "public.ecr.aws/datadog"
// DefaultImageRegistry corresponds to the datadoghq containers registry
DefaultImageRegistry = "gcr.io/datadoghq"
// Default Image Registries
DefaultAzureImageRegistry string = "datadoghq.azurecr.io"
DefaultEuropeImageRegistry string = "eu.gcr.io/datadoghq"
DefaultAsiaImageRegistry string = "asia.gcr.io/datadoghq"
DefaultGovImageRegistry string = "public.ecr.aws/datadog"
// SIG Storage Kubernetes registry
SIGStorageRegistry = "registry.k8s.io/sig-storage"
// JMXTagSuffix tag suffix for agent JMX images
JMXTagSuffix = "-jmx"
// FIPSTagSuffix tag suffix for agent FIPS images
FIPSTagSuffix = "-fips"
// FullTagSuffix tag suffix for full agent images
FullTagSuffix = "-full"
// Default Image names
DefaultAgentImageName string = "agent"
DefaultClusterAgentImageName string = "cluster-agent"
DefaultDdotCollectorImageName string = "ddot-collector"
)
// imageHasTag identifies whether an image string contains a tag suffix
// Ref: https://github.com/distribution/distribution/blob/v2.7.1/reference/reference.go
var imageHasTag = regexp.MustCompile(`.+:[\w][\w.-]{0,127}$`)
// imageNameContainsTag return true if the image name contains a tag
func imageNameContainsTag(name string) bool {
// The image name corresponds to a full image string
return imageHasTag.MatchString(name)
}
// Image represents a container image information
type Image struct {
registry string
name string
tag string
isJMX bool
isFIPS bool
isFull bool
}
// newImage return a new Image instance
// Assumes that tag suffixes have already been trimmed and booleans updated accordingly
func newImage(registry, name, tag string, isJMX, isFIPS, isFull bool) *Image {
return &Image{
registry: registry,
name: name,
tag: tag,
isJMX: isJMX,
isFIPS: isFIPS,
isFull: isFull,
}
}
func (i *Image) WithRegistry(registry string) *Image {
if registry == "" {
return i
}
i.registry = registry
return i
}
func (i *Image) WithTag(tag string) *Image {
if tag == "" {
return i
}
i.tag = tag
return i
}
func (i *Image) WithName(name string) *Image {
if name == "" {
return i
}
i.name = name
return i
}
func (i *Image) WithJMX(isJMX bool) *Image {
i.isJMX = isJMX
return i
}
func (i *Image) WithFIPS(isFIPS bool) *Image {
i.isFIPS = isFIPS
return i
}
func (i *Image) WithFull(isFull bool) *Image {
i.isFull = isFull
return i
}
// FIPSVersionError returns an error if this image requires a FIPS variant that does not exist
// for the configured version. Specifically:
// - agent -fips-full (isFIPS && isFull) is only published from v7.78.0
// - ddot-collector -fips (isFIPS && name == DefaultDdotCollectorImageName) is only published from v7.78.0
//
// Returns nil if no incompatibility is detected.
func (i *Image) FIPSVersionError() error {
if !i.isFIPS {
return nil
}
if (i.name == DefaultAgentImageName && i.isFull) || i.name == DefaultDdotCollectorImageName {
if !utils.IsAboveMinVersion(i.tag, DDOTFIPSMinimumVersion, nil) {
return fmt.Errorf("%s:%s does not have a FIPS variant: agent -fips-full and ddot-collector -fips are only published from v7.78.0", i.name, i.tag)
}
}
return nil
}
// GetLatestAgentImage returns the latest stable agent release version
func GetLatestAgentImage() string {
image := newImage(DefaultImageRegistry, DefaultAgentImageName, AgentLatestVersion, false, false, false)
return image.ToString()
}
// GetLatestDdotCollectorImage returns the latest ddot collector image
func GetLatestDdotCollectorImage() string {
image := newImage(DefaultImageRegistry, DefaultDdotCollectorImageName, DdotCollectorLatestVersion, false, false, false)
return image.ToString()
}
// GetLatestClusterAgentImage returns the latest stable agent release version
func GetLatestClusterAgentImage() string {
image := newImage(DefaultImageRegistry, DefaultClusterAgentImageName, ClusterAgentLatestVersion, false, false, false)
return image.ToString()
}
// AssembleImage builds the image string based on ImageConfig and the registry configuration.
func AssembleImage(imageSpec *v2alpha1.AgentImageConfig, registry string) string {
if imageNameContainsTag(imageSpec.Name) {
return imageSpec.Name
}
if registry == "" {
registry = DefaultImageRegistry
}
tag := imageSpec.Tag
// If JMXEnabled, then proactively trim JMX suffix to prevent duplicate suffixes
if imageSpec.JMXEnabled {
tag = strings.TrimSuffix(imageSpec.Tag, JMXTagSuffix)
}
img := newImage(registry, imageSpec.Name, tag, imageSpec.JMXEnabled, false, false)
return img.ToString()
}
// OverrideAgentImage takes an existing image reference and potentially overrides portions of it based on the provided image configuration
func OverrideAgentImage(currentImage string, overrideImageSpec *v2alpha1.AgentImageConfig) string {
image := FromString(currentImage)
overrideImage := fromImageConfig(overrideImageSpec)
image.WithRegistry(overrideImage.registry).
WithName(overrideImage.name).
WithTag(overrideImage.tag).
WithJMX(overrideImage.isJMX)
// If an override tag (whether from the tag or name) is provided, then the FIPS and full suffixes present in this tag
// should take precedence over the current image suffixes. If it's not provided, then preserve the original
if overrideImage.tag != "" {
image.WithFIPS(overrideImage.isFIPS).
WithFull(overrideImage.isFull)
}
return image.ToString()
}
// String return the string representation of an image
func (i *Image) ToString() string {
suffix := ""
// FIPS is a global setting, JMX is an override setting and Full is a feature setting.
// Order of priority is JMX -> FIPS -> Full
if i.isJMX {
if i.isFIPS && i.isFull {
// JMX + FIPS + Full: Full image includes JMX, so use -fips-full
suffix = FIPSTagSuffix + FullTagSuffix
} else if i.isFIPS {
suffix = FIPSTagSuffix + JMXTagSuffix
} else if i.isFull {
// Since JMX is compatible with the Full image, iff isJMX and isFull are true then use the Full suffix
suffix = FullTagSuffix
} else {
suffix = JMXTagSuffix
}
} else if i.isFIPS && i.isFull {
suffix = FIPSTagSuffix + FullTagSuffix
} else if i.isFIPS {
suffix = FIPSTagSuffix
} else if i.isFull {
suffix = FullTagSuffix
}
return fmt.Sprintf("%s/%s:%s%s", i.registry, i.name, i.tag, suffix)
}
// parseTagSuffixes extracts FIPS, JMX, and Full suffix flags from a tag string.
// Suffixes are parsed right to left: Full -> JMX -> FIPS, matching the order they appear in the tag.
func parseTagSuffixes(tag string) (baseTag string, isJMX, isFIPS, isFull bool) {
isFull = strings.HasSuffix(tag, FullTagSuffix)
if isFull {
tag = strings.TrimSuffix(tag, FullTagSuffix)
}
isJMX = strings.HasSuffix(tag, JMXTagSuffix)
if isJMX {
tag = strings.TrimSuffix(tag, JMXTagSuffix)
}
isFIPS = strings.HasSuffix(tag, FIPSTagSuffix)
if isFIPS {
tag = strings.TrimSuffix(tag, FIPSTagSuffix)
}
return tag, isJMX, isFIPS, isFull
}
// FromString translates a string Image in the format registry/name:tag to an Image object
func FromString(stringImage string) *Image {
splitImg := strings.Split(stringImage, "/")
registry := strings.Join(splitImg[:len(splitImg)-1], "/")
splitName := strings.Split(splitImg[len(splitImg)-1], ":")
name := splitName[0]
tag, isJMX, isFIPS, isFull := parseTagSuffixes(splitName[1])
return newImage(registry, name, tag, isJMX, isFIPS, isFull)
}
// fromImageConfig creates an Image instance from the AgentImageConfig spec object
// We accept the imageConfig.name in the following formats:
// - name
// - name:tag
// - registry/name:tag
// (Notably, we do not accept "registry/name".)
// Note that if the name includes a tag, then we ignore imageConfig.tag and imageConfig.JMXEnabled
func fromImageConfig(imageConfig *v2alpha1.AgentImageConfig) *Image {
if strings.Contains(imageConfig.Name, ":") {
return FromString(imageConfig.Name)
}
imageTag, isJMX, isFIPS, isFull := parseTagSuffixes(imageConfig.Tag)
isJMX = isJMX || imageConfig.JMXEnabled
return newImage("", imageConfig.Name, imageTag, isJMX, isFIPS, isFull)
}