Service type ClusterIP - Controller port forward through CLI (#431)
setting serviceType to ClusterIP as default for fission controller and corresponding changes in fission cli to be able to port-forward the controller pod.
This commit is contained in:
committed by
smruthi2187
parent
1428c64b4f
commit
b9a559af2f
+18
-1
@@ -157,6 +157,20 @@ func createArchive(client *client.Client, fileName string, specFile string) *fis
|
||||
archive.Type = fission.ArchiveTypeLiteral
|
||||
archive.Literal = contents
|
||||
} else {
|
||||
// make a kubernetes client
|
||||
_, kubeClient, _, err := crd.GetKubernetesClient()
|
||||
if err != nil {
|
||||
fatal(err.Error())
|
||||
}
|
||||
|
||||
fissionNamespace := os.Getenv("FISSION_NAMESPACE")
|
||||
|
||||
// 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()))
|
||||
}
|
||||
|
||||
u := strings.TrimSuffix(client.Url, "/") + "/proxy/storage"
|
||||
ssClient := storageSvcClient.MakeClient(u)
|
||||
|
||||
@@ -164,7 +178,10 @@ func createArchive(client *client.Client, fileName string, specFile string) *fis
|
||||
id, err := ssClient.Upload(fileName, nil)
|
||||
checkErr(err, fmt.Sprintf("upload file %v", fileName))
|
||||
|
||||
archiveUrl := ssClient.GetUrl(id)
|
||||
// this needs to be storagesvc.fission
|
||||
storageSvcEndpoint := fmt.Sprintf("http://%s.%s/", service.Name, service.Namespace)
|
||||
storageServiceClient := storageSvcClient.MakeClient(storageSvcEndpoint)
|
||||
archiveUrl := storageServiceClient.GetUrl(id)
|
||||
|
||||
archive.Type = fission.ArchiveTypeUrl
|
||||
archive.URL = archiveUrl
|
||||
|
||||
+28
-2
@@ -21,6 +21,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
@@ -602,10 +603,35 @@ func fnPods(c *cli.Context) error {
|
||||
}
|
||||
|
||||
func fnTest(c *cli.Context) error {
|
||||
//we can port-forward the router specifically for this method
|
||||
fnName := c.String("name")
|
||||
if len(fnName) == 0 {
|
||||
fatal("Need function name to be specified with --name")
|
||||
}
|
||||
|
||||
routerURL := os.Getenv("FISSION_ROUTER")
|
||||
if len(routerURL) == 0 {
|
||||
fatal("Need FISSION_ROUTER set to your fission router.")
|
||||
localRouterPort, err := findFreePort()
|
||||
if err != nil {
|
||||
fatal(fmt.Sprintf("Error finding unused port for router :%s", err.Error()))
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("http://%s/fission-function/%s", routerURL, fnName)
|
||||
@@ -621,7 +647,7 @@ func fnTest(c *cli.Context) error {
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
checkErr(err, "read log response from pod")
|
||||
fmt.Printf("Error calling function %v: %v %v", fnName, resp.StatusCode, string(body))
|
||||
fmt.Printf("Error calling function %s: %d %s", fnName, resp.StatusCode, string(body))
|
||||
defer resp.Body.Close()
|
||||
err = printPodLogs(c)
|
||||
if err != nil {
|
||||
|
||||
+17
-1
@@ -28,8 +28,24 @@ func main() {
|
||||
app.Usage = "Serverless functions for Kubernetes"
|
||||
app.Version = "0.5.0"
|
||||
|
||||
// fetch the FISSION_URL env variable. If not set, port-forward to controller.
|
||||
var value string
|
||||
fissionUrl := os.Getenv("FISSION_URL")
|
||||
if len(fissionUrl) == 0 {
|
||||
// check here to specify env var for KUBECONFIG and FISSION_NAMESPACE
|
||||
fissionNamespace := os.Getenv("FISSION_NAMESPACE")
|
||||
kubeConfig := os.Getenv("KUBECONFIG")
|
||||
if len(kubeConfig) == 0 || len(fissionNamespace) == 0 {
|
||||
fatal("Environment variables KUBECONFIG and FISSION_NAMESPACE are mandatory if the serviceType is ClusterIP")
|
||||
}
|
||||
localPort := controllerPodPortForward(fissionNamespace)
|
||||
value = "http://127.0.0.1:" + localPort
|
||||
} else {
|
||||
value = fissionUrl
|
||||
}
|
||||
|
||||
app.Flags = []cli.Flag{
|
||||
cli.StringFlag{Name: "server", Usage: "Fission server URL", EnvVar: "FISSION_URL"},
|
||||
cli.StringFlag{Name: "server", Value: value, Usage: "Fission server URL"},
|
||||
}
|
||||
|
||||
// trigger method and url flags (used in function and route CLIs)
|
||||
|
||||
+3
-1
@@ -53,9 +53,11 @@ func downloadStoragesvcURL(client *client.Client, fileUrl string) io.ReadCloser
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// replace in-cluster storage service host with controller server url
|
||||
fileDownloadUrl := strings.TrimSuffix(client.Url, "/") + "/proxy/storage" + u.RequestURI()
|
||||
fileDownloadUrl := strings.TrimSuffix(client.Url, "/") + "/proxy/storage/" + u.RequestURI()
|
||||
reader, err := downloadURL(fileDownloadUrl)
|
||||
|
||||
checkErr(err, fmt.Sprintf("download from storage service url: %v", fileUrl))
|
||||
return reader
|
||||
}
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/tools/portforward"
|
||||
"k8s.io/client-go/tools/remotecommand"
|
||||
|
||||
"github.com/fission/fission/crd"
|
||||
)
|
||||
|
||||
func findFreePort() (string, error) {
|
||||
listener, err := net.Listen("tcp", ":0")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
port := strconv.Itoa(listener.Addr().(*net.TCPAddr).Port)
|
||||
file, err := listener.(*net.TCPListener).File()
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
err = listener.Close()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
err = file.Close()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return port, nil
|
||||
}
|
||||
|
||||
func runportForward(serviceName string, localPort string, fissionNamespace string) error {
|
||||
//KUBECONFIG needs to be set to the correct path i.e ~/.kube/config
|
||||
config, podClient, _, err := crd.GetKubernetesClient()
|
||||
if err != nil {
|
||||
fatal(err.Error())
|
||||
}
|
||||
|
||||
//get the podname for the controller
|
||||
podList, err := podClient.CoreV1().Pods(fissionNamespace).List(meta_v1.ListOptions{LabelSelector: "application=fission-api"})
|
||||
if err != nil || len(podList.Items) == 0 {
|
||||
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
|
||||
podNameSpace := podList.Items[0].Namespace
|
||||
|
||||
//get the ControllerPort
|
||||
service, err := podClient.CoreV1().Services(podNameSpace).Get(serviceName, meta_v1.GetOptions{})
|
||||
if err != nil {
|
||||
fatal(fmt.Sprintf("Error getting %v service :%v", serviceName, err.Error()))
|
||||
}
|
||||
|
||||
var targetPort string
|
||||
for _, servicePort := range service.Spec.Ports {
|
||||
targetPort = servicePort.TargetPort.String()
|
||||
}
|
||||
|
||||
stopChannel := make(chan struct{}, 1)
|
||||
readyChannel := make(chan struct{})
|
||||
|
||||
//create request URL
|
||||
req := podClient.CoreV1Client.RESTClient().Post().Resource("pods").Namespace(podNameSpace).Name(podName).SubResource("portforward")
|
||||
url := req.URL()
|
||||
|
||||
//create ports slice
|
||||
portCombo := localPort + ":" + targetPort
|
||||
ports := []string{portCombo}
|
||||
|
||||
//actually start the port-forwarding process here
|
||||
dialer, err := remotecommand.NewExecutor(config, "POST", url)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("newexecutor errored out :%v", err.Error())
|
||||
fatal(msg)
|
||||
}
|
||||
|
||||
fw, err := portforward.New(dialer, ports, stopChannel, readyChannel, nil, os.Stderr)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("portforward.new errored out :%v", err.Error())
|
||||
fatal(msg)
|
||||
}
|
||||
|
||||
return fw.ForwardPorts()
|
||||
}
|
||||
|
||||
func controllerPodPortForward(fissionNamespace string) string {
|
||||
localControllerPort, err := findFreePort()
|
||||
if err != nil {
|
||||
fatal(fmt.Sprintf("Error finding unused port :%v", err.Error()))
|
||||
}
|
||||
|
||||
timeBefore := time.Now()
|
||||
for {
|
||||
conn, _ := net.DialTimeout("tcp", net.JoinHostPort("", localControllerPort), time.Millisecond)
|
||||
if conn != nil {
|
||||
conn.Close()
|
||||
} else {
|
||||
break
|
||||
}
|
||||
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() {
|
||||
err := runportForward("controller", localControllerPort, fissionNamespace)
|
||||
if err != nil {
|
||||
fatal(err.Error())
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
conn, _ := net.DialTimeout("tcp", net.JoinHostPort("", localControllerPort), time.Millisecond)
|
||||
if conn != nil {
|
||||
conn.Close()
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Millisecond * 50)
|
||||
}
|
||||
|
||||
return localControllerPort
|
||||
}
|
||||
Reference in New Issue
Block a user