Skip to content

Commit 8aeabe9

Browse files
committedMar 5, 2020
Match bundle image directory structure
This commit introduces a change to the way that the way the API function bundle.GenerateFunc manages directory structure. Currently, the output of that function creates a metadata folder with generated annotations inside the given manifest directory. However, this is not how bundle images are actually formatted, and the Dockerfile does some indirection in order to copy the files into the correct directory. However, we should consider the default behvaior of `generate` to be "run once" (especially given that by default the regeneration does not happen in the build function by default). The expectation is that generate is a scaffolding method. Given that, we should scaffold the metadata directory in the same manner as it would actually appear in the union filesystem on the resulting container image. In order to accomplish this, this PR makes a few functional changes: - By default, create the metadata directory in the same parent directory as the given manifest directory. This, at a high level, mirrors the directory tree that will exist on the resulting bundle. - Generates the dockerfile in the current working directory that the function is called from. Modifies the dockerfile to point to the relative path of the generated files - Adds an option output directory parameter to the function (as well as the shadowed `opm alpha bundle build/generate` commands) to allow the user to generate a *new* bundle directory.
1 parent 4357be1 commit 8aeabe9

17 files changed

+12038
-51
lines changed
 

‎cmd/opm/alpha/bundle/build.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ var (
1313
packageNameArgs string
1414
channelsArgs string
1515
channelDefaultArgs string
16+
outputDirArgs string
1617
overwriteArgs bool
1718
)
1819

@@ -69,11 +70,13 @@ func newBundleBuildCmd() *cobra.Command {
6970

7071
bundleBuildCmd.Flags().BoolVarP(&overwriteArgs, "overwrite", "o", false, "To overwrite annotations.yaml locally if existed. By default, overwrite is set to `false`.")
7172

73+
bundleBuildCmd.Flags().StringVarP(&outputDirArgs, "output-dir", "u", "", "Optional output directory for operator manifests")
74+
7275
return bundleBuildCmd
7376
}
7477

7578
func buildFunc(cmd *cobra.Command, args []string) error {
76-
err := bundle.BuildFunc(dirBuildArgs, tagBuildArgs, imageBuilderArgs,
79+
err := bundle.BuildFunc(dirBuildArgs, outputDirArgs, tagBuildArgs, imageBuilderArgs,
7780
packageNameArgs, channelsArgs, channelDefaultArgs, overwriteArgs)
7881
if err != nil {
7982
return err

‎cmd/opm/alpha/bundle/generate.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,13 @@ func newBundleGenerateCmd() *cobra.Command {
4141

4242
bundleGenerateCmd.Flags().StringVarP(&channelDefaultArgs, "default", "e", "", "The default channel for the bundle image")
4343

44+
bundleGenerateCmd.Flags().StringVarP(&outputDirArgs, "output-dir", "u", "", "Optional output directory for operator manifests")
45+
4446
return bundleGenerateCmd
4547
}
4648

4749
func generateFunc(cmd *cobra.Command, args []string) error {
48-
err := bundle.GenerateFunc(dirBuildArgs, packageNameArgs, channelsArgs, channelDefaultArgs, true)
50+
err := bundle.GenerateFunc(dirBuildArgs, outputDirArgs, packageNameArgs, channelsArgs, channelDefaultArgs, true)
4951
if err != nil {
5052
return err
5153
}

‎docs/design/operator-bundle.md

+25-5
Original file line numberDiff line numberDiff line change
@@ -119,13 +119,14 @@ Flags:
119119
-e, --default string The default channel for the bundle image
120120
-d, --directory string The directory where bundle manifests for a specific version are located.
121121
-h, --help help for generate
122+
-u, --output-dir string Optional output directory for operator manifests
122123
-p, --package string The name of the package that bundle image belongs to
123124
124125
Note:
125126
* All manifests yaml must be in the same directory.
126127
```
127128

128-
The `--directory/-d`, `--channels/-c`, `--package/-p` are required flags while `--default/-e` is optional.
129+
The `--directory/-d`, `--channels/-c`, `--package/-p` are required flags while `--default/-e` and `--output-dir/-u` are optional.
129130

130131
The command for `generate` task is:
131132
```bash
@@ -145,17 +146,35 @@ The `--package` or `-p` is the name of package fo the operator such as `etcd` wh
145146

146147
All information in `annotations.yaml` is also existed in `LABEL` section of `Dockerfile`.
147148

148-
After the generate command is executed, the `Dockerfile` is generated in the same directory where the YAML manifests are located while the `annotations.yaml` file is located in a folder named `metadata`. For example:
149+
After the generate command is executed, the `Dockerfile` is generated in the directory where command is run. By default, the `annotations.yaml` file is located in a folder named `metadata` in the same root directory as the input directory containing manifests. For example:
149150
```bash
150151
$ tree test
151152
test
152-
├── etcdcluster.crd.yaml
153-
├── etcdoperator.clusterserviceversion.yaml
153+
├── my-manifests
154+
│ ├── etcdcluster.crd.yaml
155+
│ └── etcdoperator.clusterserviceversion.yaml
154156
├── metadata
155157
│   └── annotations.yaml
156158
└── Dockerfile
157159
```
158160

161+
If the `--output-dir` parameter is specified, that directory becomes the parent for a new pair of folders `manifests/` and `metadata/`, where `manifests/` is a copy of the passed in directory of manifests and `metadata/` is the folder containing annotations.yaml:
162+
163+
```bash
164+
$ tree test
165+
test
166+
├── my-manifests
167+
│ ├── etcdcluster.crd.yaml
168+
│ └── etcdoperator.clusterserviceversion.yaml
169+
├── my-output-manifest-dir
170+
│ ├── manifests
171+
│ │ ├── etcdoperator.clusterserviceversion.yaml
172+
│ │ └── etcdoperator.clusterserviceversion.yaml
173+
│   └── metadata
174+
│ └── annotations.yaml
175+
└── Dockerfile
176+
```
177+
159178
The `Dockerfile` can be used manually to build the bundle image using container image tools such as Docker, Podman or Buildah. For example, the Docker build command would be:
160179

161180
```bash
@@ -175,7 +194,8 @@ Flags:
175194
-d, --directory string The directory where bundle manifests for a specific version are located
176195
-h, --help help for build
177196
-b, --image-builder string Tool to build container images. One of: [docker, podman, buildah] (default "docker")
178-
-0, --overwrite To overwrite annotations.yaml if existing
197+
-u, --output-dir string Optional output directory for operator manifests
198+
-0, --overwrite To overwrite annotations.yaml if existing
179199
-p, --package string The name of the package that bundle image belongs to
180200
-t, --tag string The name of the bundle image will be built
181201

‎pkg/lib/bundle/build.go

+6-9
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,19 @@ import (
44
"fmt"
55
"os"
66
"os/exec"
7-
"path"
87

98
log "github.com/sirupsen/logrus"
109
)
1110

1211
// Create build command to build bundle manifests image
13-
func BuildBundleImage(directory, imageTag, imageBuilder string) (*exec.Cmd, error) {
12+
func BuildBundleImage(imageTag, imageBuilder string) (*exec.Cmd, error) {
1413
var args []string
1514

16-
dockerfilePath := path.Join(directory, DockerFile)
17-
1815
switch imageBuilder {
1916
case "docker", "podman":
20-
args = append(args, "build", "-f", dockerfilePath, "-t", imageTag, directory)
17+
args = append(args, "build", "-f", DockerFile, "-t", imageTag, ".")
2118
case "buildah":
22-
args = append(args, "bud", "--format=docker", "-f", dockerfilePath, "-t", imageTag, directory)
19+
args = append(args, "bud", "--format=docker", "-f", DockerFile, "-t", imageTag, ".")
2320
default:
2421
return nil, fmt.Errorf("%s is not supported image builder", imageBuilder)
2522
}
@@ -53,21 +50,21 @@ func ExecuteCommand(cmd *exec.Cmd) error {
5350
// @channels: The list of channels that bundle image belongs to
5451
// @channelDefault: The default channel for the bundle image
5552
// @overwrite: Boolean flag to enable overwriting annotations.yaml locally if existed
56-
func BuildFunc(directory, imageTag, imageBuilder, packageName, channels, channelDefault string, overwrite bool) error {
53+
func BuildFunc(directory, outputDir, imageTag, imageBuilder, packageName, channels, channelDefault string, overwrite bool) error {
5754
_, err := os.Stat(directory)
5855
if os.IsNotExist(err) {
5956
return err
6057
}
6158

6259
// Generate annotations.yaml and Dockerfile
63-
err = GenerateFunc(directory, packageName, channels, channelDefault, overwrite)
60+
err = GenerateFunc(directory, outputDir, packageName, channels, channelDefault, overwrite)
6461
if err != nil {
6562
return err
6663
}
6764

6865
// Build bundle image
6966
log.Info("Building bundle image")
70-
buildCmd, err := BuildBundleImage(path.Clean(directory), imageTag, imageBuilder)
67+
buildCmd, err := BuildBundleImage(imageTag, imageBuilder)
7168
if err != nil {
7269
return err
7370
}

‎pkg/lib/bundle/build_test.go

+4-9
Original file line numberDiff line numberDiff line change
@@ -12,35 +12,30 @@ func TestBuildBundleImage(t *testing.T) {
1212
defer cleanup()
1313

1414
tests := []struct {
15-
directory string
1615
imageTag string
1716
imageBuilder string
1817
commandStr string
1918
errorMsg string
2019
}{
2120
{
22-
testOperatorDir,
2321
"test",
2422
"docker",
25-
"docker build -f /test-operator/Dockerfile -t test /test-operator",
23+
"docker build -f bundle.Dockerfile -t test .",
2624
"",
2725
},
2826
{
29-
testOperatorDir,
3027
"test",
3128
"buildah",
32-
"buildah bud --format=docker -f /test-operator/Dockerfile -t test /test-operator",
29+
"buildah bud --format=docker -f bundle.Dockerfile -t test .",
3330
"",
3431
},
3532
{
36-
testOperatorDir,
3733
"test",
3834
"podman",
39-
"podman build -f /test-operator/Dockerfile -t test /test-operator",
35+
"podman build -f bundle.Dockerfile -t test .",
4036
"",
4137
},
4238
{
43-
testOperatorDir,
4439
"test",
4540
"hello",
4641
"",
@@ -50,7 +45,7 @@ func TestBuildBundleImage(t *testing.T) {
5045

5146
for _, item := range tests {
5247
var cmd *exec.Cmd
53-
cmd, err := BuildBundleImage(item.directory, item.imageTag, item.imageBuilder)
48+
cmd, err := BuildBundleImage(item.imageTag, item.imageBuilder)
5449
if item.errorMsg == "" {
5550
require.Contains(t, cmd.String(), item.commandStr)
5651
} else {

‎pkg/lib/bundle/generate.go

+156-22
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package bundle
22

33
import (
44
"fmt"
5+
"io"
56
"io/ioutil"
67
"os"
78
"path/filepath"
@@ -19,7 +20,7 @@ const (
1920
PlainType = "plain"
2021
HelmType = "helm"
2122
AnnotationsFile = "annotations.yaml"
22-
DockerFile = "Dockerfile"
23+
DockerFile = "bundle.Dockerfile"
2324
ManifestsDir = "manifests/"
2425
MetadataDir = "metadata/"
2526
ManifestsLabel = "operators.operatorframework.io.bundle.manifests.v1"
@@ -39,12 +40,26 @@ type AnnotationMetadata struct {
3940
// channels information and then writes the file to `/metadata` directory.
4041
// Inputs:
4142
// @directory: The local directory where bundle manifests and metadata are located
43+
// @outputDir: Optional generated path where the /manifests and /metadata directories are copied
44+
// as they would appear on the bundle image
4245
// @packageName: The name of the package that bundle image belongs to
4346
// @channels: The list of channels that bundle image belongs to
4447
// @channelDefault: The default channel for the bundle image
4548
// @overwrite: Boolean flag to enable overwriting annotations.yaml locally if existed
46-
func GenerateFunc(directory, packageName, channels, channelDefault string, overwrite bool) error {
47-
_, err := os.Stat(directory)
49+
func GenerateFunc(directory, outputDir, packageName, channels, channelDefault string, overwrite bool) error {
50+
// clean the input so that we know the absolute paths of input directories
51+
directory, err := filepath.Abs(directory)
52+
if err != nil {
53+
return err
54+
}
55+
if outputDir != "" {
56+
outputDir, err = filepath.Abs(outputDir)
57+
if err != nil {
58+
return err
59+
}
60+
}
61+
62+
_, err = os.Stat(directory)
4863
if os.IsNotExist(err) {
4964
return err
5065
}
@@ -55,6 +70,12 @@ func GenerateFunc(directory, packageName, channels, channelDefault string, overw
5570
return err
5671
}
5772

73+
// Get directory context for file output
74+
workingDir, err := os.Getwd()
75+
if err != nil {
76+
return err
77+
}
78+
5879
log.Info("Building annotations.yaml")
5980

6081
// Generate annotations.yaml
@@ -63,37 +84,83 @@ func GenerateFunc(directory, packageName, channels, channelDefault string, overw
6384
return err
6485
}
6586

66-
file, err := ioutil.ReadFile(filepath.Join(directory, MetadataDir, AnnotationsFile))
67-
if os.IsNotExist(err) || overwrite {
68-
err = WriteFile(AnnotationsFile, filepath.Join(directory, MetadataDir), content)
69-
if err != nil {
70-
return err
71-
}
72-
} else if err != nil {
87+
// Push the output yaml content to the correct directory and conditionally copy the manifest dir
88+
outManifestDir, outMetadataDir, err := CopyYamlOutput(content, directory, outputDir, workingDir, overwrite)
89+
if err != nil {
7390
return err
74-
} else {
75-
log.Info("An annotations.yaml already exists in directory")
76-
if err = ValidateAnnotations(file, content); err != nil {
77-
return err
78-
}
7991
}
8092

8193
log.Info("Building Dockerfile")
8294

8395
// Generate Dockerfile
84-
content, err = GenerateDockerfile(mediaType, ManifestsDir, MetadataDir, packageName, channels, channelDefault)
96+
content, err = GenerateDockerfile(mediaType, ManifestsDir, MetadataDir, outManifestDir, outMetadataDir, workingDir, packageName, channels, channelDefault)
8597
if err != nil {
8698
return err
8799
}
88100

89-
err = WriteFile(DockerFile, directory, content)
90-
if err != nil {
101+
_, err = os.Stat(filepath.Join(workingDir, DockerFile))
102+
if os.IsNotExist(err) || overwrite {
103+
err = WriteFile(DockerFile, workingDir, content)
104+
if err != nil {
105+
return err
106+
}
107+
} else if err != nil {
91108
return err
109+
} else {
110+
log.Info("A bundle.Dockerfile already exists in current working directory")
92111
}
93112

94113
return nil
95114
}
96115

116+
// CopyYamlOutput takes the generated annotations yaml and writes it to disk.
117+
// If an outputDir is specified, it will copy the input manifests
118+
// It returns two strings. resultMetadata is the path to the output metadata/ folder.
119+
// resultManifests is the path to the output manifests/ folder -- if no copy occured,
120+
// it just returns the input manifestDir
121+
func CopyYamlOutput(annotationsContent []byte, manifestDir, outputDir, workingDir string, overwrite bool) (resultManifests, resultMetadata string, err error) {
122+
// First, determine the parent directory of the metadata and manifest directories
123+
copyDir := ""
124+
125+
// If an output directory is not defined defined, generate metadata folder into the same parent dir as existing manifest dir
126+
if outputDir == "" {
127+
copyDir = filepath.Dir(manifestDir)
128+
resultManifests = manifestDir
129+
} else { // otherwise copy the manifests into $outputDir/manifests and create the annotations file in $outputDir/metadata
130+
copyDir = outputDir
131+
132+
log.Info("Generating output manifests directory")
133+
134+
resultManifests = filepath.Join(copyDir, "/manifests/")
135+
// copy the manifest directory into $pwd/manifests/
136+
err := copyManifestDir(manifestDir, resultManifests, overwrite)
137+
if err != nil {
138+
return "", "", err
139+
}
140+
}
141+
142+
// Now, generate the `metadata/` dir and write the annotations
143+
file, err := ioutil.ReadFile(filepath.Join(copyDir, MetadataDir, AnnotationsFile))
144+
if os.IsNotExist(err) || overwrite {
145+
writeDir := filepath.Join(copyDir, MetadataDir)
146+
err = WriteFile(AnnotationsFile, writeDir, annotationsContent)
147+
if err != nil {
148+
return "", "", err
149+
}
150+
} else if err != nil {
151+
return "", "", err
152+
} else {
153+
log.Info("An annotations.yaml already exists in directory")
154+
if err = ValidateAnnotations(file, annotationsContent); err != nil {
155+
return "", "", err
156+
}
157+
}
158+
159+
resultMetadata = filepath.Join(copyDir, "metadata")
160+
161+
return resultManifests, resultMetadata, nil
162+
}
163+
97164
// GetMediaType determines mediatype from files (yaml) in given directory
98165
// Currently able to detect helm chart, registry+v1 (CSV) and plain k8s resources
99166
// such as CRD.
@@ -247,14 +314,24 @@ func GenerateAnnotations(mediaType, manifests, metadata, packageName, channels,
247314
// GenerateDockerfile builds Dockerfile with mediatype, manifests &
248315
// metadata directories in bundle image, package name, channels and default
249316
// channels information in LABEL section.
250-
func GenerateDockerfile(mediaType, manifests, metadata, packageName, channels, channelDefault string) ([]byte, error) {
317+
func GenerateDockerfile(mediaType, manifests, metadata, copyManifestDir, copyMetadataDir, workingDir, packageName, channels, channelDefault string) ([]byte, error) {
251318
var fileContent string
252319

253320
chanDefault, err := ValidateChannelDefault(channels, channelDefault)
254321
if err != nil {
255322
return nil, err
256323
}
257324

325+
relativeManifestDirectory, err := filepath.Rel(workingDir, copyManifestDir)
326+
if err != nil {
327+
return nil, err
328+
}
329+
330+
relativeMetadataDirectory, err := filepath.Rel(workingDir, copyMetadataDir)
331+
if err != nil {
332+
return nil, err
333+
}
334+
258335
// FROM
259336
fileContent += "FROM scratch\n\n"
260337

@@ -267,8 +344,8 @@ func GenerateDockerfile(mediaType, manifests, metadata, packageName, channels, c
267344
fileContent += fmt.Sprintf("LABEL %s=%s\n\n", ChannelDefaultLabel, chanDefault)
268345

269346
// CONTENT
270-
fileContent += fmt.Sprintf("COPY %s %s\n", "/*.yaml", "/manifests/")
271-
fileContent += fmt.Sprintf("COPY %s %s%s\n", filepath.Join("/", metadata, AnnotationsFile), "/metadata/", AnnotationsFile)
347+
fileContent += fmt.Sprintf("COPY %s %s\n", filepath.Join(relativeManifestDirectory, "/*.yaml"), "/manifests/")
348+
fileContent += fmt.Sprintf("COPY %s %s%s\n", filepath.Join(relativeMetadataDirectory, AnnotationsFile), "/metadata/", AnnotationsFile)
272349

273350
return []byte(fileContent), nil
274351
}
@@ -277,7 +354,10 @@ func GenerateDockerfile(mediaType, manifests, metadata, packageName, channels, c
277354
// Note: Will overwrite the existing `fileName` file if it exists
278355
func WriteFile(fileName, directory string, content []byte) error {
279356
if _, err := os.Stat(directory); os.IsNotExist(err) {
280-
os.Mkdir(directory, os.ModePerm)
357+
err := os.MkdirAll(directory, os.ModePerm)
358+
if err != nil {
359+
return err
360+
}
281361
}
282362

283363
err := ioutil.WriteFile(filepath.Join(directory, fileName), content, DefaultPermission)
@@ -286,3 +366,57 @@ func WriteFile(fileName, directory string, content []byte) error {
286366
}
287367
return nil
288368
}
369+
370+
// copy the contents of a flat manifest dir into an output dir
371+
func copyManifestDir(from, to string, overwrite bool) error {
372+
fromFiles, err := ioutil.ReadDir(from)
373+
if err != nil {
374+
return err
375+
}
376+
377+
if _, err := os.Stat(to); os.IsNotExist(err) {
378+
os.MkdirAll(to, os.ModePerm)
379+
}
380+
381+
for _, fromFile := range fromFiles {
382+
if fromFile.IsDir() {
383+
nestedTo := filepath.Join(to, filepath.Base(from))
384+
nestedFrom := filepath.Join(from, fromFile.Name())
385+
err = copyManifestDir(nestedFrom, nestedTo, overwrite)
386+
if err != nil {
387+
return err
388+
}
389+
continue
390+
}
391+
392+
contents, err := os.Open(filepath.Join(from, fromFile.Name()))
393+
if err != nil {
394+
return err
395+
}
396+
397+
toFilePath := filepath.Join(to, fromFile.Name())
398+
_, err = os.Stat(toFilePath)
399+
if err == nil && !overwrite {
400+
continue
401+
} else if err != nil && !os.IsNotExist(err) {
402+
return err
403+
}
404+
405+
toFile, err := os.Create(toFilePath)
406+
if err != nil {
407+
return err
408+
}
409+
410+
_, err = io.Copy(contents, toFile)
411+
if err != nil {
412+
return err
413+
}
414+
415+
err = os.Chmod(toFilePath, fromFile.Mode())
416+
if err != nil {
417+
return err
418+
}
419+
}
420+
421+
return nil
422+
}

‎pkg/lib/bundle/generate_test.go

+72-4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package bundle
22

33
import (
44
"fmt"
5+
"io/ioutil"
6+
"os"
57
"path/filepath"
68
"testing"
79

@@ -206,11 +208,77 @@ func TestGenerateDockerfileFunc(t *testing.T) {
206208
"LABEL operators.operatorframework.io.bundle.package.v1=test4\n"+
207209
"LABEL operators.operatorframework.io.bundle.channels.v1=test5\n"+
208210
"LABEL operators.operatorframework.io.bundle.channel.default.v1=test5\n\n"+
209-
"COPY /*.yaml /manifests/\n"+
210-
"COPY %s/annotations.yaml /metadata/annotations.yaml\n", MetadataDir,
211-
filepath.Join("/", MetadataDir))
211+
"COPY test2/*.yaml /manifests/\n"+
212+
"COPY metadata/annotations.yaml /metadata/annotations.yaml\n", MetadataDir)
212213

213-
content, err := GenerateDockerfile("test1", "test2", MetadataDir, "test4", "test5", "")
214+
content, err := GenerateDockerfile("test1", "test2", MetadataDir, "test2/", "metadata/", "./", "test4", "test5", "")
214215
require.NoError(t, err)
215216
require.Equal(t, output, string(content))
216217
}
218+
219+
func TestCopyYamlOutput(t *testing.T) {
220+
testOutputDir, _ := ioutil.TempDir("./", "test-generate")
221+
defer os.RemoveAll(testOutputDir)
222+
223+
testContent := []byte{0, 1, 0, 0}
224+
testManifestDir := "./testdata/generate/manifests"
225+
testWorkingDir := "./"
226+
testOverwrite := true
227+
228+
resultManifestDir, resultMetadataDir, err := CopyYamlOutput(testContent, testManifestDir, testOutputDir, testWorkingDir, testOverwrite)
229+
require.NoError(t, err)
230+
require.Equal(t, filepath.Join(testOutputDir, "manifests/"), resultManifestDir)
231+
require.Equal(t, filepath.Join(testOutputDir, "metadata/"), resultMetadataDir)
232+
233+
outputAnnotationsFile := filepath.Join(testOutputDir, "metadata/", "annotations.yaml")
234+
annotationsBlob, err := ioutil.ReadFile(outputAnnotationsFile)
235+
require.NoError(t, err)
236+
require.Equal(t, testContent, annotationsBlob)
237+
238+
csvFile := filepath.Join(testOutputDir, "manifests/", "prometheusoperator.0.14.0.clusterserviceversion.yaml")
239+
_, err = ioutil.ReadFile(csvFile)
240+
require.NoError(t, err)
241+
}
242+
243+
func TestCopyYamlOutput_NoOutputDir(t *testing.T) {
244+
testContent := []byte{0, 1, 0, 0}
245+
testManifestDir := "./testdata/generate/manifests"
246+
testWorkingDir := "./"
247+
testOverwrite := true
248+
249+
resultManifestDir, resultMetadataDir, err := CopyYamlOutput(testContent, testManifestDir, "", testWorkingDir, testOverwrite)
250+
require.NoError(t, err)
251+
require.Equal(t, testManifestDir, resultManifestDir)
252+
require.Equal(t, filepath.Join(filepath.Dir(testManifestDir), "metadata/"), resultMetadataDir)
253+
254+
outputAnnotationsFile := filepath.Join(resultMetadataDir, "annotations.yaml")
255+
annotationsBlob, err := ioutil.ReadFile(outputAnnotationsFile)
256+
require.NoError(t, err)
257+
require.Equal(t, testContent, annotationsBlob)
258+
259+
os.RemoveAll(filepath.Dir(outputAnnotationsFile))
260+
}
261+
262+
func TestCopyYamlOutput_NestedCopy(t *testing.T) {
263+
testOutputDir, _ := ioutil.TempDir("./", "test-generate")
264+
defer os.RemoveAll(testOutputDir)
265+
266+
testContent := []byte{0, 1, 0, 0}
267+
testManifestDir := "./testdata/generate/nested_manifests"
268+
testWorkingDir := "./"
269+
testOverwrite := true
270+
271+
resultManifestDir, resultMetadataDir, err := CopyYamlOutput(testContent, testManifestDir, testOutputDir, testWorkingDir, testOverwrite)
272+
require.NoError(t, err)
273+
require.Equal(t, filepath.Join(testOutputDir, "manifests/"), resultManifestDir)
274+
require.Equal(t, filepath.Join(testOutputDir, "metadata/"), resultMetadataDir)
275+
276+
outputAnnotationsFile := filepath.Join(testOutputDir, "metadata/", "annotations.yaml")
277+
annotationsBlob, err := ioutil.ReadFile(outputAnnotationsFile)
278+
require.NoError(t, err)
279+
require.Equal(t, testContent, annotationsBlob)
280+
281+
csvFile := filepath.Join(testOutputDir, "manifests/nested_manifests/", "prometheusoperator.0.14.0.clusterserviceversion.yaml")
282+
_, err = ioutil.ReadFile(csvFile)
283+
require.NoError(t, err)
284+
}

‎pkg/lib/bundle/testdata/generate/manifests/alertmanager.crd.yaml

+2,398
Large diffs are not rendered by default.

‎pkg/lib/bundle/testdata/generate/manifests/prometheus.crd.yaml

+2,971
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
#! parse-kind: ClusterServiceVersion
2+
apiVersion: operators.coreos.com/v1alpha1
3+
kind: ClusterServiceVersion
4+
metadata:
5+
name: prometheusoperator.0.14.0
6+
namespace: placeholder
7+
spec:
8+
displayName: Prometheus
9+
description: |
10+
An open-source monitoring system with a dimensional data model, flexible query language, efficient time series database and modern alerting approach.
11+
12+
_The Prometheus Open Cloud Service is Public Alpha. The goal before Beta is for additional user testing and minor bug fixes._
13+
14+
### Monitoring applications
15+
16+
Prometheus scrapes your application metrics based on targets maintained in a ServiceMonitor object. When alerts need to be sent, they are processsed by an AlertManager.
17+
18+
[Read the complete guide to monitoring applications with the Prometheus Open Cloud Service](https://coreos.com/tectonic/docs/latest/alm/prometheus-ocs.html)
19+
20+
## Supported Features
21+
22+
**High availability**
23+
Multiple instances are run across failure zones and data is replicated. This keeps your monitoring available during an outage, when you need it most.
24+
**Updates via automated operations**
25+
New Prometheus versions are deployed using a rolling update with no downtime, making it easy to stay up to date.
26+
**Handles the dynamic nature of containers**
27+
Alerting rules are attached to groups of containers instead of individual instances, which is ideal for the highly dynamic nature of container deployment.
28+
29+
keywords: ['prometheus', 'monitoring', 'tsdb', 'alerting']
30+
31+
maintainers:
32+
- name: CoreOS, Inc
33+
email: support@coreos.com
34+
35+
provider:
36+
name: CoreOS, Inc
37+
38+
links:
39+
- name: Prometheus
40+
url: https://www.prometheus.io/
41+
- name: Documentation
42+
url: https://coreos.com/operators/prometheus/docs/latest/
43+
- name: Prometheus Operator Source Code
44+
url: https://github.com/coreos/prometheus-operator
45+
46+
labels:
47+
alm-status-descriptors: prometheusoperator.0.14.0
48+
alm-owner-prometheus: prometheusoperator
49+
50+
selector:
51+
matchLabels:
52+
alm-owner-prometheus: prometheusoperator
53+
54+
icon:
55+
- base64data: PHN2ZyB3aWR0aD0iMjQ5MCIgaGVpZ2h0PSIyNTAwIiB2aWV3Qm94PSIwIDAgMjU2IDI1NyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCI+PHBhdGggZD0iTTEyOC4wMDEuNjY3QzU3LjMxMS42NjcgMCA1Ny45NzEgMCAxMjguNjY0YzAgNzAuNjkgNTcuMzExIDEyNy45OTggMTI4LjAwMSAxMjcuOTk4UzI1NiAxOTkuMzU0IDI1NiAxMjguNjY0QzI1NiA1Ny45NyAxOTguNjg5LjY2NyAxMjguMDAxLjY2N3ptMCAyMzkuNTZjLTIwLjExMiAwLTM2LjQxOS0xMy40MzUtMzYuNDE5LTMwLjAwNGg3Mi44MzhjMCAxNi41NjYtMTYuMzA2IDMwLjAwNC0zNi40MTkgMzAuMDA0em02MC4xNTMtMzkuOTRINjcuODQyVjE3OC40N2gxMjAuMzE0djIxLjgxNmgtLjAwMnptLS40MzItMzMuMDQ1SDY4LjE4NWMtLjM5OC0uNDU4LS44MDQtLjkxLTEuMTg4LTEuMzc1LTEyLjMxNS0xNC45NTQtMTUuMjE2LTIyLjc2LTE4LjAzMi0zMC43MTYtLjA0OC0uMjYyIDE0LjkzMyAzLjA2IDI1LjU1NiA1LjQ1IDAgMCA1LjQ2NiAxLjI2NSAxMy40NTggMi43MjItNy42NzMtOC45OTQtMTIuMjMtMjAuNDI4LTEyLjIzLTMyLjExNiAwLTI1LjY1OCAxOS42OC00OC4wNzkgMTIuNTgtNjYuMjAxIDYuOTEuNTYyIDE0LjMgMTQuNTgzIDE0LjggMzYuNTA1IDcuMzQ2LTEwLjE1MiAxMC40Mi0yOC42OSAxMC40Mi00MC4wNTYgMC0xMS43NjkgNy43NTUtMjUuNDQgMTUuNTEyLTI1LjkwNy02LjkxNSAxMS4zOTYgMS43OSAyMS4xNjUgOS41MyA0NS40IDIuOTAyIDkuMTAzIDIuNTMyIDI0LjQyMyA0Ljc3MiAzNC4xMzguNzQ0LTIwLjE3OCA0LjIxMy00OS42MiAxNy4wMTQtNTkuNzg0LTUuNjQ3IDEyLjguODM2IDI4LjgxOCA1LjI3IDM2LjUxOCA3LjE1NCAxMi40MjQgMTEuNDkgMjEuODM2IDExLjQ5IDM5LjYzOCAwIDExLjkzNi00LjQwNyAyMy4xNzMtMTEuODQgMzEuOTU4IDguNDUyLTEuNTg2IDE0LjI4OS0zLjAxNiAxNC4yODktMy4wMTZsMjcuNDUtNS4zNTVjLjAwMi0uMDAyLTMuOTg3IDE2LjQwMS0xOS4zMTQgMzIuMTk3eiIgZmlsbD0iI0RBNEUzMSIvPjwvc3ZnPg==
56+
mediatype: image/svg+xml
57+
58+
install:
59+
strategy: deployment
60+
spec:
61+
permissions:
62+
- serviceAccountName: prometheus-k8s
63+
rules:
64+
- apiGroups: [""]
65+
resources:
66+
- nodes
67+
- services
68+
- endpoints
69+
- pods
70+
verbs: ["get", "list", "watch"]
71+
- apiGroups: [""]
72+
resources:
73+
- configmaps
74+
verbs: ["get"]
75+
- serviceAccountName: prometheus-operator-0-14-0
76+
rules:
77+
- apiGroups:
78+
- apiextensions.k8s.io
79+
resources:
80+
- customresourcedefinitions
81+
verbs: ["get", "list"]
82+
- apiGroups:
83+
- monitoring.coreos.com
84+
resources:
85+
- alertmanagers
86+
- prometheuses
87+
- servicemonitors
88+
verbs:
89+
- "*"
90+
- apiGroups:
91+
- apps
92+
resources:
93+
- statefulsets
94+
verbs: ["*"]
95+
- apiGroups: [""]
96+
resources:
97+
- configmaps
98+
- secrets
99+
verbs: ["*"]
100+
- apiGroups: [""]
101+
resources:
102+
- pods
103+
verbs: ["list", "delete"]
104+
- apiGroups: [""]
105+
resources:
106+
- services
107+
- endpoints
108+
verbs: ["get", "create", "update"]
109+
- apiGroups: [""]
110+
resources:
111+
- nodes
112+
verbs: ["list", "watch"]
113+
- apiGroups: [""]
114+
resources:
115+
- namespaces
116+
verbs: ['list']
117+
deployments:
118+
- name: prometheus-operator
119+
spec:
120+
replicas: 1
121+
selector:
122+
matchLabels:
123+
k8s-app: prometheus-operator
124+
template:
125+
metadata:
126+
labels:
127+
k8s-app: prometheus-operator
128+
spec:
129+
serviceAccount: prometheus-operator-0-14-0
130+
containers:
131+
- name: prometheus-operator
132+
image: quay.io/coreos/prometheus-operator@sha256:5037b4e90dbb03ebdefaa547ddf6a1f748c8eeebeedf6b9d9f0913ad662b5731
133+
command:
134+
- sh
135+
- -c
136+
- >
137+
/bin/operator --namespace=$K8S_NAMESPACE --crd-apigroup monitoring.coreos.com
138+
--labels alm-status-descriptors=prometheusoperator.0.14.0,alm-owner-prometheus=prometheusoperator
139+
--kubelet-service=kube-system/kubelet
140+
--config-reloader-image=quay.io/coreos/configmap-reload:v0.0.1
141+
env:
142+
- name: K8S_NAMESPACE
143+
valueFrom:
144+
fieldRef:
145+
fieldPath: metadata.namespace
146+
ports:
147+
- containerPort: 8080
148+
name: http
149+
resources:
150+
limits:
151+
cpu: 200m
152+
memory: 100Mi
153+
requests:
154+
cpu: 100m
155+
memory: 50Mi
156+
maturity: alpha
157+
version: 0.14.0
158+
customresourcedefinitions:
159+
owned:
160+
- name: prometheuses.monitoring.coreos.com
161+
version: v1
162+
kind: Prometheus
163+
displayName: Prometheus
164+
description: A running Prometheus instance
165+
resources:
166+
- kind: Pod
167+
version: v1
168+
specDescriptors:
169+
- description: Desired number of Pods for the cluster
170+
displayName: Size
171+
path: replicas
172+
x-descriptors:
173+
- 'urn:alm:descriptor:com.tectonic.ui:podCount'
174+
- description: A selector for the ConfigMaps from which to load rule files
175+
displayName: Rule Config Map Selector
176+
path: ruleSelector
177+
x-descriptors:
178+
- 'urn:alm:descriptor:com.tectonic.ui:selector:core:v1:ConfigMap'
179+
- description: ServiceMonitors to be selected for target discovery
180+
displayName: Service Monitor Selector
181+
path: serviceMonitorSelector
182+
x-descriptors:
183+
- 'urn:alm:descriptor:com.tectonic.ui:selector:monitoring.coreos.com:v1:ServiceMonitor'
184+
- description: The ServiceAccount to use to run the Prometheus pods
185+
displayName: Service Account
186+
path: serviceAccountName
187+
x-descriptors:
188+
- 'urn:alm:descriptor:io.kubernetes:ServiceAccount'
189+
- description: Define resources requests and limits for single Pods
190+
displayName: Resource Request
191+
path: resources.requests
192+
x-descriptors:
193+
- 'urn:alm:descriptor:com.tectonic.ui:resourceRequirements'
194+
statusDescriptors:
195+
- description: The current number of Pods for the cluster
196+
displayName: Cluster Size
197+
path: replicas
198+
- path: prometheusSelector
199+
displayName: Prometheus Service Selector
200+
description: Label selector to find the service that routes to this prometheus
201+
x-descriptors:
202+
- 'urn:alm:descriptor:label:selector'
203+
- name: servicemonitors.monitoring.coreos.com
204+
version: v1
205+
kind: ServiceMonitor
206+
displayName: Service Monitor
207+
description: Configures prometheus to monitor a particular k8s service
208+
resources:
209+
- kind: Pod
210+
version: v1
211+
specDescriptors:
212+
- description: Selector to select which namespaces the Endpoints objects are discovered from
213+
displayName: Monitoring Namespaces
214+
path: namespaceSelector
215+
x-descriptors:
216+
- 'urn:alm:descriptor:com.tectonic.ui:namespaceSelector'
217+
- description: The label to use to retrieve the job name from
218+
displayName: Job Label
219+
path: jobLabel
220+
x-descriptors:
221+
- 'urn:alm:descriptor:com.tectonic.ui:label'
222+
- description: A list of endpoints allowed as part of this ServiceMonitor
223+
displayName: Endpoints
224+
path: endpoints
225+
x-descriptors:
226+
- 'urn:alm:descriptor:com.tectonic.ui:endpointList'
227+
- name: alertmanagers.monitoring.coreos.com
228+
version: v1
229+
kind: Alertmanager
230+
displayName: Alert Manager
231+
description: Configures an Alert Manager for the namespace
232+
resources:
233+
- kind: Pod
234+
version: v1
235+
specDescriptors:
236+
- description: Desired number of Pods for the cluster
237+
displayName: Size
238+
path: replicas
239+
x-descriptors:
240+
- 'urn:alm:descriptor:com.tectonic.ui:podCount'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
apiVersion: apiextensions.k8s.io/v1beta1
2+
kind: CustomResourceDefinition
3+
metadata:
4+
name: prometheusrules.monitoring.coreos.com
5+
spec:
6+
group: monitoring.coreos.com
7+
names:
8+
kind: PrometheusRule
9+
plural: prometheusrules
10+
scope: Namespaced
11+
validation:
12+
openAPIV3Schema:
13+
properties:
14+
spec:
15+
description: PrometheusRuleSpec contains specification parameters for a
16+
Rule.
17+
properties:
18+
groups:
19+
description: Content of Prometheus rule file
20+
items:
21+
description: RuleGroup is a list of sequentially evaluated recording
22+
and alerting rules.
23+
properties:
24+
interval:
25+
type: string
26+
name:
27+
type: string
28+
rules:
29+
items:
30+
description: Rule describes an alerting or recording rule.
31+
properties:
32+
alert:
33+
type: string
34+
annotations:
35+
type: object
36+
expr:
37+
type: string
38+
for:
39+
type: string
40+
labels:
41+
type: object
42+
record:
43+
type: string
44+
required:
45+
- expr
46+
type: array
47+
required:
48+
- name
49+
- rules
50+
type: array
51+
version: v1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
apiVersion: apiextensions.k8s.io/v1beta1
2+
kind: CustomResourceDefinition
3+
metadata:
4+
name: servicemonitors.monitoring.coreos.com
5+
spec:
6+
group: monitoring.coreos.com
7+
names:
8+
kind: ServiceMonitor
9+
plural: servicemonitors
10+
scope: Namespaced
11+
validation:
12+
openAPIV3Schema:
13+
properties:
14+
spec:
15+
description: ServiceMonitorSpec contains specification parameters for a
16+
ServiceMonitor.
17+
properties:
18+
endpoints:
19+
description: A list of endpoints allowed as part of this ServiceMonitor.
20+
items:
21+
description: Endpoint defines a scrapeable endpoint serving Prometheus
22+
metrics.
23+
properties:
24+
basicAuth:
25+
description: 'BasicAuth allow an endpoint to authenticate over
26+
basic authentication More info: https://prometheus.io/docs/operating/configuration/#endpoints'
27+
properties:
28+
password:
29+
description: SecretKeySelector selects a key of a Secret.
30+
properties:
31+
key:
32+
description: The key of the secret to select from. Must
33+
be a valid secret key.
34+
type: string
35+
name:
36+
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
37+
type: string
38+
optional:
39+
description: Specify whether the Secret or it's key must
40+
be defined
41+
type: boolean
42+
required:
43+
- key
44+
username:
45+
description: SecretKeySelector selects a key of a Secret.
46+
properties:
47+
key:
48+
description: The key of the secret to select from. Must
49+
be a valid secret key.
50+
type: string
51+
name:
52+
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
53+
type: string
54+
optional:
55+
description: Specify whether the Secret or it's key must
56+
be defined
57+
type: boolean
58+
required:
59+
- key
60+
bearerTokenFile:
61+
description: File to read bearer token for scraping targets.
62+
type: string
63+
honorLabels:
64+
description: HonorLabels chooses the metric's labels on collisions
65+
with target labels.
66+
type: boolean
67+
interval:
68+
description: Interval at which metrics should be scraped
69+
type: string
70+
metricRelabelings:
71+
description: MetricRelabelConfigs to apply to samples before ingestion.
72+
items:
73+
description: 'RelabelConfig allows dynamic rewriting of the
74+
label set, being applied to samples before ingestion. It defines
75+
`<metric_relabel_configs>`-section of Prometheus configuration.
76+
More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#metric_relabel_configs'
77+
properties:
78+
action:
79+
description: Action to perform based on regex matching.
80+
Default is 'replace'
81+
type: string
82+
modulus:
83+
description: Modulus to take of the hash of the source label
84+
values.
85+
format: int64
86+
type: integer
87+
regex:
88+
description: Regular expression against which the extracted
89+
value is matched. defailt is '(.*)'
90+
type: string
91+
replacement:
92+
description: Replacement value against which a regex replace
93+
is performed if the regular expression matches. Regex
94+
capture groups are available. Default is '$1'
95+
type: string
96+
separator:
97+
description: Separator placed between concatenated source
98+
label values. default is ';'.
99+
type: string
100+
sourceLabels:
101+
description: The source labels select values from existing
102+
labels. Their content is concatenated using the configured
103+
separator and matched against the configured regular expression
104+
for the replace, keep, and drop actions.
105+
items:
106+
type: string
107+
type: array
108+
targetLabel:
109+
description: Label to which the resulting value is written
110+
in a replace action. It is mandatory for replace actions.
111+
Regex capture groups are available.
112+
type: string
113+
type: array
114+
params:
115+
description: Optional HTTP URL parameters
116+
type: object
117+
path:
118+
description: HTTP path to scrape for metrics.
119+
type: string
120+
port:
121+
description: Name of the service port this endpoint refers to.
122+
Mutually exclusive with targetPort.
123+
type: string
124+
proxyUrl:
125+
description: ProxyURL eg http://proxyserver:2195 Directs scrapes
126+
to proxy through this endpoint.
127+
type: string
128+
scheme:
129+
description: HTTP scheme to use for scraping.
130+
type: string
131+
scrapeTimeout:
132+
description: Timeout after which the scrape is ended
133+
type: string
134+
targetPort:
135+
anyOf:
136+
- type: string
137+
- type: integer
138+
tlsConfig:
139+
description: TLSConfig specifies TLS configuration parameters.
140+
properties:
141+
caFile:
142+
description: The CA cert to use for the targets.
143+
type: string
144+
certFile:
145+
description: The client cert file for the targets.
146+
type: string
147+
insecureSkipVerify:
148+
description: Disable target certificate validation.
149+
type: boolean
150+
keyFile:
151+
description: The client key file for the targets.
152+
type: string
153+
serverName:
154+
description: Used to verify the hostname for the targets.
155+
type: string
156+
type: array
157+
jobLabel:
158+
description: The label to use to retrieve the job name from.
159+
type: string
160+
namespaceSelector:
161+
description: A selector for selecting namespaces either selecting all
162+
namespaces or a list of namespaces.
163+
properties:
164+
any:
165+
description: Boolean describing whether all namespaces are selected
166+
in contrast to a list restricting them.
167+
type: boolean
168+
matchNames:
169+
description: List of namespace names.
170+
items:
171+
type: string
172+
type: array
173+
selector:
174+
description: A label selector is a label query over a set of resources.
175+
The result of matchLabels and matchExpressions are ANDed. An empty
176+
label selector matches all objects. A null label selector matches
177+
no objects.
178+
properties:
179+
matchExpressions:
180+
description: matchExpressions is a list of label selector requirements.
181+
The requirements are ANDed.
182+
items:
183+
description: A label selector requirement is a selector that contains
184+
values, a key, and an operator that relates the key and values.
185+
properties:
186+
key:
187+
description: key is the label key that the selector applies
188+
to.
189+
type: string
190+
operator:
191+
description: operator represents a key's relationship to a
192+
set of values. Valid operators are In, NotIn, Exists and
193+
DoesNotExist.
194+
type: string
195+
values:
196+
description: values is an array of string values. If the operator
197+
is In or NotIn, the values array must be non-empty. If the
198+
operator is Exists or DoesNotExist, the values array must
199+
be empty. This array is replaced during a strategic merge
200+
patch.
201+
items:
202+
type: string
203+
type: array
204+
required:
205+
- key
206+
- operator
207+
type: array
208+
matchLabels:
209+
description: matchLabels is a map of {key,value} pairs. A single
210+
{key,value} in the matchLabels map is equivalent to an element
211+
of matchExpressions, whose key field is "key", the operator is
212+
"In", and the values array contains only "value". The requirements
213+
are ANDed.
214+
type: object
215+
targetLabels:
216+
description: TargetLabels transfers labels on the Kubernetes Service
217+
onto the target.
218+
items:
219+
type: string
220+
type: array
221+
required:
222+
- endpoints
223+
- selector
224+
version: v1

‎pkg/lib/bundle/testdata/generate/nested_manifests/alertmanager.crd.yaml

+2,398
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
#! parse-kind: ClusterServiceVersion
2+
apiVersion: operators.coreos.com/v1alpha1
3+
kind: ClusterServiceVersion
4+
metadata:
5+
name: prometheusoperator.0.14.0
6+
namespace: placeholder
7+
spec:
8+
displayName: Prometheus
9+
description: |
10+
An open-source monitoring system with a dimensional data model, flexible query language, efficient time series database and modern alerting approach.
11+
12+
_The Prometheus Open Cloud Service is Public Alpha. The goal before Beta is for additional user testing and minor bug fixes._
13+
14+
### Monitoring applications
15+
16+
Prometheus scrapes your application metrics based on targets maintained in a ServiceMonitor object. When alerts need to be sent, they are processsed by an AlertManager.
17+
18+
[Read the complete guide to monitoring applications with the Prometheus Open Cloud Service](https://coreos.com/tectonic/docs/latest/alm/prometheus-ocs.html)
19+
20+
## Supported Features
21+
22+
**High availability**
23+
Multiple instances are run across failure zones and data is replicated. This keeps your monitoring available during an outage, when you need it most.
24+
**Updates via automated operations**
25+
New Prometheus versions are deployed using a rolling update with no downtime, making it easy to stay up to date.
26+
**Handles the dynamic nature of containers**
27+
Alerting rules are attached to groups of containers instead of individual instances, which is ideal for the highly dynamic nature of container deployment.
28+
29+
keywords: ['prometheus', 'monitoring', 'tsdb', 'alerting']
30+
31+
maintainers:
32+
- name: CoreOS, Inc
33+
email: support@coreos.com
34+
35+
provider:
36+
name: CoreOS, Inc
37+
38+
links:
39+
- name: Prometheus
40+
url: https://www.prometheus.io/
41+
- name: Documentation
42+
url: https://coreos.com/operators/prometheus/docs/latest/
43+
- name: Prometheus Operator Source Code
44+
url: https://github.com/coreos/prometheus-operator
45+
46+
labels:
47+
alm-status-descriptors: prometheusoperator.0.14.0
48+
alm-owner-prometheus: prometheusoperator
49+
50+
selector:
51+
matchLabels:
52+
alm-owner-prometheus: prometheusoperator
53+
54+
icon:
55+
- base64data: PHN2ZyB3aWR0aD0iMjQ5MCIgaGVpZ2h0PSIyNTAwIiB2aWV3Qm94PSIwIDAgMjU2IDI1NyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCI+PHBhdGggZD0iTTEyOC4wMDEuNjY3QzU3LjMxMS42NjcgMCA1Ny45NzEgMCAxMjguNjY0YzAgNzAuNjkgNTcuMzExIDEyNy45OTggMTI4LjAwMSAxMjcuOTk4UzI1NiAxOTkuMzU0IDI1NiAxMjguNjY0QzI1NiA1Ny45NyAxOTguNjg5LjY2NyAxMjguMDAxLjY2N3ptMCAyMzkuNTZjLTIwLjExMiAwLTM2LjQxOS0xMy40MzUtMzYuNDE5LTMwLjAwNGg3Mi44MzhjMCAxNi41NjYtMTYuMzA2IDMwLjAwNC0zNi40MTkgMzAuMDA0em02MC4xNTMtMzkuOTRINjcuODQyVjE3OC40N2gxMjAuMzE0djIxLjgxNmgtLjAwMnptLS40MzItMzMuMDQ1SDY4LjE4NWMtLjM5OC0uNDU4LS44MDQtLjkxLTEuMTg4LTEuMzc1LTEyLjMxNS0xNC45NTQtMTUuMjE2LTIyLjc2LTE4LjAzMi0zMC43MTYtLjA0OC0uMjYyIDE0LjkzMyAzLjA2IDI1LjU1NiA1LjQ1IDAgMCA1LjQ2NiAxLjI2NSAxMy40NTggMi43MjItNy42NzMtOC45OTQtMTIuMjMtMjAuNDI4LTEyLjIzLTMyLjExNiAwLTI1LjY1OCAxOS42OC00OC4wNzkgMTIuNTgtNjYuMjAxIDYuOTEuNTYyIDE0LjMgMTQuNTgzIDE0LjggMzYuNTA1IDcuMzQ2LTEwLjE1MiAxMC40Mi0yOC42OSAxMC40Mi00MC4wNTYgMC0xMS43NjkgNy43NTUtMjUuNDQgMTUuNTEyLTI1LjkwNy02LjkxNSAxMS4zOTYgMS43OSAyMS4xNjUgOS41MyA0NS40IDIuOTAyIDkuMTAzIDIuNTMyIDI0LjQyMyA0Ljc3MiAzNC4xMzguNzQ0LTIwLjE3OCA0LjIxMy00OS42MiAxNy4wMTQtNTkuNzg0LTUuNjQ3IDEyLjguODM2IDI4LjgxOCA1LjI3IDM2LjUxOCA3LjE1NCAxMi40MjQgMTEuNDkgMjEuODM2IDExLjQ5IDM5LjYzOCAwIDExLjkzNi00LjQwNyAyMy4xNzMtMTEuODQgMzEuOTU4IDguNDUyLTEuNTg2IDE0LjI4OS0zLjAxNiAxNC4yODktMy4wMTZsMjcuNDUtNS4zNTVjLjAwMi0uMDAyLTMuOTg3IDE2LjQwMS0xOS4zMTQgMzIuMTk3eiIgZmlsbD0iI0RBNEUzMSIvPjwvc3ZnPg==
56+
mediatype: image/svg+xml
57+
58+
install:
59+
strategy: deployment
60+
spec:
61+
permissions:
62+
- serviceAccountName: prometheus-k8s
63+
rules:
64+
- apiGroups: [""]
65+
resources:
66+
- nodes
67+
- services
68+
- endpoints
69+
- pods
70+
verbs: ["get", "list", "watch"]
71+
- apiGroups: [""]
72+
resources:
73+
- configmaps
74+
verbs: ["get"]
75+
- serviceAccountName: prometheus-operator-0-14-0
76+
rules:
77+
- apiGroups:
78+
- apiextensions.k8s.io
79+
resources:
80+
- customresourcedefinitions
81+
verbs: ["get", "list"]
82+
- apiGroups:
83+
- monitoring.coreos.com
84+
resources:
85+
- alertmanagers
86+
- prometheuses
87+
- servicemonitors
88+
verbs:
89+
- "*"
90+
- apiGroups:
91+
- apps
92+
resources:
93+
- statefulsets
94+
verbs: ["*"]
95+
- apiGroups: [""]
96+
resources:
97+
- configmaps
98+
- secrets
99+
verbs: ["*"]
100+
- apiGroups: [""]
101+
resources:
102+
- pods
103+
verbs: ["list", "delete"]
104+
- apiGroups: [""]
105+
resources:
106+
- services
107+
- endpoints
108+
verbs: ["get", "create", "update"]
109+
- apiGroups: [""]
110+
resources:
111+
- nodes
112+
verbs: ["list", "watch"]
113+
- apiGroups: [""]
114+
resources:
115+
- namespaces
116+
verbs: ['list']
117+
deployments:
118+
- name: prometheus-operator
119+
spec:
120+
replicas: 1
121+
selector:
122+
matchLabels:
123+
k8s-app: prometheus-operator
124+
template:
125+
metadata:
126+
labels:
127+
k8s-app: prometheus-operator
128+
spec:
129+
serviceAccount: prometheus-operator-0-14-0
130+
containers:
131+
- name: prometheus-operator
132+
image: quay.io/coreos/prometheus-operator@sha256:5037b4e90dbb03ebdefaa547ddf6a1f748c8eeebeedf6b9d9f0913ad662b5731
133+
command:
134+
- sh
135+
- -c
136+
- >
137+
/bin/operator --namespace=$K8S_NAMESPACE --crd-apigroup monitoring.coreos.com
138+
--labels alm-status-descriptors=prometheusoperator.0.14.0,alm-owner-prometheus=prometheusoperator
139+
--kubelet-service=kube-system/kubelet
140+
--config-reloader-image=quay.io/coreos/configmap-reload:v0.0.1
141+
env:
142+
- name: K8S_NAMESPACE
143+
valueFrom:
144+
fieldRef:
145+
fieldPath: metadata.namespace
146+
ports:
147+
- containerPort: 8080
148+
name: http
149+
resources:
150+
limits:
151+
cpu: 200m
152+
memory: 100Mi
153+
requests:
154+
cpu: 100m
155+
memory: 50Mi
156+
maturity: alpha
157+
version: 0.14.0
158+
customresourcedefinitions:
159+
owned:
160+
- name: prometheuses.monitoring.coreos.com
161+
version: v1
162+
kind: Prometheus
163+
displayName: Prometheus
164+
description: A running Prometheus instance
165+
resources:
166+
- kind: Pod
167+
version: v1
168+
specDescriptors:
169+
- description: Desired number of Pods for the cluster
170+
displayName: Size
171+
path: replicas
172+
x-descriptors:
173+
- 'urn:alm:descriptor:com.tectonic.ui:podCount'
174+
- description: A selector for the ConfigMaps from which to load rule files
175+
displayName: Rule Config Map Selector
176+
path: ruleSelector
177+
x-descriptors:
178+
- 'urn:alm:descriptor:com.tectonic.ui:selector:core:v1:ConfigMap'
179+
- description: ServiceMonitors to be selected for target discovery
180+
displayName: Service Monitor Selector
181+
path: serviceMonitorSelector
182+
x-descriptors:
183+
- 'urn:alm:descriptor:com.tectonic.ui:selector:monitoring.coreos.com:v1:ServiceMonitor'
184+
- description: The ServiceAccount to use to run the Prometheus pods
185+
displayName: Service Account
186+
path: serviceAccountName
187+
x-descriptors:
188+
- 'urn:alm:descriptor:io.kubernetes:ServiceAccount'
189+
- description: Define resources requests and limits for single Pods
190+
displayName: Resource Request
191+
path: resources.requests
192+
x-descriptors:
193+
- 'urn:alm:descriptor:com.tectonic.ui:resourceRequirements'
194+
statusDescriptors:
195+
- description: The current number of Pods for the cluster
196+
displayName: Cluster Size
197+
path: replicas
198+
- path: prometheusSelector
199+
displayName: Prometheus Service Selector
200+
description: Label selector to find the service that routes to this prometheus
201+
x-descriptors:
202+
- 'urn:alm:descriptor:label:selector'
203+
- name: servicemonitors.monitoring.coreos.com
204+
version: v1
205+
kind: ServiceMonitor
206+
displayName: Service Monitor
207+
description: Configures prometheus to monitor a particular k8s service
208+
resources:
209+
- kind: Pod
210+
version: v1
211+
specDescriptors:
212+
- description: Selector to select which namespaces the Endpoints objects are discovered from
213+
displayName: Monitoring Namespaces
214+
path: namespaceSelector
215+
x-descriptors:
216+
- 'urn:alm:descriptor:com.tectonic.ui:namespaceSelector'
217+
- description: The label to use to retrieve the job name from
218+
displayName: Job Label
219+
path: jobLabel
220+
x-descriptors:
221+
- 'urn:alm:descriptor:com.tectonic.ui:label'
222+
- description: A list of endpoints allowed as part of this ServiceMonitor
223+
displayName: Endpoints
224+
path: endpoints
225+
x-descriptors:
226+
- 'urn:alm:descriptor:com.tectonic.ui:endpointList'
227+
- name: alertmanagers.monitoring.coreos.com
228+
version: v1
229+
kind: Alertmanager
230+
displayName: Alert Manager
231+
description: Configures an Alert Manager for the namespace
232+
resources:
233+
- kind: Pod
234+
version: v1
235+
specDescriptors:
236+
- description: Desired number of Pods for the cluster
237+
displayName: Size
238+
path: replicas
239+
x-descriptors:
240+
- 'urn:alm:descriptor:com.tectonic.ui:podCount'

‎pkg/lib/bundle/testdata/generate/nested_manifests/prometheus.crd.yaml

+2,971
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
apiVersion: apiextensions.k8s.io/v1beta1
2+
kind: CustomResourceDefinition
3+
metadata:
4+
name: prometheusrules.monitoring.coreos.com
5+
spec:
6+
group: monitoring.coreos.com
7+
names:
8+
kind: PrometheusRule
9+
plural: prometheusrules
10+
scope: Namespaced
11+
validation:
12+
openAPIV3Schema:
13+
properties:
14+
spec:
15+
description: PrometheusRuleSpec contains specification parameters for a
16+
Rule.
17+
properties:
18+
groups:
19+
description: Content of Prometheus rule file
20+
items:
21+
description: RuleGroup is a list of sequentially evaluated recording
22+
and alerting rules.
23+
properties:
24+
interval:
25+
type: string
26+
name:
27+
type: string
28+
rules:
29+
items:
30+
description: Rule describes an alerting or recording rule.
31+
properties:
32+
alert:
33+
type: string
34+
annotations:
35+
type: object
36+
expr:
37+
type: string
38+
for:
39+
type: string
40+
labels:
41+
type: object
42+
record:
43+
type: string
44+
required:
45+
- expr
46+
type: array
47+
required:
48+
- name
49+
- rules
50+
type: array
51+
version: v1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
apiVersion: apiextensions.k8s.io/v1beta1
2+
kind: CustomResourceDefinition
3+
metadata:
4+
name: servicemonitors.monitoring.coreos.com
5+
spec:
6+
group: monitoring.coreos.com
7+
names:
8+
kind: ServiceMonitor
9+
plural: servicemonitors
10+
scope: Namespaced
11+
validation:
12+
openAPIV3Schema:
13+
properties:
14+
spec:
15+
description: ServiceMonitorSpec contains specification parameters for a
16+
ServiceMonitor.
17+
properties:
18+
endpoints:
19+
description: A list of endpoints allowed as part of this ServiceMonitor.
20+
items:
21+
description: Endpoint defines a scrapeable endpoint serving Prometheus
22+
metrics.
23+
properties:
24+
basicAuth:
25+
description: 'BasicAuth allow an endpoint to authenticate over
26+
basic authentication More info: https://prometheus.io/docs/operating/configuration/#endpoints'
27+
properties:
28+
password:
29+
description: SecretKeySelector selects a key of a Secret.
30+
properties:
31+
key:
32+
description: The key of the secret to select from. Must
33+
be a valid secret key.
34+
type: string
35+
name:
36+
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
37+
type: string
38+
optional:
39+
description: Specify whether the Secret or it's key must
40+
be defined
41+
type: boolean
42+
required:
43+
- key
44+
username:
45+
description: SecretKeySelector selects a key of a Secret.
46+
properties:
47+
key:
48+
description: The key of the secret to select from. Must
49+
be a valid secret key.
50+
type: string
51+
name:
52+
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
53+
type: string
54+
optional:
55+
description: Specify whether the Secret or it's key must
56+
be defined
57+
type: boolean
58+
required:
59+
- key
60+
bearerTokenFile:
61+
description: File to read bearer token for scraping targets.
62+
type: string
63+
honorLabels:
64+
description: HonorLabels chooses the metric's labels on collisions
65+
with target labels.
66+
type: boolean
67+
interval:
68+
description: Interval at which metrics should be scraped
69+
type: string
70+
metricRelabelings:
71+
description: MetricRelabelConfigs to apply to samples before ingestion.
72+
items:
73+
description: 'RelabelConfig allows dynamic rewriting of the
74+
label set, being applied to samples before ingestion. It defines
75+
`<metric_relabel_configs>`-section of Prometheus configuration.
76+
More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#metric_relabel_configs'
77+
properties:
78+
action:
79+
description: Action to perform based on regex matching.
80+
Default is 'replace'
81+
type: string
82+
modulus:
83+
description: Modulus to take of the hash of the source label
84+
values.
85+
format: int64
86+
type: integer
87+
regex:
88+
description: Regular expression against which the extracted
89+
value is matched. defailt is '(.*)'
90+
type: string
91+
replacement:
92+
description: Replacement value against which a regex replace
93+
is performed if the regular expression matches. Regex
94+
capture groups are available. Default is '$1'
95+
type: string
96+
separator:
97+
description: Separator placed between concatenated source
98+
label values. default is ';'.
99+
type: string
100+
sourceLabels:
101+
description: The source labels select values from existing
102+
labels. Their content is concatenated using the configured
103+
separator and matched against the configured regular expression
104+
for the replace, keep, and drop actions.
105+
items:
106+
type: string
107+
type: array
108+
targetLabel:
109+
description: Label to which the resulting value is written
110+
in a replace action. It is mandatory for replace actions.
111+
Regex capture groups are available.
112+
type: string
113+
type: array
114+
params:
115+
description: Optional HTTP URL parameters
116+
type: object
117+
path:
118+
description: HTTP path to scrape for metrics.
119+
type: string
120+
port:
121+
description: Name of the service port this endpoint refers to.
122+
Mutually exclusive with targetPort.
123+
type: string
124+
proxyUrl:
125+
description: ProxyURL eg http://proxyserver:2195 Directs scrapes
126+
to proxy through this endpoint.
127+
type: string
128+
scheme:
129+
description: HTTP scheme to use for scraping.
130+
type: string
131+
scrapeTimeout:
132+
description: Timeout after which the scrape is ended
133+
type: string
134+
targetPort:
135+
anyOf:
136+
- type: string
137+
- type: integer
138+
tlsConfig:
139+
description: TLSConfig specifies TLS configuration parameters.
140+
properties:
141+
caFile:
142+
description: The CA cert to use for the targets.
143+
type: string
144+
certFile:
145+
description: The client cert file for the targets.
146+
type: string
147+
insecureSkipVerify:
148+
description: Disable target certificate validation.
149+
type: boolean
150+
keyFile:
151+
description: The client key file for the targets.
152+
type: string
153+
serverName:
154+
description: Used to verify the hostname for the targets.
155+
type: string
156+
type: array
157+
jobLabel:
158+
description: The label to use to retrieve the job name from.
159+
type: string
160+
namespaceSelector:
161+
description: A selector for selecting namespaces either selecting all
162+
namespaces or a list of namespaces.
163+
properties:
164+
any:
165+
description: Boolean describing whether all namespaces are selected
166+
in contrast to a list restricting them.
167+
type: boolean
168+
matchNames:
169+
description: List of namespace names.
170+
items:
171+
type: string
172+
type: array
173+
selector:
174+
description: A label selector is a label query over a set of resources.
175+
The result of matchLabels and matchExpressions are ANDed. An empty
176+
label selector matches all objects. A null label selector matches
177+
no objects.
178+
properties:
179+
matchExpressions:
180+
description: matchExpressions is a list of label selector requirements.
181+
The requirements are ANDed.
182+
items:
183+
description: A label selector requirement is a selector that contains
184+
values, a key, and an operator that relates the key and values.
185+
properties:
186+
key:
187+
description: key is the label key that the selector applies
188+
to.
189+
type: string
190+
operator:
191+
description: operator represents a key's relationship to a
192+
set of values. Valid operators are In, NotIn, Exists and
193+
DoesNotExist.
194+
type: string
195+
values:
196+
description: values is an array of string values. If the operator
197+
is In or NotIn, the values array must be non-empty. If the
198+
operator is Exists or DoesNotExist, the values array must
199+
be empty. This array is replaced during a strategic merge
200+
patch.
201+
items:
202+
type: string
203+
type: array
204+
required:
205+
- key
206+
- operator
207+
type: array
208+
matchLabels:
209+
description: matchLabels is a map of {key,value} pairs. A single
210+
{key,value} in the matchLabels map is equivalent to an element
211+
of matchExpressions, whose key field is "key", the operator is
212+
"In", and the values array contains only "value". The requirements
213+
are ANDed.
214+
type: object
215+
targetLabels:
216+
description: TargetLabels transfers labels on the Kubernetes Service
217+
onto the target.
218+
items:
219+
type: string
220+
type: array
221+
required:
222+
- endpoints
223+
- selector
224+
version: v1

0 commit comments

Comments
 (0)
Please sign in to comment.