Move packages to proejct/pkg to follow go project folder structure convention (#1190)

This commit is contained in:
Ta-Ching Chen
2019-05-31 16:28:55 +08:00
committed by GitHub
parent 1c5fd92ad6
commit a0e9a39511
196 changed files with 1672 additions and 1716 deletions
+207
View File
@@ -0,0 +1,207 @@
/*
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 util
import (
"fmt"
"net"
"net/http"
"os"
"strconv"
"strings"
"time"
v1 "k8s.io/api/core/v1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/portforward"
"k8s.io/client-go/transport/spdy"
"github.com/fission/fission/pkg/fission-cli/log"
"github.com/fission/fission/pkg/utils"
)
// 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(namespace, labelSelector string) string {
log.Verbose(2, "Setting up port forward to %s in namespace %s",
labelSelector, namespace)
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(labelSelector, localPort, namespace)
if err != nil {
log.Fatal(fmt.Sprintf("Error forwarding to port %v: %s", localPort, 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 {
return "", err
}
port := strconv.Itoa(listener.Addr().(*net.TCPAddr).Port)
err = listener.Close()
if err != nil {
return "", err
}
return port, nil
}
// runPortForward creates a local port forward to the specified pod
func runPortForward(labelSelector string, localPort string, ns string) error {
config, clientset := GetKubernetesClient()
log.Verbose(2, "Connected to Kubernetes API")
// 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(ns).
List(meta_v1.ListOptions{LabelSelector: labelSelector})
if err != nil || len(podList.Items) == 0 {
log.Fatal(fmt.Sprintf("Error getting pod for port-forwarding with label selector %v: %v", labelSelector, err))
}
nsList := make([]string, 0)
namespaces := make(map[string][]*v1.Pod)
// make a useful error message if there is more than one install
if len(podList.Items) > 0 {
for _, p := range podList.Items {
if _, ok := namespaces[p.Namespace]; !ok {
namespaces[p.Namespace] = []*v1.Pod{}
nsList = append(nsList, p.Namespace)
}
namespaces[p.Namespace] = append(namespaces[p.Namespace], &p)
}
if len(nsList) > 1 {
log.Fatal(fmt.Sprintf("Found %v fission installs, set FISSION_NAMESPACE to one of: %v",
len(namespaces), strings.Join(nsList, " ")))
}
}
// there is at most one namespace in nsList,
// use index 0 to get from it directly.
ns = nsList[0]
pods, ok := namespaces[ns]
if !ok {
log.Fatal(fmt.Sprintf("Error finding fission install within the given namespace %v, please check FISSION_NAMESPACE is set properly", ns))
}
var podName, podNameSpace string
// make sure we establish the connection to a healthy pod
for _, p := range pods {
if utils.IsReadyPod(p) {
podName = p.Name
podNameSpace = p.Namespace
break
}
}
// get the service and the target port
svcs, err := clientset.CoreV1().Services(podNameSpace).
List(meta_v1.ListOptions{LabelSelector: labelSelector})
if err != nil {
log.Fatal(fmt.Sprintf("Error getting %v service :%v", labelSelector, err.Error()))
}
if len(svcs.Items) == 0 {
log.Fatal(fmt.Sprintf("Service %v not found", labelSelector))
}
service := &svcs.Items[0]
var targetPort string
for _, servicePort := range service.Spec.Ports {
targetPort = servicePort.TargetPort.String()
}
log.Verbose(2, "Connecting to port %v on pod %v/%v", targetPort, podNameSpace, podNameSpace)
stopChannel := make(chan struct{}, 1)
readyChannel := make(chan struct{})
// create request URL
req := clientset.CoreV1().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
transport, upgrader, err := spdy.RoundTripperFor(config)
if err != nil {
msg := fmt.Sprintf("Failed to connect to Fission service on Kubernetes: %v", err.Error())
log.Fatal(msg)
}
dialer := spdy.NewDialer(upgrader, &http.Client{Transport: transport}, "POST", url)
outStream := os.Stdout
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())
log.Fatal(msg)
}
log.Verbose(2, "Starting port forwarder")
return fw.ForwardPorts()
}
+176
View File
@@ -0,0 +1,176 @@
/*
Copyright 2018 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 util
import (
"fmt"
"os"
"os/user"
"path/filepath"
"regexp"
"strings"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"github.com/fission/fission/pkg/controller/client"
"github.com/fission/fission/pkg/fission-cli/log"
)
func GetApiClient(serverUrl string) *client.Client {
if len(serverUrl) == 0 {
// starts local portforwarder etc.
serverUrl = GetServerUrl()
}
isHTTPS := strings.Index(serverUrl, "https://") == 0
isHTTP := strings.Index(serverUrl, "http://") == 0
if !(isHTTP || isHTTPS) {
serverUrl = "http://" + serverUrl
}
return client.MakeClient(serverUrl)
}
func GetFissionNamespace() string {
fissionNamespace := os.Getenv("FISSION_NAMESPACE")
return fissionNamespace
}
func GetServerUrl() string {
return GetApplicationUrl("application=fission-api")
}
func GetApplicationUrl(selector string) string {
var serverUrl string
// Use FISSION_URL env variable if set; otherwise, port-forward to controller.
fissionUrl := os.Getenv("FISSION_URL")
if len(fissionUrl) == 0 {
fissionNamespace := GetFissionNamespace()
localPort := SetupPortForward(fissionNamespace, "application=fission-api")
serverUrl = "http://127.0.0.1:" + localPort
} else {
serverUrl = fissionUrl
}
return serverUrl
}
func CheckErr(err error, msg string) {
if err != nil {
log.Fatal(fmt.Sprintf("Failed to %v: %v", msg, err))
}
}
// KubifyName make a kubernetes compliant name out of an arbitrary string
func KubifyName(old string) string {
// Kubernetes maximum name length (for some names; others can be 253 chars)
maxLen := 63
newName := strings.ToLower(old)
// replace disallowed chars with '-'
inv, err := regexp.Compile("[^-a-z0-9]")
CheckErr(err, "compile regexp")
newName = string(inv.ReplaceAll([]byte(newName), []byte("-")))
// trim leading non-alphabetic
leadingnonalpha, err := regexp.Compile("^[^a-z]+")
CheckErr(err, "compile regexp")
newName = string(leadingnonalpha.ReplaceAll([]byte(newName), []byte{}))
// trim trailing
trailing, err := regexp.Compile("[^a-z0-9]+$")
CheckErr(err, "compile regexp")
newName = string(trailing.ReplaceAll([]byte(newName), []byte{}))
// truncate to length
if len(newName) > maxLen {
newName = newName[0:maxLen]
}
// if we removed everything, call this thing "default". maybe
// we should generate a unique name...
if len(newName) == 0 {
newName = "default"
}
return newName
}
// GetKubernetesClient builds a new kubernetes client. If the KUBECONFIG
// environment variable is empty or doesn't exist, ~/.kube/config is used for
// the kube config path
func GetKubernetesClient() (*restclient.Config, *kubernetes.Clientset) {
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
kubeConfigPath := os.Getenv("KUBECONFIG")
if len(kubeConfigPath) == 0 {
usr, err := user.Current()
if err != nil {
log.Fatal(fmt.Sprintf("Could not get the current users directory: %s", err))
}
kubeConfigPath = filepath.Join(usr.HomeDir, ".kube", "config")
if _, err := os.Stat(kubeConfigPath); os.IsNotExist(err) {
log.Fatal("Couldn't find kubeconfig file. " +
"Set the KUBECONFIG environment variable to your kubeconfig's path.")
}
loadingRules.ExplicitPath = kubeConfigPath
log.Verbose(2, "Using kubeconfig from %q", kubeConfigPath)
} else {
log.Verbose(2, "Using kubeconfig from environment %q", kubeConfigPath)
}
config, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
loadingRules, &clientcmd.ConfigOverrides{}).ClientConfig()
if err != nil {
log.Fatal(fmt.Sprintf("Failed to build Kubernetes config: %s", err))
}
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
log.Fatal(fmt.Sprintf("Failed to connect to Kubernetes: %s", err))
}
return config, clientset
}
// given a list of functions, this checks if the functions actually exist on the cluster
func CheckFunctionExistence(fissionClient *client.Client, functions []string, fnNamespace string) (err error) {
fnMissing := make([]string, 0)
for _, fnName := range functions {
meta := &metav1.ObjectMeta{
Name: fnName,
Namespace: fnNamespace,
}
_, err := fissionClient.FunctionGet(meta)
if err != nil {
fnMissing = append(fnMissing, fnName)
}
}
if len(fnMissing) > 0 {
return fmt.Errorf("function(s) %s, not present in namespace : %s", fnMissing, fnNamespace)
}
return nil
}
+49
View File
@@ -0,0 +1,49 @@
package util
import (
"fmt"
yaml "gopkg.in/yaml.v2"
"github.com/fission/fission/pkg/controller/client"
"github.com/fission/fission/pkg/fission-cli/log"
"github.com/fission/fission/pkg/fission-cli/plugin"
"github.com/fission/fission/pkg/info"
)
// Versions is a container of versions of the client (and its plugins) and server (and its plugins).
type Versions struct {
Client map[string]info.BuildMeta `json:"client"`
Server map[string]info.BuildMeta `json:"server"`
}
func GetVersion(client *client.Client) []byte {
serverInfo, err := client.ServerInfo()
if err != nil {
log.Warn(fmt.Sprintf("Error getting Fission API version: %v", err))
}
// Fetch client versions
versions := Versions{
Client: map[string]info.BuildMeta{
"fission/core": info.BuildInfo(),
},
}
for _, pmd := range plugin.FindAll() {
versions.Client[pmd.Name] = info.BuildMeta{
Version: pmd.Version,
}
}
// Fetch server versions
versions.Server = map[string]info.BuildMeta{
"fission/core": serverInfo.Build,
}
// FUTURE: fetch versions of plugins server-side
bs, err := yaml.Marshal(versions)
if err != nil {
log.Fatal("Failed to format versions: " + err.Error())
}
return bs
}