-
Notifications
You must be signed in to change notification settings - Fork 4
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
feat(ingress): automatic host and path discovery #49
base: main
Are you sure you want to change the base?
Conversation
Tests are broken, need fixing and update. |
k8s.checklyhq.com/enabled: "true" | ||
k8s.checklyhq.com/path: "/baz" | ||
# k8s.checklyhq.com/endpoint: "foo.baaz" - Default read from spec.rules[0].host | ||
# k8s.checklyhq.com/success: "200" - Default "200" | ||
# k8s.checklyhq.com/endpoint: "foo.baaz" - Default read from spec.rules[*].host | ||
k8s.checklyhq.com/group: "group-sample" | ||
# k8s.checklyhq.com/muted: "false" # If not set, default "true" | ||
# k8s.checklyhq.com/path: "/baz" - Default read from spec.rules[*].http.paths[*].path | ||
# k8s.checklyhq.com/success: "200" - Default "200" |
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.
With that it seems we can add only once custom endpoint+path+status
. I'd suggest to have one annotation that can define multiple targets. E.g.:
annotations:
k8s.checklyhq.com/api_monitor: "200|https://foo.baaz/baz,301|http://redirect.demo"
Even better, maybe include JSON in the value that is directly tied to API.
JSON for flexibility, simple syntax for UX. Should be decided, but I'd move from ability to set only one endpoint.
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.
100% agree that we need something, not sure what the best path forward is, I'd hate to manage JSON inside YAML..
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.
Then we need to see if we can find best simple abstraction of what we want to achieve here and not be slapped in the face because it does not support some basic functionality. I'd still have API reference in mind here to make sure we cover basics.
What do you propose?
Also, what would be the minimum (original) API JSON request for hostname+path? Just to see verbosity. Benefit here is the ability to support those kind of annotations even in Service resources and documentation is already available.
Seems like the tests are failing still. |
6f1d0cc
to
96bb2e4
Compare
Tests are passing now. |
3117305
to
d48aa93
Compare
* Add ability to create API Checks based on ingress resource host and path entries * Determine how internal resources are linked together * Add logic to add / update / delete internal ApiCheck resources * Small code improvements
* Updated based on the new code updates
* ghcr.io is getting constant rate limits
d48aa93
to
dfad553
Compare
* if the resource annotation is no longer present * if the enabled annotation is changed to false
_, exists := newApiChecksMap[existingApiCheck.Name] | ||
if exists { | ||
if existingApiCheck.Spec == newApiChecksMap[existingApiCheck.Name].Spec { | ||
logger.Info("ApiCheck data is identical, no need for update", "ApiCheck Name", existingApiCheck.Name) | ||
} else { | ||
logger.Info("ApiCheck data is not identical, update needed", "ApiCheck Name", existingApiCheck.Name, "old spec", existingApiCheck.Spec, "new spec", newApiChecksMap[existingApiCheck.Name].Spec) | ||
updateApiChecks = append(updateApiChecks, newApiChecksMap[existingApiCheck.Name]) |
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 think it would be better to just use the map value you've retrieved instead of constantly accessing the value through the map by name, which is prone to mistakes.
_, exists := newApiChecksMap[existingApiCheck.Name] | |
if exists { | |
if existingApiCheck.Spec == newApiChecksMap[existingApiCheck.Name].Spec { | |
logger.Info("ApiCheck data is identical, no need for update", "ApiCheck Name", existingApiCheck.Name) | |
} else { | |
logger.Info("ApiCheck data is not identical, update needed", "ApiCheck Name", existingApiCheck.Name, "old spec", existingApiCheck.Spec, "new spec", newApiChecksMap[existingApiCheck.Name].Spec) | |
updateApiChecks = append(updateApiChecks, newApiChecksMap[existingApiCheck.Name]) | |
newApiCheck, exists := newApiChecksMap[existingApiCheck.Name] | |
if exists { | |
if existingApiCheck.Spec == newApiCheck.Spec { | |
logger.Info("ApiCheck data is identical, no need for update", "ApiCheck Name", existingApiCheck.Name) | |
} else { | |
logger.Info("ApiCheck data is not identical, update needed", "ApiCheck Name", existingApiCheck.Name, "old spec", existingApiCheck.Spec, "new spec", newApiCheck.Spec) | |
updateApiChecks = append(updateApiChecks, newApiCheck) |
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.
Fixed in latest commit.
continue | ||
} | ||
|
||
logger.Info("ApiCheck resource deleted successfully.", apiCheckResource.Name, "Namespace:", apiCheckResource.Namespace) |
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.
Super nitpicky but it would be nice to use a consistent format for log messages. Either always end in punctuation or never do. Also I don't think it's necessary to include the :
in any log key names.
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.
Fixed in latest commit.
continue | ||
} | ||
|
||
logger.Info("ApiCheck resource is present, we need to delete it..", "Ingress Name", ingress.Name, "Ingress namespace", ingress.Namespace) |
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.
Nitpick but you have double punctuation at the end here.
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.
Fixed in latest commit.
labels := make(map[string]*string) | ||
labels["ingress-controller"] = &ingress.Name |
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.
This labels
variable doesn't seem to be used for anything?
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.
It is used when we create the check on checklyhq.com, all labels are added as tags, it helps identifying in the UI where the checks are coming from and in this case, you could see from the tags that it was generated from a specific ingess.
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.
No, I mean that the variable is literally unused. The label map is created, and then a value is set, but then the labels
variable is not used for anything, so there is no way for it to end up in the UI. Frankly I'm a little surprised that Go doesn't complain about the variable being unused.
var host string | ||
if ingress.Annotations[annotationEndpoint] == "" { | ||
host = rule.Host | ||
} else { | ||
host = ingress.Annotations[annotationEndpoint] | ||
} |
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.
So this pattern seem to be quite prevalent in the codebase, if you prefer it the way it is then alright, but I would probably just do this instead:
var host string | |
if ingress.Annotations[annotationEndpoint] == "" { | |
host = rule.Host | |
} else { | |
host = ingress.Annotations[annotationEndpoint] | |
} | |
host := ingress.Annotations[annotationEndpoint] | |
if host == "" { | |
host = rule.Host | |
} |
Always good if you're able to reduce redundant map accesses because it gives you less opportunity to use the wrong key.
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.
Fixed in latest commit.
_, checklyAnnotationExists := ingress.Annotations[annotationEnabled] | ||
if (!checklyAnnotationExists) || (ingress.Annotations[annotationEnabled] == "false") { |
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.
Seems kinda complex. Given how the exists variable is single use here, you might as well just put them in the if
's scope. That way you can give them short generic names and it's not going to pollute entire scope. Also, minus one map access (my favorite).
_, checklyAnnotationExists := ingress.Annotations[annotationEnabled] | |
if (!checklyAnnotationExists) || (ingress.Annotations[annotationEnabled] == "false") { | |
if value, exists := ingress.Annotations[annotationEnabled]; !exists || value == "false" { |
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.
Fixed in latest commit.
}, | ||
Spec: apiCheckSpec, | ||
// Update API checks | ||
if len(updateApiChecks) > 0 { |
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.
You don't really need these len
checks, the for ... range
will work just fine without it. They're not hurting anything but you'd be able to reduce the nesting level which would make the code a bit easier to read.
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.
Fixed in latest commit.
for _, rulePath := range rule.HTTP.Paths { | ||
if ingress.Annotations[annotationPath] == "" { | ||
if rulePath.Path == "" { | ||
paths = append(paths, "/") | ||
} else { | ||
paths = append(paths, rulePath.Path) | ||
} | ||
} else { | ||
paths = append(paths, ingress.Annotations[annotationPath]) | ||
} | ||
} |
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'm not sure if the logic here is correct. It might be, but it seems a little fishy. If there are multiple rule.HTTP.Paths
, then you'll iterate over them, but then if the annotationPath
exists, you add the same value (annotationPath
's value) to paths
in every iteration? Would that not basically just create the exact same check multiple times?
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.
That is correct. I guess the right thing to do is to completely remove the path annotation. Do you agree?
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.
Since the path annotation used to be required, removing it would be a breaking change. I would rather not do that unless there is clear, worthy benefit, and I don't think there is (to be clear the feature in the PR is great, just saying I don't think removing the annotation is warranted). Would the following make sense instead:
If ingress.Annotations[annotationPath]
exists, then we simply append its value to paths
without looping through rule.HTTP.Paths
at all. And if it is not set, then we do loop through rule.HTTP.Paths
like now, except with all the annotation checking removed.
Thoughts?
} else { | ||
logger.Info( | ||
"ApiCheck data is not identical, update needed", "ApiCheck Name", existingApiCheck.Name, "old spec", existingApiCheck.Spec, "new spec", newApiCheck.Spec) | ||
updateApiChecks = append(updateApiChecks, newApiChecksMap[existingApiCheck.Name]) |
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.
updateApiChecks = append(updateApiChecks, newApiChecksMap[existingApiCheck.Name]) | |
updateApiChecks = append(updateApiChecks, newApiCheck) |
path entries