Add time trigger cron spec examination tool (#680)
This commit is contained in:
+1
-1
@@ -72,7 +72,7 @@ func MakeBuilder(sharedVolumePath string) *Builder {
|
|||||||
|
|
||||||
func (builder *Builder) VersionHandler(w http.ResponseWriter, r *http.Request) {
|
func (builder *Builder) VersionHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||||
fmt.Fprintf(w, fission.VersionInfo().String())
|
fmt.Fprintf(w, fission.BuildInfo().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (builder *Builder) Handler(w http.ResponseWriter, r *http.Request) {
|
func (builder *Builder) Handler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|||||||
+1
-1
@@ -155,7 +155,7 @@ func (api *API) getLogDBConfig(dbType string) logDBConfig {
|
|||||||
|
|
||||||
func (api *API) HomeHandler(w http.ResponseWriter, r *http.Request) {
|
func (api *API) HomeHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||||
fmt.Fprintf(w, fission.VersionInfo().String())
|
fmt.Fprintf(w, fission.ApiInfo().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) ApiVersionMismatchHandler(w http.ResponseWriter, r *http.Request) {
|
func (api *API) ApiVersionMismatchHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ package client
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -88,3 +90,25 @@ func (c *Client) handleCreateResponse(resp *http.Response) ([]byte, error) {
|
|||||||
body, err := ioutil.ReadAll(resp.Body)
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
return body, err
|
return body, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) ServerInfo() (*fission.ServerInfo, error) {
|
||||||
|
url := fmt.Sprintf(c.Url)
|
||||||
|
resp, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
info := &fission.ServerInfo{}
|
||||||
|
err = json.Unmarshal(body, info)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return info, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ func writeSecretOrConfigMap(dataMap map[string][]byte, dirPath string) error {
|
|||||||
|
|
||||||
func (fetcher *Fetcher) VersionHandler(w http.ResponseWriter, r *http.Request) {
|
func (fetcher *Fetcher) VersionHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||||
fmt.Fprintf(w, fission.VersionInfo().String())
|
fmt.Fprintf(w, fission.BuildInfo().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fetcher *Fetcher) FetchHandler(w http.ResponseWriter, r *http.Request) {
|
func (fetcher *Fetcher) FetchHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ Options:
|
|||||||
--builderMgr Start builder manager.
|
--builderMgr Start builder manager.
|
||||||
--version Print version information
|
--version Print version information
|
||||||
`
|
`
|
||||||
version := fmt.Sprintf("Fission Bundle Version: %v", fission.VersionInfo().String())
|
version := fmt.Sprintf("Fission Bundle Version: %v", fission.BuildInfo().String())
|
||||||
arguments, err := docopt.Parse(usage, nil, true, version, false)
|
arguments, err := docopt.Parse(usage, nil, true, version, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error: %v", err)
|
log.Fatalf("Error: %v", err)
|
||||||
|
|||||||
+14
-28
@@ -18,13 +18,10 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
|
||||||
|
|
||||||
version "github.com/fission/fission"
|
"github.com/fission/fission"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
@@ -47,20 +44,6 @@ func getKubeConfigPath() string {
|
|||||||
return kubeConfig
|
return kubeConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFissionAPIVersion(apiUrl string) (string, error) {
|
|
||||||
resp, err := http.Get(apiUrl)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return strings.TrimRight(string(body), "\n"), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getServerUrl() string {
|
func getServerUrl() string {
|
||||||
var serverUrl string
|
var serverUrl string
|
||||||
// Use FISSION_URL env variable if set; otherwise, port-forward to controller.
|
// Use FISSION_URL env variable if set; otherwise, port-forward to controller.
|
||||||
@@ -87,16 +70,17 @@ func main() {
|
|||||||
app := cli.NewApp()
|
app := cli.NewApp()
|
||||||
app.Name = "fission"
|
app.Name = "fission"
|
||||||
app.Usage = "Serverless functions for Kubernetes"
|
app.Usage = "Serverless functions for Kubernetes"
|
||||||
app.Version = version.Version
|
app.Version = fission.Version
|
||||||
|
|
||||||
cli.VersionPrinter = func(c *cli.Context) {
|
cli.VersionPrinter = func(c *cli.Context) {
|
||||||
clientVer := version.VersionInfo().String()
|
clientVer := fission.BuildInfo().String()
|
||||||
fmt.Printf("Client Version: %v\n", clientVer)
|
fmt.Printf("Client Version: %v\n", clientVer)
|
||||||
serverVer, err := getFissionAPIVersion(getServerUrl())
|
serverInfo, err := getClient(getServerUrl()).ServerInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error getting Fission API version: %v", err)
|
fmt.Printf("Error getting Fission API version: %v", err)
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("Server Version: %v", serverVer)
|
serverVer := serverInfo.Build.String()
|
||||||
|
fmt.Printf("Server Version: %v\n", serverVer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,14 +161,16 @@ func main() {
|
|||||||
|
|
||||||
// timetriggers
|
// timetriggers
|
||||||
ttNameFlag := cli.StringFlag{Name: "name", Usage: "Time Trigger name"}
|
ttNameFlag := cli.StringFlag{Name: "name", Usage: "Time Trigger name"}
|
||||||
ttCronFlag := cli.StringFlag{Name: "cron", Usage: "Time Trigger cron spec ('0 30 * * *', '@every 5m', '@hourly')"}
|
ttCronFlag := cli.StringFlag{Name: "cron", Usage: "Time trigger cron spec with each asterisk representing respectively second, minute, hour, the day of the month, month and day of the week. Also supports readable formats like '@every 5m', '@hourly'"}
|
||||||
ttFnNameFlag := cli.StringFlag{Name: "function", Usage: "Function name"}
|
ttFnNameFlag := cli.StringFlag{Name: "function", Usage: "Function name"}
|
||||||
|
ttRoundFlag := cli.IntFlag{Name: "round", Value: 1, Usage: "Get next N rounds of invocation time"}
|
||||||
ttSubcommands := []cli.Command{
|
ttSubcommands := []cli.Command{
|
||||||
{Name: "create", Aliases: []string{"add"}, Usage: "Create Time trigger", Flags: []cli.Flag{ttNameFlag, ttFnNameFlag, fnNamespaceFlag, ttCronFlag, specSaveFlag}, Action: ttCreate},
|
{Name: "create", Aliases: []string{"add"}, Usage: "Create time trigger", Flags: []cli.Flag{ttNameFlag, ttFnNameFlag, fnNamespaceFlag, ttCronFlag, specSaveFlag}, Action: ttCreate},
|
||||||
{Name: "get", Usage: "Get Time trigger", Flags: []cli.Flag{triggerNamespaceFlag}, Action: ttGet},
|
{Name: "get", Usage: "Get time trigger", Flags: []cli.Flag{triggerNamespaceFlag}, Action: ttGet},
|
||||||
{Name: "update", Usage: "Update Time trigger", Flags: []cli.Flag{ttNameFlag, triggerNamespaceFlag, ttCronFlag, ttFnNameFlag}, Action: ttUpdate},
|
{Name: "update", Usage: "Update time trigger", Flags: []cli.Flag{ttNameFlag, triggerNamespaceFlag, ttCronFlag, ttFnNameFlag}, Action: ttUpdate},
|
||||||
{Name: "delete", Usage: "Delete Time trigger", Flags: []cli.Flag{ttNameFlag, triggerNamespaceFlag}, Action: ttDelete},
|
{Name: "delete", Usage: "Delete time trigger", Flags: []cli.Flag{ttNameFlag, triggerNamespaceFlag}, Action: ttDelete},
|
||||||
{Name: "list", Usage: "List Time triggers", Flags: []cli.Flag{triggerNamespaceFlag}, Action: ttList},
|
{Name: "list", Usage: "List time triggers", Flags: []cli.Flag{triggerNamespaceFlag}, Action: ttList},
|
||||||
|
{Name: "showschedule", Aliases: []string{"show"}, Usage: "Show schedule for cron spec", Flags: []cli.Flag{ttCronFlag, ttRoundFlag}, Action: ttTest},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Message queue trigger
|
// Message queue trigger
|
||||||
|
|||||||
+55
-4
@@ -20,15 +20,42 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/robfig/cron"
|
||||||
"github.com/satori/go.uuid"
|
"github.com/satori/go.uuid"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
"github.com/fission/fission"
|
"github.com/fission/fission"
|
||||||
|
"github.com/fission/fission/controller/client"
|
||||||
"github.com/fission/fission/crd"
|
"github.com/fission/fission/crd"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func getAPITimeInfo(client *client.Client) time.Time {
|
||||||
|
serverInfo, err := client.ServerInfo()
|
||||||
|
if err != nil {
|
||||||
|
fatal(fmt.Sprintf("Error syncing server time information: %v", err))
|
||||||
|
}
|
||||||
|
return serverInfo.ServerTime.CurrentTime
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCronNextNActivationTime(cronSpec string, serverTime time.Time, round int) error {
|
||||||
|
sched, err := cron.Parse(cronSpec)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Current Server Time: \t%v\n", serverTime.Format(time.RFC3339))
|
||||||
|
|
||||||
|
for i := 0; i < round; i++ {
|
||||||
|
serverTime = sched.Next(serverTime)
|
||||||
|
fmt.Printf("Next %v invocation: \t%v\n", i+1, serverTime.Format(time.RFC3339))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func ttCreate(c *cli.Context) error {
|
func ttCreate(c *cli.Context) error {
|
||||||
client := getClient(c.GlobalString("server"))
|
client := getClient(c.GlobalString("server"))
|
||||||
|
|
||||||
@@ -40,11 +67,12 @@ func ttCreate(c *cli.Context) error {
|
|||||||
if len(fnName) == 0 {
|
if len(fnName) == 0 {
|
||||||
fatal("Need a function name to create a trigger, use --function")
|
fatal("Need a function name to create a trigger, use --function")
|
||||||
}
|
}
|
||||||
|
|
||||||
fnNamespace := c.String("fnNamespace")
|
fnNamespace := c.String("fnNamespace")
|
||||||
|
|
||||||
cron := c.String("cron")
|
cronSpec := c.String("cron")
|
||||||
if len(cron) == 0 {
|
if len(cronSpec) == 0 {
|
||||||
fatal("Need a cron spec like '0 30 * * *', '@every 1h30m', or '@hourly'; use --cron")
|
fatal("Need a cron spec like '0 30 * * * *', '@every 1h30m', or '@hourly'; use --cron")
|
||||||
}
|
}
|
||||||
|
|
||||||
tt := &crd.TimeTrigger{
|
tt := &crd.TimeTrigger{
|
||||||
@@ -53,7 +81,7 @@ func ttCreate(c *cli.Context) error {
|
|||||||
Namespace: fnNamespace,
|
Namespace: fnNamespace,
|
||||||
},
|
},
|
||||||
Spec: fission.TimeTriggerSpec{
|
Spec: fission.TimeTriggerSpec{
|
||||||
Cron: cron,
|
Cron: cronSpec,
|
||||||
FunctionReference: fission.FunctionReference{
|
FunctionReference: fission.FunctionReference{
|
||||||
Type: fission.FunctionReferenceTypeFunctionName,
|
Type: fission.FunctionReferenceTypeFunctionName,
|
||||||
Name: fnName,
|
Name: fnName,
|
||||||
@@ -73,6 +101,10 @@ func ttCreate(c *cli.Context) error {
|
|||||||
checkErr(err, "create Time trigger")
|
checkErr(err, "create Time trigger")
|
||||||
|
|
||||||
fmt.Printf("trigger '%v' created\n", name)
|
fmt.Printf("trigger '%v' created\n", name)
|
||||||
|
|
||||||
|
err = getCronNextNActivationTime(cronSpec, getAPITimeInfo(client), 1)
|
||||||
|
checkErr(err, "pass cron spec examination")
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,6 +150,10 @@ func ttUpdate(c *cli.Context) error {
|
|||||||
checkErr(err, "update Time trigger")
|
checkErr(err, "update Time trigger")
|
||||||
|
|
||||||
fmt.Printf("trigger '%v' updated\n", ttName)
|
fmt.Printf("trigger '%v' updated\n", ttName)
|
||||||
|
|
||||||
|
err = getCronNextNActivationTime(newCron, getAPITimeInfo(client), 1)
|
||||||
|
checkErr(err, "pass cron spec examination")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,3 +193,18 @@ func ttList(c *cli.Context) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ttTest(c *cli.Context) error {
|
||||||
|
client := getClient(c.GlobalString("server"))
|
||||||
|
|
||||||
|
round := c.Int("round")
|
||||||
|
cronSpec := c.String("cron")
|
||||||
|
if len(cronSpec) == 0 {
|
||||||
|
fatal("Need a cron spec like '0 30 * * * *', '@every 1h30m', or '@hourly'; use --cron")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := getCronNextNActivationTime(cronSpec, getAPITimeInfo(client), round)
|
||||||
|
checkErr(err, "pass cron spec examination")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
+36
-4
@@ -18,6 +18,7 @@ package fission
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -27,22 +28,53 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
Info struct {
|
BuildMeta struct {
|
||||||
GitCommit string `json:"GitCommit,omitempty"`
|
GitCommit string `json:"GitCommit,omitempty"`
|
||||||
BuildDate string `json:"BuildDate,omitempty"`
|
BuildDate string `json:"BuildDate,omitempty"`
|
||||||
Version string `json:"Version,omitempty"`
|
Version string `json:"Version,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Time struct {
|
||||||
|
Timezone string `json:"Timezone,omitempty"`
|
||||||
|
CurrentTime time.Time `json:"CurrentTime,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerInfo struct {
|
||||||
|
Build BuildMeta `json:"Build,omitempty"`
|
||||||
|
ServerTime Time `json:"ServerTime,omitempty"`
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func VersionInfo() Info {
|
func BuildInfo() BuildMeta {
|
||||||
return Info{
|
return BuildMeta{
|
||||||
GitCommit: GitCommit,
|
GitCommit: GitCommit,
|
||||||
BuildDate: BuildDate,
|
BuildDate: BuildDate,
|
||||||
Version: Version,
|
Version: Version,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (info Info) String() string {
|
func (info BuildMeta) String() string {
|
||||||
|
v, _ := json.Marshal(info)
|
||||||
|
return string(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TimeInfo() Time {
|
||||||
|
t := time.Now()
|
||||||
|
zone, _ := t.Local().Zone()
|
||||||
|
return Time{
|
||||||
|
Timezone: zone,
|
||||||
|
CurrentTime: t,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ApiInfo() ServerInfo {
|
||||||
|
return ServerInfo{
|
||||||
|
Build: BuildInfo(),
|
||||||
|
ServerTime: TimeInfo(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (info ServerInfo) String() string {
|
||||||
v, _ := json.Marshal(info)
|
v, _ := json.Marshal(info)
|
||||||
return string(v)
|
return string(v)
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user