Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ROX-16507: Download ACS Operator CRDs dynamically #1010

Merged
merged 8 commits into from
Jun 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions fleetshard/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type Config struct {
MetricsAddress string `env:"FLEETSHARD_METRICS_ADDRESS" envDefault:":8080"`
EgressProxyImage string `env:"EGRESS_PROXY_IMAGE"`
FeatureFlagUpgradeOperatorEnabled bool `env:"FEATURE_FLAG_UPGRADE_OPERATOR_ENABLED" envDefault:"false"`
BaseCrdURL string `env:"BASE_CRD_URL" envDefault:"https://raw.githubusercontent.com/stackrox/stackrox/%s/operator/bundle/manifests/"`

AWS AWS
ManagedDB ManagedDB
Expand Down
70 changes: 61 additions & 9 deletions fleetshard/pkg/central/charts/charts.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import (
"context"
"embed"
"fmt"
"io"
"io/fs"
"net/http"
"path"
"strings"

Expand All @@ -26,8 +28,8 @@ var (
data embed.FS
)

// LoadChart loads a chart from the given path on the given file system.
func LoadChart(fsys fs.FS, chartPath string) (*chart.Chart, error) {
// TraverseChart combines all chart files into memory from given file system
func TraverseChart(fsys fs.FS, chartPath string) ([]*loader.BufferedFile, error) {
chartPath = strings.TrimRight(chartPath, "/")
var chartFiles []*loader.BufferedFile
err := fs.WalkDir(fsys, chartPath, func(path string, d fs.DirEntry, err error) error {
Expand All @@ -50,22 +52,72 @@ func LoadChart(fsys fs.FS, chartPath string) (*chart.Chart, error) {
if err != nil {
return nil, fmt.Errorf("loading chart from %q: %w", chartPath, err)
}
return chartFiles, nil
}

chrt, err := loader.LoadFiles(chartFiles)
func downloadTemplates(urls []string) ([]*loader.BufferedFile, error) {
var chartFiles []*loader.BufferedFile
for _, url := range urls {
buffered, err := downloadTemplate(url)
if err != nil {
return nil, fmt.Errorf("failed downloading template from %s: %w", url, err)
}
chartFiles = append(chartFiles, buffered)
}
return chartFiles, nil
}

func downloadTemplate(url string) (*loader.BufferedFile, error) {
resp, err := http.Get(url)
kurlov marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return nil, fmt.Errorf("loading chart from %s: %w", chartPath, err)
return nil, fmt.Errorf("failed Get for %s: %w", url, err)
}
defer resp.Body.Close()

bytes, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("cannot read bytes: %w", err)
}

// parse filename from the URL
if !strings.Contains(url, "/") {
return nil, fmt.Errorf("cannot parse filename from %s", url)
}
filename := url[strings.LastIndex(url, "/")+1:]
kurlov marked this conversation as resolved.
Show resolved Hide resolved
name := path.Join("templates", filename)

bufferedFile := &loader.BufferedFile{
Name: name,
Data: bytes,
}
return chrt, nil

return bufferedFile, nil
}

// GetChart loads a chart from the data directory. The name should be the name of the containing directory.
func GetChart(name string) (*chart.Chart, error) {
return LoadChart(data, path.Join("data", name))
// Optional: pass list of URLs to download additional template files for the chart.
func GetChart(name string, urls []string) (*chart.Chart, error) {
chartFiles, err := TraverseChart(data, path.Join("data", name))
if err != nil {
return nil, fmt.Errorf("failed getting chart files for %q: %w", name, err)
}
if len(urls) > 0 {
downloadedFiles, err := downloadTemplates(urls)
if err != nil {
return nil, fmt.Errorf("failed downloading chart files %q: %w", name, err)
}
chartFiles = append(chartFiles, downloadedFiles...)
}
loadedChart, err := loader.LoadFiles(chartFiles)
if err != nil {
return nil, fmt.Errorf("failed loading chart %q: %w", name, err)
}
return loadedChart, nil
}

// MustGetChart loads a chart from the data directory. Unlike GetChart, it panics if an error is encountered.
func MustGetChart(name string) *chart.Chart {
chrt, err := GetChart(name)
func MustGetChart(name string, urls []string) *chart.Chart {
chrt, err := GetChart(name, urls)
if err != nil {
panic(err)
}
Expand Down
20 changes: 17 additions & 3 deletions fleetshard/pkg/central/charts/charts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
ctrlClient "sigs.k8s.io/controller-runtime/pkg/client"

"helm.sh/helm/v3/pkg/chart/loader"
"helm.sh/helm/v3/pkg/chartutil"

"github.com/stretchr/testify/assert"
Expand All @@ -34,13 +35,15 @@ var dummyDeployment = &appsv1.Deployment{
}

func TestTenantResourcesChart(t *testing.T) {
c, err := GetChart("tenant-resources")
c, err := GetChart("tenant-resources", nil)
require.NoError(t, err)
assert.NotNil(t, c)
}

func TestInstallOrUpdateChartCreateNew(t *testing.T) {
chart, err := LoadChart(testdata, "testdata/test-chart")
chartFiles, err := TraverseChart(testdata, "testdata/test-chart")
require.NoError(t, err)
chart, err := loader.LoadFiles(chartFiles)
require.NoError(t, err)
fakeClient := testutils.NewFakeClientBuilder(t).Build()
ctx := context.Background()
Expand All @@ -67,7 +70,9 @@ func TestInstallOrUpdateChartCreateNew(t *testing.T) {
}

func TestInstallOrUpdateChartUpdateExisting(t *testing.T) {
chart, err := LoadChart(testdata, "testdata/test-chart")
chartFiles, err := TraverseChart(testdata, "testdata/test-chart")
require.NoError(t, err)
chart, err := loader.LoadFiles(chartFiles)
require.NoError(t, err)
fakeClient := testutils.NewFakeClientBuilder(t, dummyDeployment).Build()
ctx := context.Background()
Expand All @@ -92,3 +97,12 @@ func TestInstallOrUpdateChartUpdateExisting(t *testing.T) {
assert.NotEmpty(t, res.GetLabels())
assert.Equal(t, "baz", res.GetLabels()["foo"])
}

func TestGetChartWithDynamicTemplate(t *testing.T) {
crdURL := "https://raw.githubusercontent.com/stackrox/stackrox/master/operator/bundle/manifests/platform.stackrox.io_securedclusters.yaml"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you make the URL configurable?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The URL will be dynamic (containing release tag)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The URL should be configurable so that we don't need to rebuild fleetshard to change the download source.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved URL to the config

dynamicTemplates := []string{crdURL}

c, err := GetChart("rhacs-operator", dynamicTemplates)
require.NoError(t, err)
assert.NotNil(t, c)
}
Loading