-
Notifications
You must be signed in to change notification settings - Fork 30
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
Add components verification step to bootstraping WGE #3675
base: main
Are you sure you want to change the base?
Changes from 5 commits
8937d65
24b2317
171dc77
6eb1424
1de368e
fcdb1a2
f551a78
ef56b7f
9762361
5fe1a34
749bbfc
eabd444
fe93e2c
d74deac
bb582e4
90f4cc2
5bd7d09
0d1acdc
3be5372
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package utils | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"sort" | ||
"strings" | ||
"time" | ||
|
||
"github.com/weaveworks/weave-gitops/pkg/logger" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
k8s_client "sigs.k8s.io/controller-runtime/pkg/client" | ||
|
||
"sigs.k8s.io/cli-utils/pkg/kstatus/polling" | ||
"sigs.k8s.io/cli-utils/pkg/kstatus/polling/aggregator" | ||
"sigs.k8s.io/cli-utils/pkg/kstatus/polling/collector" | ||
"sigs.k8s.io/cli-utils/pkg/kstatus/polling/event" | ||
"sigs.k8s.io/cli-utils/pkg/kstatus/status" | ||
"sigs.k8s.io/cli-utils/pkg/object" | ||
) | ||
|
||
type StatusChecker struct { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. missing comments as exported |
||
pollInterval time.Duration | ||
timeout time.Duration | ||
client client.Client | ||
statusPoller *polling.StatusPoller | ||
logger logger.Logger | ||
} | ||
|
||
func NewStatusChecker(client k8s_client.Client, pollInterval time.Duration, timeout time.Duration, log logger.Logger) (*StatusChecker, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. missing comments |
||
|
||
return &StatusChecker{ | ||
pollInterval: pollInterval, | ||
timeout: timeout, | ||
client: client, | ||
statusPoller: polling.NewStatusPoller(client, client.RESTMapper(), polling.Options{}), | ||
logger: log, | ||
}, nil | ||
} | ||
|
||
func (sc *StatusChecker) Assess(identifiers ...object.ObjMetadata) error { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. missing comments as exported |
||
ctx, cancel := context.WithTimeout(context.Background(), sc.timeout) | ||
defer cancel() | ||
|
||
opts := polling.PollOptions{PollInterval: sc.pollInterval} | ||
eventsChan := sc.statusPoller.Poll(ctx, identifiers, opts) | ||
|
||
coll := collector.NewResourceStatusCollector(identifiers) | ||
done := coll.ListenWithObserver(eventsChan, desiredStatusNotifierFunc(cancel, status.CurrentStatus)) | ||
|
||
<-done | ||
|
||
// we use sorted identifiers to loop over the resource statuses because a Go's map is unordered. | ||
// sorting identifiers by object's name makes sure that the logs look stable for every run | ||
sort.SliceStable(identifiers, func(i, j int) bool { | ||
return strings.Compare(identifiers[i].Name, identifiers[j].Name) < 0 | ||
}) | ||
for _, id := range identifiers { | ||
rs := coll.ResourceStatuses[id] | ||
switch rs.Status { | ||
case status.CurrentStatus: | ||
sc.logger.Successf("%s: %s ready", rs.Identifier.Name, strings.ToLower(rs.Identifier.GroupKind.Kind)) | ||
case status.NotFoundStatus: | ||
sc.logger.Failuref("%s: %s not found", rs.Identifier.Name, strings.ToLower(rs.Identifier.GroupKind.Kind)) | ||
default: | ||
sc.logger.Failuref("%s: %s not ready", rs.Identifier.Name, strings.ToLower(rs.Identifier.GroupKind.Kind)) | ||
} | ||
} | ||
|
||
if coll.Error != nil || ctx.Err() == context.DeadlineExceeded { | ||
return fmt.Errorf("timed out waiting for condition") | ||
} | ||
return nil | ||
} | ||
|
||
// desiredStatusNotifierFunc returns an Observer function for the | ||
// ResourceStatusCollector that will cancel the context (using the cancelFunc) | ||
// when all resources have reached the desired status. | ||
func desiredStatusNotifierFunc(cancelFunc context.CancelFunc, | ||
desired status.Status) collector.ObserverFunc { | ||
return func(rsc *collector.ResourceStatusCollector, _ event.Event) { | ||
var rss []*event.ResourceStatus | ||
for _, rs := range rsc.ResourceStatuses { | ||
rss = append(rss, rs) | ||
} | ||
aggStatus := aggregator.AggregateStatus(rss, desired) | ||
if aggStatus == desired { | ||
cancelFunc() | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
//go:build integration | ||
|
||
package utils | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"testing" | ||
"time" | ||
|
||
"github.com/stretchr/testify/assert" | ||
testutils "github.com/weaveworks/weave-gitops-enterprise/test/utils" | ||
"github.com/weaveworks/weave-gitops/pkg/logger" | ||
"k8s.io/apimachinery/pkg/runtime/schema" | ||
"sigs.k8s.io/cli-utils/pkg/object" | ||
k8s_client "sigs.k8s.io/controller-runtime/pkg/client" | ||
k8s_config "sigs.k8s.io/controller-runtime/pkg/client/config" | ||
) | ||
|
||
func TestStatusCheckerIt(t *testing.T) { | ||
// Setup function to create kubeconfig and set the KUBECONFIG environment variable | ||
setup := func() error { | ||
kp, err := testutils.CreateKubeconfigFileForRestConfig(*cfg) | ||
if err != nil { | ||
return fmt.Errorf("cannot create kubeconfig: %w", err) | ||
} | ||
os.Setenv("KUBECONFIG", kp) | ||
return nil | ||
} | ||
|
||
// Reset function to clean up after the test | ||
reset := func() { | ||
os.Unsetenv("KUBECONFIG") | ||
} | ||
|
||
// Run the setup function and handle errors | ||
assert.NoError(t, setup(), "Error setting up kubeconfig") | ||
defer reset() | ||
|
||
// Create the Kubernetes client using the kubeconfig | ||
config, err := k8s_config.GetConfig() | ||
assert.NoError(t, err, "Error getting Kubernetes config") | ||
client, err := k8s_client.New(config, k8s_client.Options{}) | ||
assert.NoError(t, err, "Error creating Kubernetes client") | ||
|
||
// Initialize logger | ||
logInstance := logger.NewCLILogger(os.Stdout) | ||
|
||
// Initialize the StatusChecker | ||
statusChecker, err := NewStatusChecker(client, 5*time.Second, 1*time.Minute, logInstance) | ||
assert.NoError(t, err, "Error creating StatusChecker") | ||
|
||
// Define test cases | ||
testCases := []struct { | ||
name string | ||
identifiers []object.ObjMetadata | ||
}{ | ||
{ | ||
name: "Check specific Kubernetes resource", | ||
identifiers: []object.ObjMetadata{ | ||
{ | ||
Name: "cluster-controller-manager", | ||
Namespace: "flux-system", | ||
GroupKind: schema.GroupKind{Group: "apps", Kind: "Deployment"}, | ||
}, | ||
// Add more resources as needed | ||
}, | ||
}, | ||
// ... other test cases ... | ||
} | ||
|
||
for _, tc := range testCases { | ||
t.Run(tc.name, func(t *testing.T) { | ||
// Call the Assess function to check the status of resources | ||
err := statusChecker.Assess(tc.identifiers...) | ||
assert.NoError(t, err, "Error assessing resource status") | ||
}) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are the suggested components to be checked, do u think we should add more?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess that we should try to see whether the list could be dynamic over static
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for the installwge step, the components are being defined as part of the helm chart and its dependencies
https://github.com/weaveworks/weave-gitops-enterprise/blob/main/charts/mccp/Chart.yaml
an strategy to resolve the components could be created out of it