Skip to content

Commit c2f6bc2

Browse files
authored
vm based providers: Introduce Provision manager (kubevirt#982)
* vm based providers: Introduce Provision manager Provision manager determines which providers to rebuild and which to retag according previous released `KUBEVIRTCI_TAG`. Motivation: 1. Freeze versions unless changed, less prone for regressions, improves reproducibility and consistency. 3. Faster provisioning. 4. Decouple collision domains, if one provider is problematic, we can still build other ones, without blocking them. Flow: It checks which files changed versus the latest `KUBEVIRTCI_TAG`. For each changed file, it find the matching rule and accumulate a list of targets to rebuild. Signed-off-by: Or Shoval <[email protected]> * gocli: Update vendor folder Signed-off-by: Or Shoval <[email protected]> * publish: Integrate provision manager Signed-off-by: Or Shoval <[email protected]> * pman: Extract filesystem functions to its own lib Signed-off-by: Or Shoval <[email protected]> * publish: Update kubevirtbot email Signed-off-by: Or Shoval <[email protected]> --------- Signed-off-by: Or Shoval <[email protected]>
1 parent 398ee73 commit c2f6bc2

File tree

554 files changed

+278127
-1455
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

554 files changed

+278127
-1455
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,5 @@ cluster-provision/gocli/bazel-*
1414
# image builder
1515
*.qcow2
1616
cluster-provision/images/vm-image-builder/*_build
17+
18+
cluster-provision/gocli/cover.out

cluster-provision/gocli/Makefile

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ GO ?= go
1313

1414
all: container-run
1515

16+
.PHONY: test
17+
test:
18+
$(GO) test -v ./cmd/... -coverprofile cover.out
19+
1620
.PHONY: gocli
1721
cli:
1822
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 $(GO) build -ldflags "-X 'kubevirt.io/kubevirtci/cluster-provision/gocli/images.SUFFIX=:$(KUBEVIRTCI_TAG)'" -o $(BIN_DIR)/cli ./cmd/cli

cluster-provision/gocli/build/Dockerfile

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
FROM scratch
1+
FROM alpine:3.18.0
2+
3+
RUN apk add git
4+
WORKDIR /workdir
5+
RUN git config --global --add safe.directory /workdir
26

37
COPY cli /cli
48

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Provision Manager
2+
3+
## Purpose:
4+
Detect which files are changed versus the latest `KUBEVIRTCI_TAG`,
5+
and build only the providers which should be updated.
6+
The other providers will be reused by retagging their latest version.
7+
8+
## Motivation:
9+
1. Freeze a state unless a change happens.
10+
2. Faster provision job.
11+
3. Reduce collision domain, a problem on one provider won't block updating the others.
12+
13+
## Related Files:
14+
1. `hack/pman/rules.yaml` - the rules that determine which folder/file affects which provider.
15+
2. `hack/pman/force` - changing this file allows to enforce rebuild of all vm based providers.
16+
17+
## Flow:
18+
1. Read rules.yaml and build a database of the rules.
19+
2. For each changed file (comparing to latest `KUBEVIRTCI_TAG`), check which rule match:
20+
a. Check the full filename (relative to kubevirtci folder).
21+
b. Check the `dirname` of the file
22+
c. Check each of the `dirname`/* of the file and its parent directories (until `.`, not included).
23+
If a match is found, the assicated rule is accumulated.
24+
Match must be found, unless the file is deleted,
25+
because we have rules which are regex, so once some files, are deleted also their rule will be gone.
26+
The motivation is to have less to maintain when adding / removing new providers.
27+
28+
See `Config` struct at `cluster-provision/gocli/cmd/provision_manager.go` for more details about rule types.
29+
30+
## Parameters:
31+
`--debug` - Run in debug mode.
32+
Output has the following sections:
33+
1. Run Parameters such as the tag comparing to, and the targets detected.
34+
2. The expanded rules (based on rules file).
35+
3. The files that were detected, their git status, and what is their effect based on the rules.
36+
4. The cumulative targets (which is the output in case of non DEBUG mode as well).
37+
Example: `docker run --rm -v $(pwd):/workdir:Z quay.io/kubevirtci/gocli provision-manager --debug`
38+
39+
## Notes:
40+
1. If you need to enforce provision of all providers, run and commit this file:
41+
`curl -sL https://storage.googleapis.com/kubevirt-prow/release/kubevirt/kubevirtci/latest?ignoreCache=1 > hack/pman/force`
42+
This is helpful in case you want a specific PR to rebuild all providers, without changing the publish job.
43+
2. In order to bypass provision manager and rebuild all targets, run `BYPASS_PMAN=true ./publish.sh`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package cmd_test
2+
3+
import (
4+
"testing"
5+
6+
. "github.com/onsi/ginkgo/v2"
7+
. "github.com/onsi/gomega"
8+
)
9+
10+
func TestCmd(t *testing.T) {
11+
RegisterFailHandler(Fail)
12+
RunSpecs(t, "Provision Manager Suite")
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package filesystem
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
7+
"github.com/spf13/afero"
8+
)
9+
10+
var fileSystem FileSystem = RealFileSystem{}
11+
12+
type FileSystem interface {
13+
Open(name string) (afero.File, error)
14+
Glob(pattern string) ([]string, error)
15+
Stat(name string) (os.FileInfo, error)
16+
}
17+
18+
// RealFileSystem
19+
type RealFileSystem struct{}
20+
21+
func (fs RealFileSystem) Open(name string) (afero.File, error) {
22+
return os.Open(name)
23+
}
24+
25+
func (fs RealFileSystem) Glob(pattern string) ([]string, error) {
26+
return filepath.Glob(pattern)
27+
}
28+
29+
func (fs RealFileSystem) Stat(name string) (os.FileInfo, error) {
30+
return os.Stat(name)
31+
}
32+
33+
// MockFileSystem
34+
type MockFileSystem struct {
35+
fs afero.Fs
36+
}
37+
38+
func (fs MockFileSystem) Open(name string) (afero.File, error) {
39+
return fs.fs.Open(name)
40+
}
41+
42+
func (fs MockFileSystem) Glob(pattern string) ([]string, error) {
43+
return afero.Glob(fs.fs, pattern)
44+
}
45+
46+
func (fs MockFileSystem) Stat(name string) (os.FileInfo, error) {
47+
return fs.fs.Stat(name)
48+
}
49+
50+
// General
51+
52+
func SetMockFileSystem() {
53+
fileSystem = MockFileSystem{fs: afero.NewMemMapFs()}
54+
}
55+
56+
func SetRealFileSystem() {
57+
fileSystem = RealFileSystem{}
58+
}
59+
60+
func GetFileSystem() FileSystem {
61+
return fileSystem
62+
}
63+
64+
func GetFs() afero.Fs {
65+
if mockFs, ok := fileSystem.(MockFileSystem); ok {
66+
return mockFs.fs
67+
} else {
68+
return afero.NewOsFs()
69+
}
70+
}
71+
72+
func GlobDirectories(path string) ([]string, error) {
73+
files, err := fileSystem.Glob(path)
74+
if err != nil {
75+
return nil, err
76+
}
77+
78+
var directories []string
79+
for _, candid := range files {
80+
f, err := fileSystem.Stat(candid)
81+
if err != nil {
82+
return nil, err
83+
}
84+
if f.IsDir() {
85+
directories = append(directories, candid)
86+
}
87+
}
88+
89+
return directories, nil
90+
}

0 commit comments

Comments
 (0)