Skip to content

Commit 3a64602

Browse files
Download latest default components vector from release branch (#62)
* Download latest default components.yaml from release branch of GLK GitHub repo * Add the release branch name to the info log. Co-authored-by: Martin Weindel <martin.weindel@sap.com> * add GetReleaseBranchName() method * Address review comments: Add documentation, refactor Git code --------- Co-authored-by: Martin Weindel <martin.weindel@sap.com>
1 parent bee29bd commit 3a64602

9 files changed

Lines changed: 142 additions & 7 deletions

File tree

docs/api-reference/landscapekit-v1alpha1.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,20 @@ string
386386
<p>ComponentsVectorFile is the path to the components vector file. A default vector is applied if not specified.</p>
387387
</td>
388388
</tr>
389+
<tr>
390+
<td>
391+
<code>defaultVersionsUpdateStrategy</code></br>
392+
<em>
393+
string
394+
</em>
395+
</td>
396+
<td>
397+
<em>(Optional)</em>
398+
<p>UpdateStrategy determines whether the versions in the default vector should be updated from the release branch on generate.
399+
Possible values are &ldquo;Disabled&rdquo; (default) and &ldquo;ReleaseBranch&rdquo;.
400+
Only used if no ComponentsVectorFile is specified.</p>
401+
</td>
402+
</tr>
389403
</tbody>
390404
</table>
391405
<hr/>

docs/usage/versions.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,21 @@ components:
2222
version: v1.134.1
2323
```
2424
25+
#### Updating Default Component Vector from GLK Release Branch
26+
27+
The included default component vector can be updated from the GLK release branch, where patch updates are regularly applied.
28+
GLK can automatically retrieve the updated `components.yaml` file and use the latest versions from the release branch if a specific configuration flag is set in your GLK configuration.
29+
This allows you to keep your component versions up-to-date with the latest patches provided by the maintainers.
30+
31+
You can enable this feature by adding the following configuration to your `LandscapeKitConfiguration`:
32+
33+
```yaml
34+
apiVersion: landscape.config.gardener.cloud/v1alpha1
35+
kind: LandscapeKitConfiguration
36+
versionConfig:
37+
defaultVersionsUpdateStrategy: ReleaseBranch
38+
```
39+
2540
### Custom Component Vector
2641

2742
You can override the default component vector by specifying a custom vector file in your GLK configuration:

example/20-componentconfig-glk.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ kind: LandscapeKitConfiguration
1919
# - component-name
2020
# versionConfig:
2121
# componentsVectorFile: ./versions.yaml
22+
# defaultVersionsUpdateStrategy: ReleaseBranch

pkg/apis/config/v1alpha1/types.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,24 @@ func (nv *OCMComponent) String() string {
9393
return nv.Name + ":" + nv.Version
9494
}
9595

96+
const (
97+
// DefaultVersionsUpdateStrategyReleaseBranch indicates that the versions in the default vector should be updated from the release branch on generate.
98+
DefaultVersionsUpdateStrategyReleaseBranch = "ReleaseBranch"
99+
// DefaultVersionsUpdateStrategyDisabled indicates that the versions in the default vector should not be updated on generate.
100+
DefaultVersionsUpdateStrategyDisabled = "Disabled"
101+
)
102+
103+
// AllowedDefaultVersionsUpdateStrategies lists all allowed strategies for updating versions in the default components vector.
104+
var AllowedDefaultVersionsUpdateStrategies = []string{DefaultVersionsUpdateStrategyReleaseBranch, DefaultVersionsUpdateStrategyDisabled}
105+
96106
// VersionConfiguration contains configuration for versioning.
97107
type VersionConfiguration struct {
98108
// ComponentsVectorFile is the path to the components vector file. A default vector is applied if not specified.
99109
// +optional
100110
ComponentsVectorFile *string `json:"componentsVectorFile,omitempty"`
111+
// UpdateStrategy determines whether the versions in the default vector should be updated from the release branch on generate.
112+
// Possible values are "Disabled" (default) and "ReleaseBranch".
113+
// Only used if no ComponentsVectorFile is specified.
114+
// +optional
115+
DefaultVersionsUpdateStrategy *string `json:"defaultVersionsUpdateStrategy,omitempty"`
101116
}

pkg/apis/config/v1alpha1/validation/validation.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package validation
77
import (
88
"net/url"
99
"path"
10+
"slices"
1011
"strings"
1112

1213
"k8s.io/apimachinery/pkg/util/validation/field"
@@ -132,6 +133,9 @@ func ValidateVersionConfig(conf *configv1alpha1.VersionConfiguration, fldPath *f
132133
if conf.ComponentsVectorFile != nil && strings.TrimSpace(*conf.ComponentsVectorFile) == "" {
133134
allErrs = append(allErrs, field.Required(fldPath.Child("componentsVectorFile"), "components vector file path must be specified"))
134135
}
136+
if conf.DefaultVersionsUpdateStrategy != nil && !slices.Contains(configv1alpha1.AllowedDefaultVersionsUpdateStrategies, *conf.DefaultVersionsUpdateStrategy) {
137+
allErrs = append(allErrs, field.Invalid(fldPath.Child("defaultVersionsUpdateStrategy"), *conf.DefaultVersionsUpdateStrategy, "allowed values are: "+strings.Join(configv1alpha1.AllowedDefaultVersionsUpdateStrategies, ", ")))
138+
}
135139

136140
return allErrs
137141
}

pkg/apis/config/v1alpha1/validation/validation_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,17 @@ var _ = Describe("Validation", func() {
249249
errList := validation.ValidateLandscapeKitConfiguration(conf)
250250
Expect(errList).To(BeEmpty())
251251
})
252+
253+
It("should pass with a valid DefaultVersionsUpdateStrategy", func() {
254+
conf := &v1alpha1.LandscapeKitConfiguration{
255+
VersionConfig: &v1alpha1.VersionConfiguration{
256+
DefaultVersionsUpdateStrategy: ptr.To("ReleaseBranch"),
257+
},
258+
}
259+
260+
errList := validation.ValidateLandscapeKitConfiguration(conf)
261+
Expect(errList).To(BeEmpty())
262+
})
252263
})
253264
})
254265
})

pkg/apis/config/v1alpha1/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/components/types.go

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,22 @@ func (o *options) GetLogger() logr.Logger {
8686
// NewOptions returns a new Options instance.
8787
func NewOptions(opts *generateoptions.Options, fs afero.Afero) (Options, error) {
8888
componentVectorBytes := componentvector.DefaultComponentsYAML
89-
if opts.Config != nil && opts.Config.VersionConfig != nil && opts.Config.VersionConfig.ComponentsVectorFile != nil {
90-
opts.Log.Info("Using custom component vector file", "file", *opts.Config.VersionConfig.ComponentsVectorFile)
91-
92-
var err error
93-
componentVectorBytes, err = fs.ReadFile(*opts.Config.VersionConfig.ComponentsVectorFile)
94-
if err != nil {
95-
return nil, fmt.Errorf("failed to read component vector file: %w", err)
89+
if opts.Config != nil && opts.Config.VersionConfig != nil {
90+
if opts.Config.VersionConfig.ComponentsVectorFile != nil {
91+
opts.Log.Info("Using custom component vector file", "file", *opts.Config.VersionConfig.ComponentsVectorFile)
92+
93+
var err error
94+
componentVectorBytes, err = fs.ReadFile(*opts.Config.VersionConfig.ComponentsVectorFile)
95+
if err != nil {
96+
return nil, fmt.Errorf("failed to read component vector file: %w", err)
97+
}
98+
} else if updateStrategy := opts.Config.VersionConfig.DefaultVersionsUpdateStrategy; updateStrategy != nil && *updateStrategy == v1alpha1.DefaultVersionsUpdateStrategyReleaseBranch {
99+
opts.Log.Info("Updating default component vector file from the release branch", "branch", utilscomponentvector.GetReleaseBranchName())
100+
var err error
101+
componentVectorBytes, err = utilscomponentvector.GetDefaultComponentVectorFromGitHub()
102+
if err != nil {
103+
return nil, fmt.Errorf("failed to update default component vector file: %w", err)
104+
}
96105
}
97106
}
98107

pkg/utils/componentvector/git.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
package componentvector
6+
7+
import (
8+
"bytes"
9+
"fmt"
10+
"io"
11+
"net/http"
12+
"strings"
13+
14+
"k8s.io/component-base/version"
15+
)
16+
17+
const (
18+
githubUrlPrefix = "https://github.com"
19+
glkRepository = "gardener/gardener-landscape-kit"
20+
filePath = "componentvector/components.yaml"
21+
)
22+
23+
// GetReleaseBranchName returns the release branch name based on the current GLK version.
24+
func GetReleaseBranchName() string {
25+
glkVersion := version.Get()
26+
return fmt.Sprintf("release-v%s.%s", glkVersion.Major, glkVersion.Minor)
27+
}
28+
29+
// GetDefaultComponentVectorFromGitHub fetches the latest default component vector file
30+
// from the release branch of the gardener-landscape-kit GitHub repository based on the current GLK version.
31+
func GetDefaultComponentVectorFromGitHub() ([]byte, error) {
32+
return getFileFromGitRepository(githubUrlPrefix+"/"+glkRepository, GetReleaseBranchName(), filePath)
33+
}
34+
35+
func getFileFromGitRepository(repositoryUrl, branch, filePath string) ([]byte, error) {
36+
rawURL := strings.TrimSuffix(repositoryUrl, "/")
37+
38+
if !strings.HasPrefix(rawURL, githubUrlPrefix) {
39+
return nil, fmt.Errorf("unsupported Git provider for URL: %s", rawURL)
40+
}
41+
// Convert GitHub repo URL to raw content URL if necessary.
42+
// e.g. https://github.com/org/repo -> https://raw.githubusercontent.com/org/repo/branch/path
43+
rawURL = "https://raw.githubusercontent.com" + rawURL[len(githubUrlPrefix):] + "/" + branch + "/" + filePath
44+
45+
resp, err := http.Get(rawURL) // #nosec G107 -- This is a GET request to a constrained public GitHub URL.
46+
if err != nil {
47+
return nil, err
48+
}
49+
defer resp.Body.Close()
50+
51+
if resp.StatusCode != http.StatusOK {
52+
return nil, fmt.Errorf("failed to fetch file from '%s': %s", rawURL, resp.Status)
53+
}
54+
55+
buf := new(bytes.Buffer)
56+
_, err = io.Copy(buf, resp.Body)
57+
if err != nil {
58+
return nil, err
59+
}
60+
return buf.Bytes(), nil
61+
}

0 commit comments

Comments
 (0)