Default values for FISSION_* env vars (#518)

This makes set up easier for new users.  Users can still set
FISSION_NAMESPACE but it will default to "fission".  Users can also
still set KUBECONFIG, but it will default to $HOME/.kube/config.

Also, update the post-install chart notes.txt and the install guide to
use "fission function test" as the first step after install.  This
means that if there's anything wrong with the setup, the user will see
useful errors instead of "internal server error".  Also, they can test
their setup without worrying about nodeports or ingresses or whatever.

All existing functionality of FISSION_URL and FISSION_ROUTER continues
to work.
This commit is contained in:
Soam Vasani
2018-02-28 18:14:57 -08:00
committed by GitHub
parent b895f98e88
commit 7ddbea59a2
10 changed files with 90 additions and 166 deletions
@@ -119,39 +119,6 @@ $ curl -Lo fission https://github.com/fission/fission/releases/download/0.5.0/fi
For Windows, you can use the linux binary on WSL. Or you can download For Windows, you can use the linux binary on WSL. Or you can download
this windows executable: [fission.exe](https://github.com/fission/fission/releases/download/0.5.0/fission-cli-windows.exe) this windows executable: [fission.exe](https://github.com/fission/fission/releases/download/0.5.0/fission-cli-windows.exe)
### Set environment vars
Set the FISSION_URL and FISSION_ROUTER environment variables.
FISSION_URL is used by the fission CLI to find the server.
(FISSION_ROUTER is only needed for the examples below to work.)
#### Minikube
If you're using minikube, use these commands:
```
$ export FISSION_URL=http://$(minikube ip):31313
$ export FISSION_ROUTER=$(minikube ip):31314
```
#### Cloud setups
Save the external IP addresses of controller and router services in
FISSION_URL and FISSION_ROUTER, respectively. Wait for services to
get IP addresses (check this with ```kubectl --namespace fission get
svc```). Then:
##### AWS
```
$ export FISSION_URL=http://$(kubectl --namespace fission get svc controller -o=jsonpath='{..hostname}')
$ export FISSION_ROUTER=$(kubectl --namespace fission get svc router -o=jsonpath='{..hostname}')
```
##### GCP
```
$ export FISSION_URL=http://$(kubectl --namespace fission get svc controller -o=jsonpath='{..ip}')
$ export FISSION_ROUTER=$(kubectl --namespace fission get svc router -o=jsonpath='{..ip}')
```
### Run an example ### Run an example
Finally, you're ready to use Fission! Finally, you're ready to use Fission!
@@ -163,9 +130,7 @@ $ curl -LO https://raw.githubusercontent.com/fission/fission/master/examples/nod
$ fission function create --name hello --env nodejs --code hello.js $ fission function create --name hello --env nodejs --code hello.js
$ fission route create --method GET --url /hello --function hello $ fission function test --name hello
$ curl http://$FISSION_ROUTER/hello
Hello, world! Hello, world!
``` ```
+6 -36
View File
@@ -9,47 +9,17 @@ Linux:
Windows: Windows:
For Windows, you can use the linux binary on WSL. Or you can download this windows executable: https://github.com/fission/fission/releases/download/0.5.0/fission-cli-windows.exe For Windows, you can use the linux binary on WSL. Or you can download this windows executable: https://github.com/fission/fission/releases/download/0.5.0/fission-cli-windows.exe
2. Set the FISSION environment variables. 2. You're ready to use Fission!
{{- if contains "NodePort" .Values.serviceType }}
$ export FISSION_URL=http://$(minikube ip):{{ .Values.controllerPort }}
{{- else if contains "LoadBalancer" .Values.serviceType }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl --namespace fission get -w svc' and 'kubectl --namespace fission get svc -w controller'
$ export FISSION_URL=http://$(kubectl --namespace fission get svc controller -o=jsonpath='{..ip}')
{{- else if contains "ClusterIP" .Values.serviceType }}
$ export FISSION_NAMESPACE={{ .Release.Namespace }}
$ export KUBECONFIG=${HOME}/.kube/config
{{- end }}
{{- if contains "NodePort" .Values.routerServiceType }}
$ export FISSION_ROUTER=$(minikube ip):{{ .Values.routerPort }}
{{- else if contains "LoadBalancer" .Values.routerServiceType }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status by running 'kubectl --namespace fission get -w svc' and 'kubectl --namespace fission get svc -w router'
$ export FISSION_ROUTER=$(kubectl --namespace fission get svc router -o=jsonpath='{..ip}')
{{- else if contains "ClusterIP" .Values.routerServiceType }}
$ export KUBECONFIG=${HOME}/.kube/config
$ curl -Lo port-forward-router.sh https://github.com/fission/fission/port-forward-router.sh && chmod +x port-forward-router.sh && ./port-forward-router.sh {{ .Release.Namespace }} router 9999
$ export FISSION_ROUTER=127.0.0.1:9999
{{- end }}
3. Finally, you're ready to use Fission!
# Create an environment
$ fission env create --name nodejs --image fission/node-env $ fission env create --name nodejs --image fission/node-env
# Get a hello world
$ curl https://raw.githubusercontent.com/fission/fission/master/examples/nodejs/hello.js > hello.js $ curl https://raw.githubusercontent.com/fission/fission/master/examples/nodejs/hello.js > hello.js
# Register this function with Fission
$ fission function create --name hello --env nodejs --code hello.js $ fission function create --name hello --env nodejs --code hello.js
$ fission route create --method GET --url /hello --function hello # Run this function
$ fission function test --name hello
$ curl http://$FISSION_ROUTER/hello
Hello, world! Hello, world!
@@ -168,6 +168,7 @@ spec:
template: template:
metadata: metadata:
labels: labels:
application: fission-router
svc: router svc: router
spec: spec:
containers: containers:
+2
View File
@@ -4,6 +4,7 @@ metadata:
name: router name: router
labels: labels:
svc: router svc: router
application: fission-router
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
spec: spec:
type: {{ .Values.routerServiceType }} type: {{ .Values.routerServiceType }}
@@ -23,6 +24,7 @@ metadata:
name: controller name: controller
labels: labels:
svc: controller svc: controller
application: fission-api
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
spec: spec:
type: {{ .Values.serviceType }} type: {{ .Values.serviceType }}
+6 -36
View File
@@ -9,47 +9,17 @@ Linux:
Windows: Windows:
For Windows, you can use the linux binary on WSL. Or you can download this windows executable: https://github.com/fission/fission/releases/download/0.5.0/fission-cli-windows.exe For Windows, you can use the linux binary on WSL. Or you can download this windows executable: https://github.com/fission/fission/releases/download/0.5.0/fission-cli-windows.exe
2. Set the FISSION_URL and FISSION_ROUTER environment variables. 2. You're ready to use Fission!
{{- if contains "NodePort" .Values.serviceType }}
$ export FISSION_URL=http://$(minikube ip):{{ .Values.controllerPort }}
{{- else if contains "LoadBalancer" .Values.serviceType }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl --namespace fission get -w svc' and 'kubectl --namespace fission get svc -w controller'
$ export FISSION_URL=http://$(kubectl --namespace fission get svc controller -o=jsonpath='{..ip}')
{{- else if contains "ClusterIP" .Values.serviceType }}
$ export FISSION_NAMESPACE={{ .Release.Namespace }}
$ export KUBECONFIG=${HOME}/.kube/config
{{- end }}
{{- if contains "NodePort" .Values.routerServiceType }}
$ export FISSION_ROUTER=$(minikube ip):{{ .Values.routerPort }}
{{- else if contains "LoadBalancer" .Values.routerServiceType }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status by running 'kubectl --namespace fission get -w svc' and 'kubectl --namespace fission get svc -w router'
$ export FISSION_ROUTER=$(kubectl --namespace fission get svc router -o=jsonpath='{..ip}')
{{- else if contains "ClusterIP" .Values.routerServiceType }}
$ export KUBECONFIG=${HOME}/.kube/config
$ curl -Lo port-forward-router.sh https://github.com/fission/fission/port-forward-router.sh && chmod +x port-forward-router.sh && ./port-forward-router.sh {{ .Release.Namespace }} router 9999
$ export FISSION_ROUTER=127.0.0.1:9999
{{- end }}
3. Finally, you're ready to use Fission!
# Create an environment
$ fission env create --name nodejs --image fission/node-env $ fission env create --name nodejs --image fission/node-env
# Get a hello world
$ curl https://raw.githubusercontent.com/fission/fission/master/examples/nodejs/hello.js > hello.js $ curl https://raw.githubusercontent.com/fission/fission/master/examples/nodejs/hello.js > hello.js
# Register this function with Fission
$ fission function create --name hello --env nodejs --code hello.js $ fission function create --name hello --env nodejs --code hello.js
$ fission route create --method GET --url /hello --function hello # Run this function
$ fission function test --name hello
$ curl http://$FISSION_ROUTER/hello
Hello, world! Hello, world!
@@ -168,6 +168,7 @@ spec:
template: template:
metadata: metadata:
labels: labels:
application: fission-router
svc: router svc: router
spec: spec:
containers: containers:
+2
View File
@@ -4,6 +4,7 @@ metadata:
name: router name: router
labels: labels:
svc: router svc: router
application: fission-router
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
spec: spec:
type: {{ .Values.routerServiceType }} type: {{ .Values.routerServiceType }}
@@ -23,6 +24,7 @@ metadata:
name: controller name: controller
labels: labels:
svc: controller svc: controller
application: fission-api
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
spec: spec:
type: {{ .Values.serviceType }} type: {{ .Values.serviceType }}
+6 -22
View File
@@ -21,10 +21,10 @@ import (
"errors" "errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net"
"net/http" "net/http"
"net/url" "net/url"
"os" "os"
"strings"
"text/tabwriter" "text/tabwriter"
"time" "time"
@@ -690,7 +690,6 @@ func fnPods(c *cli.Context) error {
} }
func fnTest(c *cli.Context) error { func fnTest(c *cli.Context) error {
//we can port-forward the router specifically for this method
fnName := c.String("name") fnName := c.String("name")
if len(fnName) == 0 { if len(fnName) == 0 {
fatal("Need function name to be specified with --name") fatal("Need function name to be specified with --name")
@@ -698,27 +697,12 @@ func fnTest(c *cli.Context) error {
routerURL := os.Getenv("FISSION_ROUTER") routerURL := os.Getenv("FISSION_ROUTER")
if len(routerURL) == 0 { if len(routerURL) == 0 {
localRouterPort, err := findFreePort() // Portforward to the fission router
if err != nil { localRouterPort := setupPortForward(getKubeConfigPath(),
fatal(fmt.Sprintf("Error finding unused port for router :%s", err.Error())) getFissionNamespace(), "application=fission-router")
}
fissionNamespace := os.Getenv("FISSION_NAMESPACE")
go func() {
err := runportForward("router", localRouterPort, fissionNamespace)
if err != nil {
fatal(err.Error())
}
}()
for {
conn, _ := net.DialTimeout("tcp", net.JoinHostPort("", localRouterPort), time.Second)
if conn != nil {
conn.Close()
break
}
}
routerURL = "127.0.0.1:" + localRouterPort routerURL = "127.0.0.1:" + localRouterPort
} else {
routerURL = strings.TrimPrefix(routerURL, "http://")
} }
url := fmt.Sprintf("http://%s/fission-function/%s", routerURL, fnName) url := fmt.Sprintf("http://%s/fission-function/%s", routerURL, fnName)
+23 -7
View File
@@ -18,10 +18,29 @@ package main
import ( import (
"os" "os"
"path/filepath"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
func getFissionNamespace() string {
fissionNamespace := os.Getenv("FISSION_NAMESPACE")
if len(fissionNamespace) == 0 {
// TODO make this smarter, perhaps based on helm releases
fissionNamespace = "fission"
}
return fissionNamespace
}
func getKubeConfigPath() string {
kubeConfig := os.Getenv("KUBECONFIG")
if len(kubeConfig) == 0 {
home := os.Getenv("HOME")
kubeConfig = filepath.Join(home, ".kube", "config")
}
return kubeConfig
}
func main() { func main() {
app := cli.NewApp() app := cli.NewApp()
app.Name = "fission" app.Name = "fission"
@@ -32,13 +51,10 @@ func main() {
var value string var value string
fissionUrl := os.Getenv("FISSION_URL") fissionUrl := os.Getenv("FISSION_URL")
if len(fissionUrl) == 0 { if len(fissionUrl) == 0 {
// check here to specify env var for KUBECONFIG and FISSION_NAMESPACE fissionNamespace := getFissionNamespace()
fissionNamespace := os.Getenv("FISSION_NAMESPACE") kubeConfig := getKubeConfigPath()
kubeConfig := os.Getenv("KUBECONFIG") localPort := setupPortForward(
if len(kubeConfig) == 0 || len(fissionNamespace) == 0 { kubeConfig, fissionNamespace, "application=fission-api")
fatal("Environment variables KUBECONFIG and FISSION_NAMESPACE are mandatory if the serviceType is ClusterIP")
}
localPort := controllerPodPortForward(fissionNamespace)
value = "http://127.0.0.1:" + localPort value = "http://127.0.0.1:" + localPort
} else { } else {
value = fissionUrl value = fissionUrl
+42 -29
View File
@@ -8,10 +8,11 @@ import (
"time" "time"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
// "k8s.io/client-go/rest"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/tools/portforward" "k8s.io/client-go/tools/portforward"
"k8s.io/client-go/tools/remotecommand" "k8s.io/client-go/tools/remotecommand"
"github.com/fission/fission/crd"
) )
func findFreePort() (string, error) { func findFreePort() (string, error) {
@@ -39,28 +40,38 @@ func findFreePort() (string, error) {
return port, nil return port, nil
} }
func runportForward(serviceName string, localPort string, fissionNamespace string) error { // runPortForward creates a local port forward to the specified pod
//KUBECONFIG needs to be set to the correct path i.e ~/.kube/config func runPortForward(kubeConfig string, labelSelector string, localPort string, fissionNamespace string) error {
config, podClient, _, err := crd.GetKubernetesClient() config, err := clientcmd.BuildConfigFromFlags("", kubeConfig)
if err != nil { if err != nil {
fatal(err.Error()) fatal(fmt.Sprintf("Failed to connect to Kubernetes: %s", err))
} }
//get the podname for the controller clientset, err := kubernetes.NewForConfig(config)
podList, err := podClient.CoreV1().Pods(fissionNamespace).List(meta_v1.ListOptions{LabelSelector: "application=fission-api"}) if err != nil {
fatal(fmt.Sprintf("Failed to connect to Kubernetes: %s", err))
}
// get the pod; if there is more than one, always port-forward to the first.
podList, err := clientset.CoreV1().Pods(fissionNamespace).
List(meta_v1.ListOptions{LabelSelector: labelSelector})
if err != nil || len(podList.Items) == 0 { if err != nil || len(podList.Items) == 0 {
fatal("Error getting controller pod for port-forwarding") fatal("Error getting controller pod for port-forwarding")
} }
// if there are more than one pods, always port-forward to the first pod returned
podName := podList.Items[0].Name podName := podList.Items[0].Name
podNameSpace := podList.Items[0].Namespace podNameSpace := podList.Items[0].Namespace
//get the ControllerPort // get the service and the target port
service, err := podClient.CoreV1().Services(podNameSpace).Get(serviceName, meta_v1.GetOptions{}) svcs, err := clientset.CoreV1().Services(podNameSpace).
List(meta_v1.ListOptions{LabelSelector: labelSelector})
if err != nil { if err != nil {
fatal(fmt.Sprintf("Error getting %v service :%v", serviceName, err.Error())) fatal(fmt.Sprintf("Error getting %v service :%v", labelSelector, err.Error()))
} }
if len(svcs.Items) == 0 {
fatal(fmt.Sprintf("Service %v not found", labelSelector))
}
service := &svcs.Items[0]
var targetPort string var targetPort string
for _, servicePort := range service.Spec.Ports { for _, servicePort := range service.Spec.Ports {
@@ -70,15 +81,16 @@ func runportForward(serviceName string, localPort string, fissionNamespace strin
stopChannel := make(chan struct{}, 1) stopChannel := make(chan struct{}, 1)
readyChannel := make(chan struct{}) readyChannel := make(chan struct{})
//create request URL // create request URL
req := podClient.CoreV1Client.RESTClient().Post().Resource("pods").Namespace(podNameSpace).Name(podName).SubResource("portforward") req := clientset.CoreV1Client.RESTClient().Post().Resource("pods").
Namespace(podNameSpace).Name(podName).SubResource("portforward")
url := req.URL() url := req.URL()
//create ports slice // create ports slice
portCombo := localPort + ":" + targetPort portCombo := localPort + ":" + targetPort
ports := []string{portCombo} ports := []string{portCombo}
//actually start the port-forwarding process here // actually start the port-forwarding process here
dialer, err := remotecommand.NewExecutor(config, "POST", url) dialer, err := remotecommand.NewExecutor(config, "POST", url)
if err != nil { if err != nil {
msg := fmt.Sprintf("newexecutor errored out :%v", err.Error()) msg := fmt.Sprintf("newexecutor errored out :%v", err.Error())
@@ -94,15 +106,20 @@ func runportForward(serviceName string, localPort string, fissionNamespace strin
return fw.ForwardPorts() return fw.ForwardPorts()
} }
func controllerPodPortForward(fissionNamespace string) string { // Port forward a free local port to a pod on the cluster. The pod is
localControllerPort, err := findFreePort() // 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 {
localPort, err := findFreePort()
if err != nil { if err != nil {
fatal(fmt.Sprintf("Error finding unused port :%v", err.Error())) fatal(fmt.Sprintf("Error finding unused port :%v", err.Error()))
} }
timeBefore := time.Now()
for { for {
conn, _ := net.DialTimeout("tcp", net.JoinHostPort("", localControllerPort), time.Millisecond) conn, _ := net.DialTimeout("tcp",
net.JoinHostPort("", localPort), time.Millisecond)
if conn != nil { if conn != nil {
conn.Close() conn.Close()
} else { } else {
@@ -111,20 +128,16 @@ func controllerPodPortForward(fissionNamespace string) string {
time.Sleep(time.Millisecond * 50) time.Sleep(time.Millisecond * 50)
} }
timeAfter := time.Since(timeBefore)
if timeAfter.Seconds()/1000 >= 100 {
fatal(fmt.Sprintln("Lag in connecting to a free port on the localhost"))
}
go func() { go func() {
err := runportForward("controller", localControllerPort, fissionNamespace) err := runPortForward(kubeConfig, labelSelector, localPort, namespace)
if err != nil { if err != nil {
fatal(err.Error()) fatal(fmt.Sprintf("Error forwarding to controller port: %s", err.Error()))
} }
}() }()
for { for {
conn, _ := net.DialTimeout("tcp", net.JoinHostPort("", localControllerPort), time.Millisecond) conn, _ := net.DialTimeout("tcp",
net.JoinHostPort("", localPort), time.Millisecond)
if conn != nil { if conn != nil {
conn.Close() conn.Close()
break break
@@ -132,5 +145,5 @@ func controllerPodPortForward(fissionNamespace string) string {
time.Sleep(time.Millisecond * 50) time.Sleep(time.Millisecond * 50)
} }
return localControllerPort return localPort
} }