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

fix: await correctly for regex sequence #34

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
4 changes: 2 additions & 2 deletions example/observed-regex.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ metadata:
annotations:
crossplane.io/external-name: foo
crossplane.io/composition-resource-name: first-subresource-2
name: first
name: first-subresource-2
spec:
forProvider:
conditionAfter:
Expand Down Expand Up @@ -32,7 +32,7 @@ metadata:
annotations:
crossplane.io/external-name: foo
crossplane.io/composition-resource-name: first-subresource-1
name: first
name: first-subresource-1
spec:
forProvider:
conditionAfter:
Expand Down
35 changes: 22 additions & 13 deletions fn.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,21 +71,14 @@ func (f *Function) RunFunction(_ context.Context, req *fnv1beta1.RunFunctionRequ
continue
}
for _, before := range sequence[:i] {
strictPattern := string(before)
if !strings.HasPrefix(strictPattern, START) && !strings.HasSuffix(strictPattern, END) {
// if the user provides a delimited regex, we'll use it as is
// if not, add the regex with ^ & $ to match the entire string
// possibly avoid using regex for matching literal strings
strictPattern = fmt.Sprintf("%s%s%s", START, string(before), END)
}
re, err := regexp.Compile(strictPattern)
beforeRegex, err := getStrictRegex(string(before))
if err != nil {
response.Fatal(rsp, errors.Wrapf(err, "cannot compile regex %s", strictPattern))
response.Fatal(rsp, errors.Wrapf(err, "cannot compile regex %s", before))
return rsp, nil
}
keys := []resource.Name{}
for k := range desiredComposed {
if re.MatchString(string(k)) {
if beforeRegex.MatchString(string(k)) {
keys = append(keys, k)
}
}
Expand All @@ -103,11 +96,11 @@ func (f *Function) RunFunction(_ context.Context, req *fnv1beta1.RunFunctionRequ

if desired == 0 || desired != readyResources {
// no resource created
msg := fmt.Sprintf("Delaying creation of resource %q because %q does not exist yet", r, before)
msg := fmt.Sprintf("Delaying creation of resource(s) matching %q because %q does not exist yet", r, before)
if desired > 0 {
// provide a nicer message if there are resources.
msg = fmt.Sprintf(
"Delaying creation of resource %q because %q is not fully ready (%d of %d)",
"Delaying creation of resource(s) matching %q because %q is not fully ready (%d of %d)",
r,
before,
readyResources,
Expand All @@ -116,7 +109,13 @@ func (f *Function) RunFunction(_ context.Context, req *fnv1beta1.RunFunctionRequ
}
response.Normal(rsp, msg)
f.log.Info(msg)
delete(desiredComposed, r)
// find all objects that match the regex and delete them from the desiredComposed map
currentRegex, _ := getStrictRegex(string(r))
for k := range desiredComposed {
if currentRegex.MatchString(string(k)) {
delete(desiredComposed, k)
}
}
break
}
}
Expand All @@ -126,3 +125,13 @@ func (f *Function) RunFunction(_ context.Context, req *fnv1beta1.RunFunctionRequ
rsp.Desired.Resources = nil
return rsp, response.SetDesiredComposedResources(rsp, desiredComposed)
}

func getStrictRegex(pattern string) (*regexp.Regexp, error) {
if !strings.HasPrefix(pattern, START) && !strings.HasSuffix(pattern, END) {
// if the user provides a delimited regex, we'll use it as is
// if not, add the regex with ^ & $ to match the entire string
// possibly avoid using regex for matching literal strings
pattern = fmt.Sprintf("%s%s%s", START, pattern, END)
}
return regexp.Compile(pattern)
}
98 changes: 88 additions & 10 deletions fn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func TestRunFunction(t *testing.T) {
Results: []*fnv1beta1.Result{
{
Severity: fnv1beta1.Severity_SEVERITY_NORMAL,
Message: "Delaying creation of resource \"third\" because \"first\" is not fully ready (0 of 1)",
Message: "Delaying creation of resource(s) matching \"third\" because \"first\" is not fully ready (0 of 1)",
},
},
Desired: &fnv1beta1.State{
Expand Down Expand Up @@ -142,7 +142,7 @@ func TestRunFunction(t *testing.T) {
Results: []*fnv1beta1.Result{
{
Severity: fnv1beta1.Severity_SEVERITY_NORMAL,
Message: "Delaying creation of resource \"second\" because \"first\" does not exist yet",
Message: "Delaying creation of resource(s) matching \"second\" because \"first\" does not exist yet",
},
},
Desired: &fnv1beta1.State{
Expand Down Expand Up @@ -197,7 +197,7 @@ func TestRunFunction(t *testing.T) {
Results: []*fnv1beta1.Result{
{
Severity: fnv1beta1.Severity_SEVERITY_NORMAL,
Message: "Delaying creation of resource \"second\" because \"first\" is not fully ready (0 of 1)",
Message: "Delaying creation of resource(s) matching \"second\" because \"first\" is not fully ready (0 of 1)",
},
},
Desired: &fnv1beta1.State{
Expand Down Expand Up @@ -383,11 +383,11 @@ func TestRunFunction(t *testing.T) {
Results: []*fnv1beta1.Result{
{
Severity: fnv1beta1.Severity_SEVERITY_NORMAL,
Message: "Delaying creation of resource \"second\" because \"first\" is not fully ready (0 of 1)",
Message: "Delaying creation of resource(s) matching \"second\" because \"first\" is not fully ready (0 of 1)",
},
{
Severity: fnv1beta1.Severity_SEVERITY_NORMAL,
Message: "Delaying creation of resource \"fourth\" because \"third\" is not fully ready (0 of 1)",
Message: "Delaying creation of resource(s) matching \"fourth\" because \"third\" is not fully ready (0 of 1)",
},
},
Desired: &fnv1beta1.State{
Expand Down Expand Up @@ -528,7 +528,7 @@ func TestRunFunction(t *testing.T) {
Results: []*fnv1beta1.Result{
{
Severity: fnv1beta1.Severity_SEVERITY_NORMAL,
Message: "Delaying creation of resource \"second\" because \"first\" is not fully ready (0 of 1)",
Message: "Delaying creation of resource(s) matching \"second\" because \"first\" is not fully ready (0 of 1)",
},
},
Desired: &fnv1beta1.State{
Expand Down Expand Up @@ -597,7 +597,7 @@ func TestRunFunction(t *testing.T) {
Results: []*fnv1beta1.Result{
{
Severity: fnv1beta1.Severity_SEVERITY_NORMAL,
Message: "Delaying creation of resource \"second\" because \"first-.*\" is not fully ready (2 of 3)",
Message: "Delaying creation of resource(s) matching \"second\" because \"first-.*\" is not fully ready (2 of 3)",
},
},
Desired: &fnv1beta1.State{
Expand Down Expand Up @@ -679,7 +679,7 @@ func TestRunFunction(t *testing.T) {
Results: []*fnv1beta1.Result{
{
Severity: fnv1beta1.Severity_SEVERITY_NORMAL,
Message: "Delaying creation of resource \"third\" because \"second-.*\" is not fully ready (1 of 2)",
Message: "Delaying creation of resource(s) matching \"third\" because \"second-.*\" is not fully ready (1 of 2)",
},
},
Desired: &fnv1beta1.State{
Expand Down Expand Up @@ -761,7 +761,7 @@ func TestRunFunction(t *testing.T) {
Results: []*fnv1beta1.Result{
{
Severity: fnv1beta1.Severity_SEVERITY_NORMAL,
Message: "Delaying creation of resource \"third\" because \"second-.*\" is not fully ready (1 of 2)",
Message: "Delaying creation of resource(s) matching \"third\" because \"second-.*\" is not fully ready (1 of 2)",
},
},
Desired: &fnv1beta1.State{
Expand All @@ -785,6 +785,84 @@ func TestRunFunction(t *testing.T) {
},
},
},
"SequenceRegexWaitComplex": {
reason: "The function should not modify the sequence regex, since it's already prefixed",
args: args{
req: &fnv1beta1.RunFunctionRequest{
Input: resource.MustStructObject(&v1beta1.Input{
Rules: []v1beta1.SequencingRule{
{
Sequence: []resource.Name{
"first-.*",
"second$",
"third-resource",
},
},
},
}),
Observed: &fnv1beta1.State{
Composite: &fnv1beta1.Resource{
Resource: resource.MustStructJSON(xr),
},
Resources: map[string]*fnv1beta1.Resource{},
},
Desired: &fnv1beta1.State{
Composite: &fnv1beta1.Resource{
Resource: resource.MustStructJSON(xr),
},
Resources: map[string]*fnv1beta1.Resource{
"first-0": {
Resource: resource.MustStructJSON(mr),
Ready: fnv1beta1.Ready_READY_TRUE,
},
"first-1": {
Resource: resource.MustStructJSON(mr),
Ready: fnv1beta1.Ready_READY_FALSE,
},
"0-second": {
Resource: resource.MustStructJSON(mr),
},
"1-second": {
Resource: resource.MustStructJSON(mr),
},
"third-resource": {
Resource: resource.MustStructJSON(mr),
},
},
},
},
},
want: want{
rsp: &fnv1beta1.RunFunctionResponse{
Meta: &fnv1beta1.ResponseMeta{Ttl: durationpb.New(response.DefaultTTL)},
Results: []*fnv1beta1.Result{
{
Severity: fnv1beta1.Severity_SEVERITY_NORMAL,
Message: "Delaying creation of resource(s) matching \"second$\" because \"first-.*\" is not fully ready (1 of 2)",
},
{
Severity: fnv1beta1.Severity_SEVERITY_NORMAL,
Message: "Delaying creation of resource(s) matching \"third-resource\" because \"first-.*\" is not fully ready (1 of 2)",
},
},
Desired: &fnv1beta1.State{
Composite: &fnv1beta1.Resource{
Resource: resource.MustStructJSON(xr),
},
Resources: map[string]*fnv1beta1.Resource{
"first-0": {
Resource: resource.MustStructJSON(mr),
Ready: fnv1beta1.Ready_READY_TRUE,
},
"first-1": {
Resource: resource.MustStructJSON(mr),
Ready: fnv1beta1.Ready_READY_FALSE,
},
},
},
},
},
},
"SequenceRegexAlreadyPrefixed": {
reason: "The function should not modify the sequence regex, since it's already prefixed",
args: args{
Expand Down Expand Up @@ -837,7 +915,7 @@ func TestRunFunction(t *testing.T) {
Results: []*fnv1beta1.Result{
{
Severity: fnv1beta1.Severity_SEVERITY_NORMAL,
Message: "Delaying creation of resource \"fourth\" because \"third-.*$\" is not fully ready (0 of 1)",
Message: "Delaying creation of resource(s) matching \"fourth\" because \"third-.*$\" is not fully ready (0 of 1)",
},
},
Desired: &fnv1beta1.State{
Expand Down