-
Notifications
You must be signed in to change notification settings - Fork 729
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
adding webhook sensor #15
Conversation
59a80f7
to
457f1bd
Compare
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.
finished review. let's go over these changes
controller/sensorjob.go
Outdated
// If signal is of type Webhook, create a service backed by the job | ||
for _, signal := range soc.s.Spec.Signals { | ||
if signal.GetType() == v1alpha1.SignalTypeWebhook { | ||
var targetPort int |
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 the most idiomatic go
would be to initialize the targetPort
as follows:
targetPort := signal.Webhook.Port
if targetPort == 0 {
targetPort = common.DefaultWebhookServiceTargetPort
}
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.
👍
controller/sensorjob.go
Outdated
Name: common.CreateServiceSuffix(soc.s.Name), | ||
Namespace: soc.s.Namespace, | ||
Labels: map[string]string{ | ||
"sensor": soc.s.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.
are these labels used anywhere else? according to the k8s docs:
"Labels are intended to be used to specify identifying attributes of objects that are meaningful and relevant to users"
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.
Its for the user who wants to list the services for webhook sensors or list a particular service for job by using kubectl get with labels
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.
okay, since its 1-1-1 for webhook sensors to jobs and services.. it doesn't really tell you anything more useful than what you expect.
controller/sensorjob.go
Outdated
Labels: map[string]string{ | ||
"sensor": soc.s.Name, | ||
"job": createdJob.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.
seems like we are creating a service
for every sensor... so there will be a one-to-one mapping here. If that's the case, we should attach an ownerReference
to the ObjectMeta
to this particular sensor. However, let's discuss the feasability of my above comment of creating a separate service for every sensor...
soc.log.Infof("created signal executor job '%s'", created.Name) | ||
soc.log.Infof("created signal executor job '%s'", createdJob.Name) | ||
|
||
// If signal is of type Webhook, create a service backed by the job |
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.
should we really be creating a difference service
for every sensor? i understand we would like to be flexible with ports and all that, but it seems a large tradeoff to spin up a service for every sensor instead of forcing all webhook sensors on a particular port. Also a service allows u to expose an internal port to any external one. It seems very unlikely that we would be conflicting on an internal port in the executor...
additionally, we could still have all the flexibility we want on specifying any route 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.
Let's think about a better way to implement the service
job/event.go
Outdated
@@ -77,3 +77,7 @@ func (ae *AbstractEvent) SetError(err error) { | |||
func (ae *AbstractEvent) GetError() error { | |||
return ae.err | |||
} | |||
|
|||
func (ae *AbstractEvent) GetTimestamp() time.Time { |
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 was purposely not implemented because it forces all the non abstract events to implement this method. let's remove this.
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.
ok
|
||
func (e *event) GetSignal() job.Signal { | ||
return e.webhook | ||
} |
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.
let's add the GetTimestamp()
implementation here...
job/webhook/signal.go
Outdated
// Hanlder for the http rest endpoint | ||
func (w *webhook) handler(writer http.ResponseWriter, request *http.Request) { | ||
w.Log.Info("Received a request from", zap.String("host", request.Host)) | ||
if request.Method == common.WebhookHTTPMethod { |
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's OKAY that we only allow POST
methods right now, but ideally this should be able to be specified in the specification. It's not that much more to add, very simple, and standard.
job/webhook/signal.go
Outdated
} | ||
w.events <- event | ||
// Do we want to keep the server running? | ||
go func() { |
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 is a very hacky way to shutdown the webserver.. and it also only works if this method has been fired. we probably need to run a separate goroutine outside of this handler to monitor a channel for a stop
signal. please look at other signal implementations for some ideas
job/webhook/signal_test.go
Outdated
|
||
wg.Add(1) | ||
|
||
go func() { |
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.
why do we need to run this in a separate goroutine
? we can probably just run this in the main thread.
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.
not actually.
@@ -271,6 +275,14 @@ type Kafka struct { | |||
Partition int32 `json:"partition" protobuf:"bytes,3,opt,name=partition"` | |||
} | |||
|
|||
// WebhookSignal is a general purpose REST API |
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 description is a little misleading. its not a general purpose REST API since it only supports POST
methods.. if we add the method to the spec, then it would be more true..
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.
makes sense.
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.
please address the following comments
controller/sensorjob.go
Outdated
@@ -146,6 +144,14 @@ func (soc *sOperationCtx) createSensorExecutorJob() error { | |||
return err | |||
} | |||
soc.log.Infof("Created executor service %s", createdSvc.Name) | |||
// Assign service as owner of sensor | |||
soc.s.OwnerReferences = []metav1.OwnerReference { |
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 owner reference should be for the sensor. in this way, when we delete the sensor, it will remove this service. look at the job implementation for the code and update the comment above
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.
😅
job/webhook/event.go
Outdated
@@ -40,3 +39,7 @@ func (e *event) GetSource() string { | |||
func (e *event) GetSignal() job.Signal { | |||
return e.webhook | |||
} | |||
|
|||
func (e *event) GetTimestamp() time.Time { | |||
return time.Now().UTC() |
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 will return a different timestamp every time this method is called. we need to snapshot the time at which the handler receives the request. i would put the timestamp
field back into the event and just use ...timestamp: time.Now().UTC()...
in the handler's init of event
job/webhook/signal.go
Outdated
@@ -68,15 +60,14 @@ func (w *webhook) Start(events chan job.Event) error { | |||
// Start http server | |||
go func() { | |||
if err := w.server.ListenAndServe(); err != nil { | |||
panic(err) | |||
w.Log.Warn("HTTP server stopped. Cause %v", zap.Error(err)) |
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.
question: does this get logged when we call w.server.Shutdown()
? according to the docs, the method ListenAndServe
always returns a non nil error, but we don't want to log an warning if we actually want to stop the signal. Maybe we can use a boolean flag to indicate if we're actually intending to stop the server.. if the stop flag is not true, we would want to return the error 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.
actually we can check if err was http.ErrServerClosed which will occur when we call ShutDown and then print the shutdown message, else for all other errors invoke panic
job/webhook/signal_test.go
Outdated
assert.NotNil(t, resp, nil) | ||
wg.Done() | ||
break | ||
for { |
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.
couple things here.
- we don't need the
for
loop. - remove the
err != nil
check. in fact, this test is not properly testing the signal with this. we should replace this an `assert.Nil(t, err) - you never actually check for the event on the
testEventChan
, let's add that check after the POST. - you assert the
response
is not nil which is true, but the response is empty.. you never write anything with thewriter
in thehandler
method. should we be responding to these methods? maybe a simple booleanACK
orOK
? - let's add more tests for all the different REST methods and perform the same strict assertions as i mentioned above for the POST
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.
we do need the for loop as the server is started in separate go routine . So you never know when it will start accepting requests.
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.
- maybe a better way is to check for response 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.
okay i ran this test myself without the loop and it worked. we just need to check when the server is ready. a loop is not the right answer 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.
- we should probably just do a
defer writer.WriteHeader(http.StatusOK)
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 worked because the server did start before you made request. a simpler way would be to wait for a few seconds before making request as there is no other way server let you know when it started. Other way is to check if port is bound and accepts connections using "net"
and then make the request
pkg/apis/sensor/v1alpha1/types.go
Outdated
@@ -281,6 +281,8 @@ type WebhookSignal struct { | |||
Endpoint string `json:"endpoint" protobuf:"bytes,1,opt,name=endpoint"` | |||
// Port to listen on | |||
Port int `json:"port" protobuf:"bytes,2,opt,name=port"` | |||
// Method is HTTP method |
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.
we can make this documentation much better. refer to this page: http://www.restapitutorial.com/lessons/httpmethods.html
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.
But I don't think people need a primer on what HTTP methods are.
I guess a good description would be something like, Method is HTTP request method that indicates the desired action to be performed for a given resource
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 wouldn't assume anything about our users. we don't need to copy the description, but maybe just reference a link to the REST API standards.
51983b4
to
98a0e23
Compare
* adding webhook as new type of signal
No description provided.