Commit f806bb06 authored by xmlviking's avatar xmlviking Committed by Trevor Conn

PUT or POST inteval action not work

Fix #1497
Fixed issue with Scheduler POST and PUT HTTP Verbs not supplying JSON body when creating interval actions.
Fixed scheduler rst documentation around the use of interval and interval actions.
Signed-off-by: default avatarxmlviking <ecotter@gmail.com>
parent c745a94a
......@@ -12,7 +12,7 @@ For a description of the architecture, see :doc:`../Ch-Scheduling`
Introduction
============
The following API RESTful Web Services for EdgeX Foundry at this time shows the older development name of "fuse." The EdgeX Foundry name in the software will be updated soon to "edgexfoundry."
The following is and example of the EdgeX Foundry Scheduler Service RESTful API.
https://github.com/edgexfoundry/edgex-go/blob/master/api/raml/support-scheduling.raml
......@@ -26,93 +26,73 @@ https://github.com/edgexfoundry/edgex-go/blob/master/api/raml/support-scheduling
Description
===========
**Scheduler Service** - a service that can be used to schedule invocation of a URL. Requires the use of addressables, schedules, and schedule events.
**Scheduler Service** - a service that can be used to schedule invocation of a URL. Requires the use of interval(s), and interval action(s).
**Addressables**
**Interval(s)**
* **name** - unique name of the service.
* **start** - identifies when the operation starts. Expressed in ISO 8601 YYYYMMDD'T'HHmmss format. Empty means now.
* **end** - identifies when the operation ends. Expressed in ISO 8601 YYYYMMDD'T'HHmmss format. Empty means never
* **frequency** - identifies the interval between invocations. Expressed in ISO 8601 PxYxMxDTxHxMxS format. Empty means no frequency.
identify the called service
**Interval Action(s)**
* **name** - unique name of the interval action.
* **interval** - unique name of an existing interval.
* **target** - the recipient of the interval action (ergo service or name).
* **protocol** - the protocol type to be used to contact the target. (example HTTP).
* **httpMethod** - HTTP protocol verb.
* **address** - the endpoint server host.
* **port** - the desired port.
* **path** - the api path which will be acted on.
* **parameters** - (optional) parameters which will be included in the BODY tag for HttpMethods. Any parameters that should be provided to the call, e.g. {"milliseconds":86400000}
**Schedules**
name - unique name of the service.
start - identifies when the operation starts. Expressed in ISO 8601 YYYYMMDD'T'HHmmss format. Empty means now.
end - identifies when the operation ends. Expressed in ISO 8601 YYYYMMDD'T'HHmmss format. Empty means never
frequency - identifies the interval between invocations. Expressed in ISO 8601 PxYxMxDTxHxMxS format. Empty means no frequency.
**Schedule Events** name - unique name of the event. addressable - address information of the service to invoke parameters - any parameters that should be provided to the call, e.g. {"milliseconds":86400000} service - identifies the service that should execute the event, e.g. fuse-support-scheduler * schedule - associates the event to a schedule
========
Examples
========
Create an Addressable for the service requiring invocation
::
curl -X POST -H "Content-Type: application/json" -H "Cache-Control: no-cache" -d '{
"origin":1234567890,
"name":"pushed events",
"protocol":"HTTP",
"address":"localhost",
"port":48080,
"path":"/api/v1/event/scrub",
"publisher":null,
"user":null,
"password":null,
"topic":null }' "http://localhost:48081/api/v1/addressable"
Create an interval upon which the scheduler will operate
::
curl -X POST -H "Content-Type: application/json" -H "Cache-Control: no-cache" -d '{
"origin":1234567890,
"name":"aged events",
"protocol":"HTTP",
"address":"localhost",
"port":48080,
"path":"/api/v1/event/removeold/age/604800000",
"publisher":null,
"user":null,
"password":null,
"topic":null }' "http://localhost:48081/api/v1/addressable"
curl -X POST -H "Content-Type: application/json" -H "Cache-Control: no-cache" -d '{
"name": "midnight",
"start": "20180101T000000",
"frequency": "P1D"}' "http://localhost:48081/api/v1/interval"
Create a schedule upon which the scheduler will operate
Example of a second interval which will run every 20 seconds
::
curl -X POST -H "Content-Type: application/json" -H "Cache-Control: no-cache" -d '{
"origin":1234567890,
"name":"midnight",
curl -X POST -H "Content-Type: application/json" -H "Cache-Control: no-cache" -d '{
"name": "every20s",
"start":"20000101T000000",
"end":"",
"frequency":"P1D"}' "http://localhost:48081/api/v1/schedule"
Create an event that will use the schedule and invoke the addressable (drive the scrubber)
"frequency":"PT20S"}' "http://localhost:48081/api/v1/interval"
Create an interval action that will invoke the interval action (drive the scrubber) in core-data
::
curl -X POST -H "Content-Type: application/json" -H "Cache-Control: no-cache" -d '{
"origin":1234567890,
"name":"pushed events",
"addressable": { "name" : "pushed events" },
"parameters": null,
"service" : "fuse-support-scheduler",
"schedule":"midnight"}' "http://localhost:48081/api/v1/scheduleevent"
::
curl -X POST -H "Content-Type: application/json" -H "Cache-Control: no-cache" -d '{
"name": "scrub-pushed-events",
"interval": "midnight",
"target": "core-data",
"protocol": "http",
"httpMethod": "DELETE",
"address": "localhost",
"port": 48080,
"path": "/api/v1/event/scrub"}' "http://localhost:48085/api/v1/intervalaction"
curl -X POST -H "Content-Type: application/json" -H "Cache-Control: no-cache" -d '{
"origin":1234567890,
"name":"aged events",
"addressable": { "name" : "aged events" },
"parameters": null,
"service" : "fuse-support-scheduler",
"schedule":"midnight"}' "http://localhost:48081/api/v1/scheduleevent"
For testing update the midnight service to be every 60 seconds
This is a Random-Boolean-Device which created by edgex-device-virtual that connects every 20 seconds.
::
curl -X PUT -H "Content-Type: application/json" -H "Cache-Control: no-cache" -d '{
"name":"midnight",
"frequency":"PT60S"}' "http://localhost:48081/api/v1/schedule"
curl -X POST -H "Content-Type: application/json" -d '{
"name": "put-action",
"interval": "every20s",
"target": "edgex-device-modbus",
"protocol": "http",
"httpMethod": "PUT",
"address": "localhost",
"port": 49990,
"path":"/api/v1/device/name/Random-Boolean-Device/RandomValue_Bool",
"parameters": "{\"RandomValue_Bool\": \"true\",\"EnableRandomization_Bool\": \"true\"}"
}' "http://localhost:48085/api/v1/intervalaction"
\ No newline at end of file
......@@ -7,6 +7,7 @@
package scheduler
import (
"bytes"
"errors"
"fmt"
contract "github.com/edgexfoundry/go-mod-core-contracts/models"
......@@ -336,7 +337,6 @@ func (qc *QueueClient) UpdateIntervalActionQueue(intervalAction contract.Interva
delete(intervalContext.IntervalActionsMap, intervalActionId)
//if there are no more events for the interval, remove the interval context
// TODO: Not sure we want to just remove the interval from the interval context
if len(intervalContext.IntervalActionsMap) == 0 {
LoggingClient.Debug("there are no more events for the interval : " + oldIntervalId + ", remove it.")
deleteIntervalOperation(interval, intervalContext)
......@@ -455,22 +455,13 @@ func execute(context *IntervalContext, wg *sync.WaitGroup) error {
executingUrl := getUrlStr(intervalAction)
LoggingClient.Debug("the event with id : " + eventId + " will request url : " + executingUrl)
//TODO: change the method type based on the event
httpMethod := intervalAction.HTTPMethod
if !validMethod(httpMethod) {
LoggingClient.Error(fmt.Sprintf("net/http: invalid method %q", httpMethod))
return nil
}
req, err := http.NewRequest(httpMethod, executingUrl, nil)
req.Header.Set(ContentTypeKey, ContentTypeJsonValue)
params := strings.TrimSpace(intervalAction.Parameters)
if len(params) > 0 {
req.Header.Set(ContentLengthKey, string(len(params)))
}
req, err := getHttpRequest(httpMethod, executingUrl, intervalAction)
if err != nil {
LoggingClient.Error("create new request occurs error : " + err.Error())
......@@ -498,6 +489,29 @@ func execute(context *IntervalContext, wg *sync.WaitGroup) error {
return nil
}
// EFC We may need to modify this for authorization type in the future
func getHttpRequest(httpMethod string, executingUrl string, intervalAction contract.IntervalAction) (*http.Request, error) {
var body []byte
params := strings.TrimSpace(intervalAction.Parameters)
if len(params) > 0 {
body = []byte(params)
} else {
body = nil
}
req, err := http.NewRequest(httpMethod, executingUrl, bytes.NewBuffer([]byte(body)))
req.Header.Set(ContentTypeKey, ContentTypeJsonValue)
if len(params) > 0 {
req.Header.Set(ContentLengthKey, string(len(params)))
}
if err != nil {
LoggingClient.Error("create new request occurs error : " + err.Error())
}
return req, err
}
func getUrlStr(intervalAction contract.IntervalAction) string {
return intervalAction.GetBaseURL() + intervalAction.Path
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment