diff --git a/fission/common.go b/fission/common.go index 581273b6..167d1c06 100644 --- a/fission/common.go +++ b/fission/common.go @@ -37,29 +37,10 @@ import ( "github.com/fission/fission" "github.com/fission/fission/controller/client" "github.com/fission/fission/crd" + "github.com/fission/fission/fission/log" storageSvcClient "github.com/fission/fission/storagesvc/client" ) -var ( - // global verbosity of our CLI - verbosity int -) - -func fatal(msg string) { - os.Stderr.WriteString(msg + "\n") - os.Exit(1) -} - -func warn(msg string) { - os.Stderr.WriteString(msg + "\n") -} - -func verbose(msglevel int, format string, args ...interface{}) { - if verbosity >= msglevel { - fmt.Printf(format+"\n", args...) - } -} - func getClient(serverUrl string) *client.Client { if len(serverUrl) == 0 { // starts local portforwarder etc. @@ -78,7 +59,7 @@ func getClient(serverUrl string) *client.Client { func checkErr(err error, msg string) { if err != nil { - fatal(fmt.Sprintf("Failed to %v: %v", msg, err)) + log.Fatal(fmt.Sprintf("Failed to %v: %v", msg, err)) } } @@ -91,7 +72,7 @@ func httpRequest(method, url, body string, headers []string) *http.Response { method != http.MethodDelete && method != http.MethodPost && method != http.MethodPut { - fatal(fmt.Sprintf("Invalid HTTP method '%s'.", method)) + log.Fatal(fmt.Sprintf("Invalid HTTP method '%s'.", method)) } req, err := http.NewRequest(method, url, strings.NewReader(body)) @@ -171,7 +152,7 @@ func createArchive(client *client.Client, fileName string, specFile string) *fis // make a kubernetes client _, kubeClient, _, err := crd.GetKubernetesClient() if err != nil { - fatal(err.Error()) + log.Fatal(err.Error()) } fissionNamespace := os.Getenv("FISSION_NAMESPACE") @@ -179,7 +160,7 @@ func createArchive(client *client.Client, fileName string, specFile string) *fis // get svc end point for storagesvc service, err := kubeClient.CoreV1().Services(fissionNamespace).Get("storagesvc", metav1.GetOptions{}) if err != nil { - fatal(fmt.Sprintf("Error getting storage service object from kubernetes :%v", err.Error())) + log.Fatal(fmt.Sprintf("Error getting storage service object from kubernetes :%v", err.Error())) } u := strings.TrimSuffix(client.Url, "/") + "/proxy/storage" diff --git a/fission/environment.go b/fission/environment.go index 8b33773e..f99af6b2 100644 --- a/fission/environment.go +++ b/fission/environment.go @@ -30,6 +30,7 @@ import ( "github.com/fission/fission" "github.com/fission/fission/controller/client" "github.com/fission/fission/crd" + "github.com/fission/fission/fission/log" ) func getFunctionsByEnvironment(client *client.Client, envName, envNamespace string) ([]crd.Function, error) { @@ -51,13 +52,15 @@ func envCreate(c *cli.Context) error { envName := c.String("name") if len(envName) == 0 { - fatal("Need a name, use --name.") + log.Fatal("Need a name, use --name.") } envNamespace := c.String("envNamespace") envList, err := client.EnvironmentList(envNamespace) if err == nil && len(envList) > 0 { - verbose(2, "%d environment(s) are present in the %s namespace. These environments are not isolated from each other; use separate namespaces if you need isolation.", len(envList), envNamespace) + log.Verbose(2, "%d environment(s) are present in the %s namespace. "+ + "These environments are not isolated from each other; use separate namespaces if you need isolation.", + len(envList), envNamespace) } var poolsize int @@ -69,7 +72,7 @@ func envCreate(c *cli.Context) error { envImg := c.String("image") if len(envImg) == 0 { - fatal("Need an image, use --image.") + log.Fatal("Need an image, use --image.") } envVersion := c.Int("version") @@ -139,7 +142,7 @@ func envGet(c *cli.Context) error { envName := c.String("name") if len(envName) == 0 { - fatal("Need a name, use --name.") + log.Fatal("Need a name, use --name.") } envNamespace := c.String("envNamespace") @@ -163,7 +166,7 @@ func envUpdate(c *cli.Context) error { envName := c.String("name") if len(envName) == 0 { - fatal("Need a name, use --name.") + log.Fatal("Need a name, use --name.") } envNamespace := c.String("envNamespace") @@ -173,7 +176,7 @@ func envUpdate(c *cli.Context) error { envExternalNetwork := c.Bool("externalnetwork") if len(envImg) == 0 && len(envBuilderImg) == 0 && len(envBuildCmd) == 0 { - fatal("Need --image to specify env image, or use --builder to specify env builder, or use --buildcmd to specify new build command.") + log.Fatal("Need --image to specify env image, or use --builder to specify env builder, or use --buildcmd to specify new build command.") } env, err := client.EnvironmentGet(&metav1.ObjectMeta{ @@ -187,7 +190,7 @@ func envUpdate(c *cli.Context) error { } if env.Spec.Version == 1 && (len(envBuilderImg) > 0 || len(envBuildCmd) > 0) { - fatal("Version 1 Environments do not support builders. Must specify --version=2.") + log.Fatal("Version 1 Environments do not support builders. Must specify --version=2.") } if len(envBuilderImg) > 0 { @@ -219,7 +222,7 @@ func envDelete(c *cli.Context) error { envName := c.String("name") if len(envName) == 0 { - fatal("Need a name , use --name.") + log.Fatal("Need a name , use --name.") } envNamespace := c.String("envNamespace") @@ -269,7 +272,7 @@ func getResourceReq(c *cli.Context, resources v1.ResourceRequirements) v1.Resour mincpu := c.Int("mincpu") cpuRequest, err := resource.ParseQuantity(strconv.Itoa(mincpu) + "m") if err != nil { - fatal("Failed to parse mincpu") + log.Fatal("Failed to parse mincpu") } requestResources[v1.ResourceCPU] = cpuRequest } @@ -278,7 +281,7 @@ func getResourceReq(c *cli.Context, resources v1.ResourceRequirements) v1.Resour minmem := c.Int("minmemory") memRequest, err := resource.ParseQuantity(strconv.Itoa(minmem) + "Mi") if err != nil { - fatal("Failed to parse minmemory") + log.Fatal("Failed to parse minmemory") } requestResources[v1.ResourceMemory] = memRequest } @@ -294,7 +297,7 @@ func getResourceReq(c *cli.Context, resources v1.ResourceRequirements) v1.Resour maxcpu := c.Int("maxcpu") cpuLimit, err := resource.ParseQuantity(strconv.Itoa(maxcpu) + "m") if err != nil { - fatal("Failed to parse maxcpu") + log.Fatal("Failed to parse maxcpu") } limitResources[v1.ResourceCPU] = cpuLimit } @@ -303,7 +306,7 @@ func getResourceReq(c *cli.Context, resources v1.ResourceRequirements) v1.Resour maxmem := c.Int("maxmemory") memLimit, err := resource.ParseQuantity(strconv.Itoa(maxmem) + "Mi") if err != nil { - fatal("Failed to parse maxmemory") + log.Fatal("Failed to parse maxmemory") } limitResources[v1.ResourceMemory] = memLimit } diff --git a/fission/function.go b/fission/function.go index ea57e911..cbdbdba6 100644 --- a/fission/function.go +++ b/fission/function.go @@ -36,13 +36,15 @@ import ( "github.com/fission/fission" "github.com/fission/fission/crd" + "github.com/fission/fission/fission/log" "github.com/fission/fission/fission/logdb" + "github.com/fission/fission/fission/portforward" ) func printPodLogs(c *cli.Context) error { fnName := c.String("name") if len(fnName) == 0 { - fatal("Need --name argument.") + log.Fatal("Need --name argument.") } queryURL, err := url.Parse(getServerUrl()) @@ -74,7 +76,7 @@ func getInvokeStrategy(minScale int, maxScale int, executorType string, targetcp } if minScale > maxScale { - fatal("Maxscale must be higher than or equal to minscale") + log.Fatal("Maxscale must be higher than or equal to minscale") } var fnExecutor fission.ExecutorType @@ -86,7 +88,7 @@ func getInvokeStrategy(minScale int, maxScale int, executorType string, targetcp case fission.ExecutorTypeNewdeploy: fnExecutor = fission.ExecutorTypeNewdeploy default: - fatal("Executor type must be one of 'poolmgr' or 'newdeploy', defaults to 'poolmgr'") + log.Fatal("Executor type must be one of 'poolmgr' or 'newdeploy', defaults to 'poolmgr'") } // Right now a simple single case strategy implementation @@ -108,7 +110,7 @@ func getTargetCPU(c *cli.Context) int { if c.IsSet("targetcpu") { targetCPU = c.Int("targetcpu") if targetCPU <= 0 || targetCPU > 100 { - fatal("TargetCPU must be a value between 1 - 100") + log.Fatal("TargetCPU must be a value between 1 - 100") } } else { targetCPU = 80 @@ -125,7 +127,7 @@ func fnCreate(c *cli.Context) error { fnName := c.String("name") if len(fnName) == 0 { - fatal("Need --name argument.") + log.Fatal("Need --name argument.") } // user wants a spec, create a yaml file with package and function @@ -142,7 +144,7 @@ func fnCreate(c *cli.Context) error { // check function existence before creating package for _, fn := range fnList { if fn.Metadata.Name == fnName { - fatal("A function with the same name already exists.") + log.Fatal("A function with the same name already exists.") } } entrypoint := c.String("entrypoint") @@ -168,7 +170,7 @@ func fnCreate(c *cli.Context) error { // need to specify environment for creating new package envName = c.String("env") if len(envName) == 0 { - fatal("Need --env argument.") + log.Fatal("Need --env argument.") } // examine existence of given environment @@ -191,7 +193,7 @@ func fnCreate(c *cli.Context) error { } // fatal when both src & deploy archive are empty if len(srcArchiveName) == 0 && len(deployArchiveName) == 0 { - fatal("Need --deploy or --src argument.") + log.Fatal("Need --deploy or --src argument.") } buildcmd := c.String("buildcmd") @@ -204,7 +206,7 @@ func fnCreate(c *cli.Context) error { resourceReq := getResourceReq(c, apiv1.ResourceRequirements{}) if (c.IsSet("mincpu") || c.IsSet("maxcpu") || c.IsSet("minmemory") || c.IsSet("maxmemory")) && invokeStrategy.ExecutionStrategy.ExecutorType == fission.ExecutorTypePoolmgr { - warn("CPU/Memory specified for function with pool manager executor will be ignored in favor of resources specified at environment") + log.Warn("CPU/Memory specified for function with pool manager executor will be ignored in favor of resources specified at environment") } var secrets []fission.SecretReference @@ -217,7 +219,7 @@ func fnCreate(c *cli.Context) error { Name: secretName, }) if k8serrors.IsNotFound(err) { - warn(fmt.Sprintf("Secret %s not found in Namespace: %s. Secret needs to be present in the same namespace as function", secretName, fnNamespace)) + log.Warn(fmt.Sprintf("Secret %s not found in Namespace: %s. Secret needs to be present in the same namespace as function", secretName, fnNamespace)) } newSecret := fission.SecretReference{ @@ -234,7 +236,7 @@ func fnCreate(c *cli.Context) error { Name: cfgMapName, }) if k8serrors.IsNotFound(err) { - warn(fmt.Sprintf("ConfigMap %s not found in Namespace: %s. ConfigMap needs to be present in the same namespace as function", cfgMapName, fnNamespace)) + log.Warn(fmt.Sprintf("ConfigMap %s not found in Namespace: %s. ConfigMap needs to be present in the same namespace as function", cfgMapName, fnNamespace)) } newCfgMap := fission.ConfigMapReference{ @@ -322,7 +324,7 @@ func fnGet(c *cli.Context) error { fnName := c.String("name") if len(fnName) == 0 { - fatal("Need name of function, use --name") + log.Fatal("Need name of function, use --name") } fnNamespace := c.String("fnNamespace") m := &metav1.ObjectMeta{ @@ -347,7 +349,7 @@ func fnGetMeta(c *cli.Context) error { fnName := c.String("name") if len(fnName) == 0 { - fatal("Need name of function, use --name") + log.Fatal("Need name of function, use --name") } fnNamespace := c.String("fnNamespace") @@ -371,16 +373,16 @@ func fnUpdate(c *cli.Context) error { client := getClient(c.GlobalString("server")) if len(c.String("package")) > 0 { - fatal("--package is deprecated, please use --deploy instead.") + log.Fatal("--package is deprecated, please use --deploy instead.") } if len(c.String("srcpkg")) > 0 { - fatal("--srcpkg is deprecated, please use --src instead.") + log.Fatal("--srcpkg is deprecated, please use --src instead.") } fnName := c.String("name") if len(fnName) == 0 { - fatal("Need name of function, use --name") + log.Fatal("Need name of function, use --name") } fnNamespace := c.String("fnNamespace") @@ -406,12 +408,12 @@ func fnUpdate(c *cli.Context) error { cfgMapName := c.String("configmap") if len(srcArchiveName) > 0 && len(deployArchiveName) > 0 { - fatal("Need either of --src or --deploy and not both arguments.") + log.Fatal("Need either of --src or --deploy and not both arguments.") } if len(secretName) > 0 { if len(function.Spec.Secrets) > 1 { - fatal("Please use 'fission spec apply' to update list of secrets") + log.Fatal("Please use 'fission spec apply' to update list of secrets") } // check that the referenced secret is in the same ns as the function, if not give a warning. @@ -420,7 +422,7 @@ func fnUpdate(c *cli.Context) error { Name: secretName, }) if k8serrors.IsNotFound(err) { - warn(fmt.Sprintf("secret %s not found in Namespace: %s. Secret needs to be present in the same namespace as function", secretName, fnNamespace)) + log.Warn(fmt.Sprintf("secret %s not found in Namespace: %s. Secret needs to be present in the same namespace as function", secretName, fnNamespace)) } newSecret := fission.SecretReference{ @@ -432,7 +434,7 @@ func fnUpdate(c *cli.Context) error { if len(cfgMapName) > 0 { if len(function.Spec.ConfigMaps) > 1 { - fatal("Please use 'fission spec apply' to update list of configmaps") + log.Fatal("Please use 'fission spec apply' to update list of configmaps") } // check that the referenced cfgmap is in the same ns as the function, if not give a warning. @@ -441,7 +443,7 @@ func fnUpdate(c *cli.Context) error { Name: cfgMapName, }) if k8serrors.IsNotFound(err) { - warn(fmt.Sprintf("ConfigMap %s not found in Namespace: %s. ConfigMap needs to be present in the same namespace as the function", cfgMapName, fnNamespace)) + log.Warn(fmt.Sprintf("ConfigMap %s not found in Namespace: %s. ConfigMap needs to be present in the same namespace as the function", cfgMapName, fnNamespace)) } newCfgMap := fission.ConfigMapReference{ @@ -476,7 +478,7 @@ func fnUpdate(c *cli.Context) error { checkErr(err, "get function list") if !force && len(fnList) > 1 { - fatal("Package is used by multiple functions, use --force to force update") + log.Fatal("Package is used by multiple functions, use --force to force update") } pkgMetadata = updatePackage(client, pkg, envName, envNamespace, srcArchiveName, deployArchiveName, buildcmd) @@ -515,11 +517,11 @@ func fnUpdate(c *cli.Context) error { minscale := c.Int("minscale") maxscale := c.Int("maxscale") if c.IsSet("maxscale") && minscale > c.Int("maxscale") { - fatal(fmt.Sprintf("Minscale's value %v can not be greater than maxscale value %v", minscale, maxscale)) + log.Fatal(fmt.Sprintf("Minscale's value %v can not be greater than maxscale value %v", minscale, maxscale)) } if function.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType != fission.ExecutorTypePoolmgr && minscale > function.Spec.InvokeStrategy.ExecutionStrategy.MaxScale { - fatal(fmt.Sprintf("Minscale provided: %v can not be greater than maxscale of existing function: %v", minscale, + log.Fatal(fmt.Sprintf("Minscale provided: %v can not be greater than maxscale of existing function: %v", minscale, function.Spec.InvokeStrategy.ExecutionStrategy.MaxScale)) } function.Spec.InvokeStrategy.ExecutionStrategy.MinScale = minscale @@ -528,7 +530,7 @@ func fnUpdate(c *cli.Context) error { if c.IsSet("maxscale") { maxscale := c.Int("maxscale") if maxscale < function.Spec.InvokeStrategy.ExecutionStrategy.MinScale { - fatal(fmt.Sprintf("Function's minscale: %v can not be greater than maxscale provided: %v", + log.Fatal(fmt.Sprintf("Function's minscale: %v can not be greater than maxscale provided: %v", function.Spec.InvokeStrategy.ExecutionStrategy.MinScale, maxscale)) } function.Spec.InvokeStrategy.ExecutionStrategy.MaxScale = maxscale @@ -544,11 +546,11 @@ func fnUpdate(c *cli.Context) error { case fission.ExecutorTypeNewdeploy: fnExecutor = fission.ExecutorTypeNewdeploy default: - fatal("Executor type must be one of 'poolmgr' or 'newdeploy', defaults to 'poolmgr'") + log.Fatal("Executor type must be one of 'poolmgr' or 'newdeploy', defaults to 'poolmgr'") } if (c.IsSet("mincpu") || c.IsSet("maxcpu") || c.IsSet("minmemory") || c.IsSet("maxmemory")) && fnExecutor == fission.ExecutorTypePoolmgr { - warn("CPU/Memory specified for function with pool manager executor will be ignored in favor of resources specified at environment") + log.Warn("CPU/Memory specified for function with pool manager executor will be ignored in favor of resources specified at environment") } function.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType = fnExecutor } @@ -565,7 +567,7 @@ func fnDelete(c *cli.Context) error { fnName := c.String("name") if len(fnName) == 0 { - fatal("Need name of function, use --name") + log.Fatal("Need name of function, use --name") } fnNamespace := c.String("fnNamespace") @@ -616,7 +618,7 @@ func fnLogs(c *cli.Context) error { fnName := c.String("name") if len(fnName) == 0 { - fatal("Need name of function, use --name") + log.Fatal("Need name of function, use --name") } fnNamespace := c.String("fnNamespace") @@ -642,7 +644,7 @@ func fnLogs(c *cli.Context) error { // request the controller to establish a proxy server to the database. logDB, err := logdb.GetLogDB(dbType, getServerUrl()) if err != nil { - fatal("failed to connect log database") + log.Fatal("failed to connect log database") } requestChan := make(chan struct{}) @@ -663,7 +665,7 @@ func fnLogs(c *cli.Context) error { } logEntries, err := logDB.GetLogs(logFilter) if err != nil { - fatal("failed to query logs") + log.Fatal("failed to query logs") } for _, logEntry := range logEntries { if c.Bool("d") { @@ -695,14 +697,14 @@ func fnLogs(c *cli.Context) error { func fnTest(c *cli.Context) error { fnName := c.String("name") if len(fnName) == 0 { - fatal("Need function name to be specified with --name") + log.Fatal("Need function name to be specified with --name") } ns := c.String("fnNamespace") routerURL := os.Getenv("FISSION_ROUTER") if len(routerURL) == 0 { // Portforward to the fission router - localRouterPort := setupPortForward(getKubeConfigPath(), + localRouterPort := portforward.Setup(getKubeConfigPath(), getFissionNamespace(), "application=fission-router") routerURL = "127.0.0.1:" + localRouterPort } else { diff --git a/fission/httptrigger.go b/fission/httptrigger.go index 820d9a30..f021fd87 100644 --- a/fission/httptrigger.go +++ b/fission/httptrigger.go @@ -30,6 +30,7 @@ import ( "github.com/fission/fission" "github.com/fission/fission/controller/client" "github.com/fission/fission/crd" + "github.com/fission/fission/fission/log" ) // returns one of http.Method* @@ -54,7 +55,7 @@ func getMethod(method string) string { case "TRACE": return http.MethodTrace } - fatal(fmt.Sprintf("Invalid HTTP Method %v", method)) + log.Fatal(fmt.Sprintf("Invalid HTTP Method %v", method)) return "" } @@ -75,13 +76,13 @@ func htCreate(c *cli.Context) error { fnName := c.String("function") if len(fnName) == 0 { - fatal("Need a function name to create a trigger, use --function") + log.Fatal("Need a function name to create a trigger, use --function") } fnNamespace := c.String("fnNamespace") triggerUrl := c.String("url") if len(triggerUrl) == 0 { - fatal("Need a trigger URL, use --url") + log.Fatal("Need a trigger URL, use --url") } if !strings.HasPrefix(triggerUrl, "/") { triggerUrl = fmt.Sprintf("/%s", triggerUrl) @@ -143,14 +144,14 @@ func htUpdate(c *cli.Context) error { client := getClient(c.GlobalString("server")) htName := c.String("name") if len(htName) == 0 { - fatal("Need name of trigger, use --name") + log.Fatal("Need name of trigger, use --name") } triggerNamespace := c.String("triggerNamespace") // update function ref newFn := c.String("function") if len(newFn) == 0 { - fatal("Nothing to update. Use --function to specify a new function.") + log.Fatal("Nothing to update. Use --function to specify a new function.") } checkFunctionExistence(client, newFn, triggerNamespace) @@ -184,7 +185,7 @@ func htDelete(c *cli.Context) error { client := getClient(c.GlobalString("server")) htName := c.String("name") if len(htName) == 0 { - fatal("Need name of trigger to delete, use --name") + log.Fatal("Need name of trigger to delete, use --name") } triggerNamespace := c.String("triggerNamespace") diff --git a/fission/log/log.go b/fission/log/log.go new file mode 100644 index 00000000..ceba041a --- /dev/null +++ b/fission/log/log.go @@ -0,0 +1,42 @@ +/* +Copyright 2016 The Fission Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package log + +import ( + "fmt" + "os" +) + +var ( + // global Verbosity of our CLI + Verbosity int +) + +func Fatal(msg interface{}) { + os.Stderr.WriteString(fmt.Sprintf("%v\n", msg)) + os.Exit(1) +} + +func Warn(msg interface{}) { + os.Stderr.WriteString(fmt.Sprintf("%v\n", msg)) +} + +func Verbose(verbosityLevel int, format string, args ...interface{}) { + if Verbosity >= verbosityLevel { + fmt.Printf(format+"\n", args...) + } +} diff --git a/fission/main.go b/fission/main.go index 53b649e1..4b22105c 100644 --- a/fission/main.go +++ b/fission/main.go @@ -22,6 +22,8 @@ import ( "path/filepath" "github.com/fission/fission" + "github.com/fission/fission/fission/log" + "github.com/fission/fission/fission/portforward" "github.com/urfave/cli" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -38,7 +40,8 @@ func getKubeConfigPath() string { kubeConfig = filepath.Join(home, ".kube", "config") if _, err := os.Stat(kubeConfig); os.IsNotExist(err) { - fatal("Couldn't find kubeconfig file. Set the KUBECONFIG environment variable to your kubeconfig's path.") + log.Fatal("Couldn't find kubeconfig file. " + + "Set the KUBECONFIG environment variable to your kubeconfig's path.") } } return kubeConfig @@ -51,8 +54,7 @@ func getServerUrl() string { if len(fissionUrl) == 0 { fissionNamespace := getFissionNamespace() kubeConfig := getKubeConfigPath() - localPort := setupPortForward( - kubeConfig, fissionNamespace, "application=fission-api") + localPort := portforward.Setup(kubeConfig, fissionNamespace, "application=fission-api") serverUrl = "http://127.0.0.1:" + localPort } else { serverUrl = fissionUrl @@ -61,8 +63,8 @@ func getServerUrl() string { } func cliHook(c *cli.Context) error { - verbosity = c.Int("verbosity") - verbose(2, "Verbosity = 2") + log.Verbosity = c.Int("verbosity") + log.Verbose(2, "Verbosity = 2") return nil } diff --git a/fission/mqtrigger.go b/fission/mqtrigger.go index 34d79bdd..b09ad18b 100644 --- a/fission/mqtrigger.go +++ b/fission/mqtrigger.go @@ -27,6 +27,7 @@ import ( "github.com/fission/fission" "github.com/fission/fission/crd" + "github.com/fission/fission/fission/log" fv1 "github.com/fission/fission/pkg/apis/fission.io/v1" ) @@ -39,7 +40,7 @@ func mqtCreate(c *cli.Context) error { } fnName := c.String("function") if len(fnName) == 0 { - fatal("Need a function name to create a trigger, use --function") + log.Fatal("Need a function name to create a trigger, use --function") } fnNamespace := c.String("fnNamespace") @@ -52,20 +53,20 @@ func mqtCreate(c *cli.Context) error { case fission.MessageQueueTypeASQ: mqType = fission.MessageQueueTypeASQ default: - fatal("Unknown message queue type, currently only \"nats-streaming, azure-storage-queue \" is supported") + log.Fatal("Unknown message queue type, currently only \"nats-streaming, azure-storage-queue \" is supported") } // TODO: check topic availability topic := c.String("topic") if len(topic) == 0 { - fatal("Listen topic cannot be empty") + log.Fatal("Listen topic cannot be empty") } respTopic := c.String("resptopic") if topic == respTopic { // TODO maybe this should just be a warning, perhaps // allow it behind a --force flag - fatal("Listen topic should not equal to response topic") + log.Fatal("Listen topic should not equal to response topic") } contentType := c.String("contenttype") @@ -115,7 +116,7 @@ func mqtUpdate(c *cli.Context) error { client := getClient(c.GlobalString("server")) mqtName := c.String("name") if len(mqtName) == 0 { - fatal("Need name of trigger, use --name") + log.Fatal("Need name of trigger, use --name") } mqtNs := c.String("triggerns") @@ -153,7 +154,7 @@ func mqtUpdate(c *cli.Context) error { } if !updated { - fatal("Nothing to update. Use --topic, --resptopic, or --function.") + log.Fatal("Nothing to update. Use --topic, --resptopic, or --function.") } _, err = client.MessageQueueTriggerUpdate(mqt) @@ -167,7 +168,7 @@ func mqtDelete(c *cli.Context) error { client := getClient(c.GlobalString("server")) mqtName := c.String("name") if len(mqtName) == 0 { - fatal("Need name of trigger to delete, use --name") + log.Fatal("Need name of trigger to delete, use --name") } mqtNs := c.String("triggerns") @@ -204,7 +205,7 @@ func mqtList(c *cli.Context) error { func checkMQTopicAvailability(mqType fission.MessageQueueType, topics ...string) { for _, t := range topics { if len(t) > 0 && !fv1.IsTopicValid(mqType, t) { - fatal(fmt.Sprintf("Invalid topic for %s: %s", mqType, t)) + log.Fatal(fmt.Sprintf("Invalid topic for %s: %s", mqType, t)) } } } diff --git a/fission/package.go b/fission/package.go index 6528c551..2503519a 100644 --- a/fission/package.go +++ b/fission/package.go @@ -31,6 +31,7 @@ import ( "github.com/fission/fission" "github.com/fission/fission/controller/client" "github.com/fission/fission/crd" + "github.com/fission/fission/fission/log" ) func getFunctionsByPackage(client *client.Client, pkgName, pkgNamespace string) ([]crd.Function, error) { @@ -68,7 +69,7 @@ func pkgCreate(c *cli.Context) error { pkgNamespace := c.String("pkgNamespace") envName := c.String("env") if len(envName) == 0 { - fatal("Need --env argument.") + log.Fatal("Need --env argument.") } envNamespace := c.String("envNamespace") srcArchiveName := c.String("src") @@ -76,7 +77,7 @@ func pkgCreate(c *cli.Context) error { buildcmd := c.String("buildcmd") if len(srcArchiveName) == 0 && len(deployArchiveName) == 0 { - fatal("Need --src to specify source archive, or use --deploy to specify deployment archive.") + log.Fatal("Need --src to specify source archive, or use --deploy to specify deployment archive.") } meta := createPackage(client, pkgNamespace, envName, envNamespace, srcArchiveName, deployArchiveName, buildcmd, "") @@ -90,7 +91,7 @@ func pkgUpdate(c *cli.Context) error { pkgName := c.String("name") if len(pkgName) == 0 { - fatal("Need --name argument.") + log.Fatal("Need --name argument.") } pkgNamespace := c.String("pkgNamespace") @@ -102,12 +103,12 @@ func pkgUpdate(c *cli.Context) error { buildcmd := c.String("buildcmd") if len(srcArchiveName) > 0 && len(deployArchiveName) > 0 { - fatal("Need either of --src or --deploy and not both arguments.") + log.Fatal("Need either of --src or --deploy and not both arguments.") } if len(srcArchiveName) == 0 && len(deployArchiveName) == 0 && len(envName) == 0 && len(buildcmd) == 0 { - fatal("Need --env or --src or --deploy or --buildcmd argument.") + log.Fatal("Need --env or --src or --deploy or --buildcmd argument.") } pkg, err := client.PackageGet(&metav1.ObjectMeta{ @@ -120,7 +121,7 @@ func pkgUpdate(c *cli.Context) error { checkErr(err, "get function list") if !force && len(fnList) > 1 { - fatal("Package is used by multiple functions, use --force to force update") + log.Fatal("Package is used by multiple functions, use --force to force update") } newPkgMeta := updatePackage(client, pkg, @@ -185,7 +186,7 @@ func pkgSourceGet(c *cli.Context) error { pkgName := c.String("name") if len(pkgName) == 0 { - fatal("Need name of package, use --name") + log.Fatal("Need name of package, use --name") } pkgNamespace := c.String("pkgNamespace") @@ -222,7 +223,7 @@ func pkgDeployGet(c *cli.Context) error { pkgName := c.String("name") if len(pkgName) == 0 { - fatal("Need name of package, use --name") + log.Fatal("Need name of package, use --name") } pkgNamespace := c.String("pkgNamespace") @@ -259,7 +260,7 @@ func pkgInfo(c *cli.Context) error { pkgName := c.String("name") if len(pkgName) == 0 { - fatal("Need name of package, use --name") + log.Fatal("Need name of package, use --name") } pkgNamespace := c.String("pkgNamespace") @@ -369,7 +370,7 @@ func pkgDelete(c *cli.Context) error { fnList, err := getFunctionsByPackage(client, pkgName, pkgNamespace) if !force && len(fnList) > 0 { - fatal("Package is used by at least one function, use -f to force delete") + log.Fatal("Package is used by at least one function, use -f to force delete") } err = deletePackage(client, pkgName, pkgNamespace) diff --git a/fission/portforward.go b/fission/portforward/portforward.go similarity index 63% rename from fission/portforward.go rename to fission/portforward/portforward.go index 2205e2d7..19c5e357 100644 --- a/fission/portforward.go +++ b/fission/portforward/portforward.go @@ -1,4 +1,20 @@ -package main +/* +Copyright 2016 The Fission Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package portforward import ( "fmt" @@ -14,8 +30,60 @@ import ( "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/portforward" "k8s.io/client-go/transport/spdy" + + "github.com/fission/fission/fission/log" ) +// Port forward a free local port to a pod on the cluster. The pod is +// found in the specified namespace by labelSelector. The pod's port +// is found by looking for a service in the same namespace and using +// its targetPort. Once the port forward is started, wait for it to +// start accepting connections before returning. +func Setup(kubeConfig, namespace, labelSelector string) string { + log.Verbose(2, "Setting up port forward to %s in namespace %s using the kubeconfig at %s", + labelSelector, namespace, kubeConfig) + + localPort, err := findFreePort() + if err != nil { + log.Fatal(fmt.Sprintf("Error finding unused port :%v", err.Error())) + } + + log.Verbose(2, "Waiting for local port %v", localPort) + for { + conn, _ := net.DialTimeout("tcp", + net.JoinHostPort("", localPort), time.Millisecond) + if conn != nil { + conn.Close() + } else { + break + } + time.Sleep(time.Millisecond * 50) + } + + log.Verbose(2, "Starting port forward from local port %v", localPort) + go func() { + err := runPortForward(kubeConfig, labelSelector, localPort, namespace) + if err != nil { + log.Fatal(fmt.Sprintf("Error forwarding to controller port: %s", err.Error())) + } + }() + + log.Verbose(2, "Waiting for port forward %v to start...", localPort) + for { + conn, _ := net.DialTimeout("tcp", + net.JoinHostPort("", localPort), time.Millisecond) + if conn != nil { + conn.Close() + break + } + time.Sleep(time.Millisecond * 50) + } + + log.Verbose(2, "Port forward from local port %v started", localPort) + + return localPort +} + func findFreePort() (string, error) { listener, err := net.Listen("tcp", ":0") if err != nil { @@ -33,29 +101,29 @@ func findFreePort() (string, error) { } // runPortForward creates a local port forward to the specified pod -func runPortForward(kubeConfig string, labelSelector string, localPort string, fissionNamespace string) error { +func runPortForward(kubeConfig string, labelSelector string, localPort string, ns string) error { config, err := clientcmd.BuildConfigFromFlags("", kubeConfig) if err != nil { - fatal(fmt.Sprintf("Failed to connect to Kubernetes: %s", err)) + log.Fatal(fmt.Sprintf("Failed to connect to Kubernetes: %s", err)) } clientset, err := kubernetes.NewForConfig(config) if err != nil { - fatal(fmt.Sprintf("Failed to connect to Kubernetes: %s", err)) + log.Fatal(fmt.Sprintf("Failed to connect to Kubernetes: %s", err)) } - verbose(2, "Connected to Kubernetes API") + log.Verbose(2, "Connected to Kubernetes API") - // if fission namespace is unset, try to find a fission pod in any namespace - if len(fissionNamespace) == 0 { - fissionNamespace = meta_v1.NamespaceAll + // if namespace is unset, try to find a pod in any namespace + if len(ns) == 0 { + ns = meta_v1.NamespaceAll } // get the pod; if there is more than one, ask the user to disambiguate - podList, err := clientset.CoreV1().Pods(fissionNamespace). + podList, err := clientset.CoreV1().Pods(ns). List(meta_v1.ListOptions{LabelSelector: labelSelector}) if err != nil || len(podList.Items) == 0 { - fatal("Error getting controller pod for port-forwarding") + log.Fatal("Error getting controller pod for port-forwarding") } // make a useful error message if there is more than one install @@ -64,7 +132,7 @@ func runPortForward(kubeConfig string, labelSelector string, localPort string, f for _, p := range podList.Items { namespaces = append(namespaces, p.Namespace) } - fatal(fmt.Sprintf("Found %v fission installs, set FISSION_NAMESPACE to one of: %v", + log.Fatal(fmt.Sprintf("Found %v fission installs, set FISSION_NAMESPACE to one of: %v", len(podList.Items), strings.Join(namespaces, " "))) } @@ -76,10 +144,10 @@ func runPortForward(kubeConfig string, labelSelector string, localPort string, f svcs, err := clientset.CoreV1().Services(podNameSpace). List(meta_v1.ListOptions{LabelSelector: labelSelector}) if err != nil { - fatal(fmt.Sprintf("Error getting %v service :%v", labelSelector, err.Error())) + log.Fatal(fmt.Sprintf("Error getting %v service :%v", labelSelector, err.Error())) } if len(svcs.Items) == 0 { - fatal(fmt.Sprintf("Service %v not found", labelSelector)) + log.Fatal(fmt.Sprintf("Service %v not found", labelSelector)) } service := &svcs.Items[0] @@ -87,7 +155,7 @@ func runPortForward(kubeConfig string, labelSelector string, localPort string, f for _, servicePort := range service.Spec.Ports { targetPort = servicePort.TargetPort.String() } - verbose(2, "Connecting to port %v on pod %v/%v", targetPort, podNameSpace, podNameSpace) + log.Verbose(2, "Connecting to port %v on pod %v/%v", targetPort, podNameSpace, podNameSpace) stopChannel := make(chan struct{}, 1) readyChannel := make(chan struct{}) @@ -105,70 +173,20 @@ func runPortForward(kubeConfig string, labelSelector string, localPort string, f transport, upgrader, err := spdy.RoundTripperFor(config) if err != nil { msg := fmt.Sprintf("Failed to connect to Fission service on Kubernetes: %v", err.Error()) - fatal(msg) + log.Fatal(msg) } dialer := spdy.NewDialer(upgrader, &http.Client{Transport: transport}, "POST", url) outStream := os.Stdout - if verbosity < 2 { + if log.Verbosity < 2 { outStream = nil } fw, err := portforward.New(dialer, ports, stopChannel, readyChannel, outStream, os.Stderr) if err != nil { msg := fmt.Sprintf("portforward.new errored out :%v", err.Error()) - fatal(msg) + log.Fatal(msg) } - verbose(2, "Starting port forwarder") + log.Verbose(2, "Starting port forwarder") return fw.ForwardPorts() } - -// Port forward a free local port to a pod on the cluster. The pod is -// found in the specified namespace by labelSelector. The pod's port -// is found by looking for a service in the same namespace and using -// its targetPort. Once the port forward is started, wait for it to -// start accepting connections before returning. -func setupPortForward(kubeConfig, namespace, labelSelector string) string { - verbose(2, "Setting up port forward to %s in namespace %s using the kubeconfig at %s", - labelSelector, namespace, kubeConfig) - - localPort, err := findFreePort() - if err != nil { - fatal(fmt.Sprintf("Error finding unused port :%v", err.Error())) - } - - verbose(2, "Waiting for local port %v", localPort) - for { - conn, _ := net.DialTimeout("tcp", - net.JoinHostPort("", localPort), time.Millisecond) - if conn != nil { - conn.Close() - } else { - break - } - time.Sleep(time.Millisecond * 50) - } - - verbose(2, "Starting port forward from local port %v", localPort) - go func() { - err := runPortForward(kubeConfig, labelSelector, localPort, namespace) - if err != nil { - fatal(fmt.Sprintf("Error forwarding to controller port: %s", err.Error())) - } - }() - - verbose(2, "Waiting for port forward %v to start...", localPort) - for { - conn, _ := net.DialTimeout("tcp", - net.JoinHostPort("", localPort), time.Millisecond) - if conn != nil { - conn.Close() - break - } - time.Sleep(time.Millisecond * 50) - } - - verbose(2, "Port forward from local port %v started", localPort) - - return localPort -} diff --git a/fission/spec.go b/fission/spec.go index cc9bfb39..6e894038 100644 --- a/fission/spec.go +++ b/fission/spec.go @@ -39,6 +39,7 @@ import ( "github.com/fission/fission" "github.com/fission/fission/controller/client" "github.com/fission/fission/crd" + "github.com/fission/fission/fission/log" ) const SPEC_API_VERSION = "fission.io/v1" @@ -503,7 +504,7 @@ func (fr *FissionResources) parseYaml(b []byte, loc *location) error { default: // no need to error out just because there's some extra files around; // also good for compatibility. - warn(fmt.Sprintf("Ignoring unknown type %v in %v", tm.Kind, loc)) + log.Warn(fmt.Sprintf("Ignoring unknown type %v in %v", tm.Kind, loc)) } // add to source map, check for duplicates @@ -523,7 +524,8 @@ func readSpecs(specDir string) (*FissionResources, error) { // make sure spec directory exists before continue if _, err := os.Stat(specDir); os.IsNotExist(err) { - fatal(fmt.Sprintf("Spec directory %v doesn't exist. Please check directory path or run \"fission spec init\" to create it.", specDir)) + log.Fatal(fmt.Sprintf("Spec directory %v doesn't exist. "+ + "Please check directory path or run \"fission spec init\" to create it.", specDir)) } fr := FissionResources{ @@ -950,7 +952,7 @@ func localArchiveFromSpec(specDir string, aus *ArchiveUploadSpec) (*fission.Arch absGlob := rootDir + "/" + relativeGlob f, err := filepath.Glob(absGlob) if err != nil { - warn(fmt.Sprintf("Invalid glob in archive %v: %v", aus.Name, relativeGlob)) + log.Warn(fmt.Sprintf("Invalid glob in archive %v: %v", aus.Name, relativeGlob)) return nil, err } files = append(files, f...) diff --git a/fission/timetrigger.go b/fission/timetrigger.go index 5d5d1abc..ce7f4a39 100644 --- a/fission/timetrigger.go +++ b/fission/timetrigger.go @@ -30,12 +30,13 @@ import ( "github.com/fission/fission" "github.com/fission/fission/controller/client" "github.com/fission/fission/crd" + "github.com/fission/fission/fission/log" ) func getAPITimeInfo(client *client.Client) time.Time { serverInfo, err := client.ServerInfo() if err != nil { - fatal(fmt.Sprintf("Error syncing server time information: %v", err)) + log.Fatal(fmt.Sprintf("Error syncing server time information: %v", err)) } return serverInfo.ServerTime.CurrentTime } @@ -65,14 +66,14 @@ func ttCreate(c *cli.Context) error { } fnName := c.String("function") if len(fnName) == 0 { - fatal("Need a function name to create a trigger, use --function") + log.Fatal("Need a function name to create a trigger, use --function") } fnNamespace := c.String("fnNamespace") cronSpec := c.String("cron") if len(cronSpec) == 0 { - fatal("Need a cron spec like '0 30 * * * *', '@every 1h30m', or '@hourly'; use --cron") + log.Fatal("Need a cron spec like '0 30 * * * *', '@every 1h30m', or '@hourly'; use --cron") } tt := &crd.TimeTrigger{ @@ -116,7 +117,7 @@ func ttUpdate(c *cli.Context) error { client := getClient(c.GlobalString("server")) ttName := c.String("name") if len(ttName) == 0 { - fatal("Need name of trigger, use --name") + log.Fatal("Need name of trigger, use --name") } ttNs := c.String("triggerns") @@ -143,7 +144,7 @@ func ttUpdate(c *cli.Context) error { } if !updated { - fatal("Nothing to update. Use --cron or --function.") + log.Fatal("Nothing to update. Use --cron or --function.") } _, err = client.TimeTriggerUpdate(tt) @@ -161,7 +162,7 @@ func ttDelete(c *cli.Context) error { client := getClient(c.GlobalString("server")) ttName := c.String("name") if len(ttName) == 0 { - fatal("Need name of trigger to delete, use --name") + log.Fatal("Need name of trigger to delete, use --name") } ttNs := c.String("triggerns") @@ -200,7 +201,7 @@ func ttTest(c *cli.Context) error { 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") + log.Fatal("Need a cron spec like '0 30 * * * *', '@every 1h30m', or '@hourly'; use --cron") } err := getCronNextNActivationTime(cronSpec, getAPITimeInfo(client), round) diff --git a/fission/upgrade.go b/fission/upgrade.go index cfdcc7e0..b2ad8937 100644 --- a/fission/upgrade.go +++ b/fission/upgrade.go @@ -16,6 +16,7 @@ import ( "github.com/fission/fission" "github.com/fission/fission/crd" + "github.com/fission/fission/fission/log" "github.com/fission/fission/v1" ) @@ -37,7 +38,7 @@ type ( func getV1URL(serverUrl string) string { if len(serverUrl) == 0 { - fatal("Need --server or FISSION_URL set to your fission server.") + log.Fatal("Need --server or FISSION_URL set to your fission server.") } isHTTPS := strings.Index(serverUrl, "https://") == 0 isHTTP := strings.Index(serverUrl, "http://") == 0 @@ -57,7 +58,7 @@ func get(url string) []byte { checkErr(err, "reading server response") if resp.StatusCode != 200 { - fatal(fmt.Sprintf("Failed to fetch fission v0.1 state: %v", string(body))) + log.Fatal(fmt.Sprintf("Failed to fetch fission v0.1 state: %v", string(body))) } return body } @@ -251,7 +252,7 @@ func upgradeDumpState(c *cli.Context) error { checkErr(err, "reach fission server") if resp.StatusCode == http.StatusNotFound { msg := fmt.Sprintf("Server %v isn't a v1 Fission server. Use --server to point at a pre-0.2.x Fission server.", u) - fatal(msg) + log.Fatal(msg) } upgradeDumpV1State(u, filename) diff --git a/fission/watch.go b/fission/watch.go index 63c25160..14c5cebf 100644 --- a/fission/watch.go +++ b/fission/watch.go @@ -27,6 +27,7 @@ import ( "github.com/fission/fission" "github.com/fission/fission/crd" + "github.com/fission/fission/fission/log" ) func wCreate(c *cli.Context) error { @@ -34,7 +35,7 @@ func wCreate(c *cli.Context) error { fnName := c.String("function") if len(fnName) == 0 { - fatal("Need a function name to create a watch, use --function") + log.Fatal("Need a function name to create a watch, use --function") } fnNamespace := c.String("fnNamespace") @@ -95,13 +96,13 @@ func wCreate(c *cli.Context) error { func wGet(c *cli.Context) error { // TODO - fatal("Not implemented") + log.Fatal("Not implemented") return nil } func wUpdate(c *cli.Context) error { // TODO - fatal("Not implemented") + log.Fatal("Not implemented") return nil } @@ -110,7 +111,7 @@ func wDelete(c *cli.Context) error { wName := c.String("name") if len(wName) == 0 { - fatal("Need name of watch to delete, use --name") + log.Fatal("Need name of watch to delete, use --name") } wNs := c.String("triggerns")