Switch to official Kubernetes Go client -- client-go/1.4

Switch to client-go package instead of pulling the from kubernetes.
Use a versioned client with sensible compatiblity.

This change breaks 'go get'.  For now you have to manually checkout
the 'release-1.4' branch of the client-go package after 'go get'
fetches it.  TODO: use one of the build tools to fix this.
This commit is contained in:
Soam Vasani
2016-11-01 01:32:02 -07:00
parent 7d1058d7be
commit 40dfba1a41
3 changed files with 96 additions and 70 deletions
+25 -2
View File
@@ -18,14 +18,19 @@ package poolmgr
import ( import (
"encoding/json" "encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http" "net/http"
"os"
"time" "time"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"github.com/platform9/fission" "github.com/platform9/fission"
"github.com/platform9/fission/cache" "github.com/platform9/fission/cache"
controllerclient "github.com/platform9/fission/controller/client" controllerclient "github.com/platform9/fission/controller/client"
"io/ioutil"
"log"
) )
type funcSvc struct { type funcSvc struct {
@@ -44,6 +49,15 @@ type API struct {
controller *controllerclient.Client controller *controllerclient.Client
} }
func MakeAPI(gpm *GenericPoolManager, controller *controllerclient.Client) *API {
return &API{
poolMgr: gpm,
functionEnv: cache.MakeCache(),
functionService: cache.MakeCache(),
controller: controller,
}
}
func (api *API) lookupApi(w http.ResponseWriter, r *http.Request) { func (api *API) lookupApi(w http.ResponseWriter, r *http.Request) {
body, err := ioutil.ReadAll(r.Body) body, err := ioutil.ReadAll(r.Body)
if err != nil { if err != nil {
@@ -136,3 +150,12 @@ func (api *API) lookup(m *fission.Metadata) (string, error) {
return funcSvc.serviceName, nil return funcSvc.serviceName, nil
} }
func (api *API) Serve(port int) {
r := mux.NewRouter()
r.HandleFunc("/v1/lookup", api.lookupApi).Methods("GET")
address := fmt.Sprintf(":%v", port)
log.Printf("starting poolmgr at port %v", port)
log.Fatal(http.ListenAndServe(address, handlers.LoggingHandler(os.Stdout, r)))
}
+64 -63
View File
@@ -25,25 +25,25 @@ import (
"net/http" "net/http"
"time" "time"
"github.com/platform9/fission" "k8s.io/client-go/1.4/kubernetes"
"k8s.io/client-go/1.4/pkg/api"
"k8s.io/client-go/1.4/pkg/api/v1"
"k8s.io/client-go/1.4/pkg/apis/extensions/v1beta1"
"k8s.io/client-go/1.4/pkg/labels"
"k8s.io/kubernetes/pkg/api" "github.com/platform9/fission"
apiUnversioned "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/extensions"
clientUnversioned "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/labels"
) )
type ( type (
GenericPool struct { GenericPool struct {
env *fission.Environment env *fission.Environment
replicas int // num containers replicas int32 // num containers
deployment *extensions.Deployment // kubernetes deployment deployment *v1beta1.Deployment // kubernetes deployment
namespace string // namespace to keep our resources namespace string // namespace to keep our resources
podReadyTimeout time.Duration // timeout for generic pods to become ready podReadyTimeout time.Duration // timeout for generic pods to become ready
controllerHostName string controllerUrl string
kubernetesClient *clientUnversioned.Client kubernetesClient *kubernetes.Clientset
requestChannel chan *choosePodRequest requestChannel chan *choosePodRequest
} }
@@ -53,25 +53,26 @@ type (
responseChannel chan *choosePodResponse responseChannel chan *choosePodResponse
} }
choosePodResponse struct { choosePodResponse struct {
pod *api.Pod pod *v1.Pod
error error
} }
) )
func MakeGenericPool( func MakeGenericPool(
kubernetesClient *clientUnversioned.Client, controllerUrl string,
kubernetesClient *kubernetes.Clientset,
env *fission.Environment, env *fission.Environment,
initialReplicas int, initialReplicas int32,
namespace string) (*GenericPool, error) { namespace string) (*GenericPool, error) {
gp := &GenericPool{ gp := &GenericPool{
env: env, env: env,
replicas: initialReplicas, replicas: initialReplicas,
requestChannel: make(chan *choosePodRequest), requestChannel: make(chan *choosePodRequest),
kubernetesClient: kubernetesClient, kubernetesClient: kubernetesClient,
namespace: namespace, namespace: namespace,
podReadyTimeout: 5 * time.Minute, podReadyTimeout: 5 * time.Minute,
controllerHostName: "controller", controllerUrl: controllerUrl,
} }
// create the pool // create the pool
@@ -107,7 +108,7 @@ func (gp *GenericPool) choosePodService() {
// choosePod picks a ready pod from the pool and relabels it, waiting if necessary. // choosePod picks a ready pod from the pool and relabels it, waiting if necessary.
// returns the pod API object. // returns the pod API object.
func (gp *GenericPool) choosePod(newLabels map[string]string) (*api.Pod, error) { func (gp *GenericPool) choosePod(newLabels map[string]string) (*v1.Pod, error) {
req := &choosePodRequest{ req := &choosePodRequest{
newLabels: newLabels, newLabels: newLabels,
responseChannel: make(chan *choosePodResponse), responseChannel: make(chan *choosePodResponse),
@@ -118,7 +119,7 @@ func (gp *GenericPool) choosePod(newLabels map[string]string) (*api.Pod, error)
} }
// _choosePod is called serially by choosePodService // _choosePod is called serially by choosePodService
func (gp *GenericPool) _choosePod(newLabels map[string]string) (*api.Pod, error) { func (gp *GenericPool) _choosePod(newLabels map[string]string) (*v1.Pod, error) {
startTime := time.Now() startTime := time.Now()
for { for {
// Retries took too long, error out. // Retries took too long, error out.
@@ -127,7 +128,7 @@ func (gp *GenericPool) _choosePod(newLabels map[string]string) (*api.Pod, error)
} }
// Get pods; filter the ones that are ready // Get pods; filter the ones that are ready
podList, err := gp.kubernetesClient.Pods(gp.namespace).List( podList, err := gp.kubernetesClient.Core().Pods(gp.namespace).List(
api.ListOptions{ api.ListOptions{
LabelSelector: labels.Set( LabelSelector: labels.Set(
gp.deployment.Spec.Selector.MatchLabels).AsSelector(), gp.deployment.Spec.Selector.MatchLabels).AsSelector(),
@@ -135,7 +136,7 @@ func (gp *GenericPool) _choosePod(newLabels map[string]string) (*api.Pod, error)
if err != nil { if err != nil {
return nil, err return nil, err
} }
readyPods := make([]api.Pod, len(podList.Items)) readyPods := make([]v1.Pod, len(podList.Items))
for _, pod := range podList.Items { for _, pod := range podList.Items {
podReady := true podReady := true
for _, cs := range pod.Status.ContainerStatuses { for _, cs := range pod.Status.ContainerStatuses {
@@ -164,7 +165,7 @@ func (gp *GenericPool) _choosePod(newLabels map[string]string) (*api.Pod, error)
// modified, this should fail; in that case just // modified, this should fail; in that case just
// retry. // retry.
chosenPod.ObjectMeta.Labels = newLabels chosenPod.ObjectMeta.Labels = newLabels
_, err = gp.kubernetesClient.Pods(gp.namespace).Update(&chosenPod) _, err = gp.kubernetesClient.Core().Pods(gp.namespace).Update(&chosenPod)
if err != nil { if err != nil {
log.Printf("failed to relabel pod: %v", err) log.Printf("failed to relabel pod: %v", err)
continue continue
@@ -184,7 +185,7 @@ func labelsForMetadata(metadata *fission.Metadata) map[string]string {
// specializePod chooses a pod, copies the required user-defined function to that pod // specializePod chooses a pod, copies the required user-defined function to that pod
// (via fetcher), and calls the function-run container to load it, resulting in a // (via fetcher), and calls the function-run container to load it, resulting in a
// specialized pod. // specialized pod.
func (gp *GenericPool) specializePod(metadata *fission.Metadata) (*api.Pod, error) { func (gp *GenericPool) specializePod(metadata *fission.Metadata) (*v1.Pod, error) {
newLabels := labelsForMetadata(metadata) newLabels := labelsForMetadata(metadata)
pod, err := gp.choosePod(newLabels) pod, err := gp.choosePod(newLabels)
@@ -200,8 +201,8 @@ func (gp *GenericPool) specializePod(metadata *fission.Metadata) (*api.Pod, erro
// tell fetcher to get the function // tell fetcher to get the function
fetcherUrl := fmt.Sprintf("http://%v:8000/", podIP) fetcherUrl := fmt.Sprintf("http://%v:8000/", podIP)
functionUrl := fmt.Sprintf("http://%v/v1/functions/%v?uid=%v&raw=1", functionUrl := fmt.Sprintf("%v/v1/functions/%v?uid=%v&raw=1",
gp.controllerHostName, metadata.Name, metadata.Uid) gp.controllerUrl, metadata.Name, metadata.Uid)
fetcherRequest := fmt.Sprintf("{\"url\": \"%v\", \"filename\": \"user\"}", functionUrl) fetcherRequest := fmt.Sprintf("{\"url\": \"%v\", \"filename\": \"user\"}", functionUrl)
resp, err := http.Post(fetcherUrl, "application/json", bytes.NewReader([]byte(fetcherRequest))) resp, err := http.Post(fetcherUrl, "application/json", bytes.NewReader([]byte(fetcherRequest)))
@@ -234,52 +235,52 @@ func (gp *GenericPool) createPool() error {
} }
sharedMountPath := "/userfunc" sharedMountPath := "/userfunc"
deployment := &extensions.Deployment{ deployment := &v1beta1.Deployment{
ObjectMeta: api.ObjectMeta{ ObjectMeta: v1.ObjectMeta{
Name: poolDeploymentName, Name: poolDeploymentName,
Labels: map[string]string{ Labels: map[string]string{
"environmentName": gp.env.Metadata.Name, "environmentName": gp.env.Metadata.Name,
"environmentUid": gp.env.Metadata.Uid, "environmentUid": gp.env.Metadata.Uid,
}, },
}, },
Spec: extensions.DeploymentSpec{ Spec: v1beta1.DeploymentSpec{
Replicas: int32(gp.replicas), Replicas: &gp.replicas,
Selector: &apiUnversioned.LabelSelector{ Selector: &v1beta1.LabelSelector{
MatchLabels: podLabels, MatchLabels: podLabels,
}, },
Template: api.PodTemplateSpec{ Template: v1.PodTemplateSpec{
ObjectMeta: api.ObjectMeta{ ObjectMeta: v1.ObjectMeta{
Labels: podLabels, Labels: podLabels,
}, },
Spec: api.PodSpec{ Spec: v1.PodSpec{
Volumes: []api.Volume{ Volumes: []v1.Volume{
api.Volume{ v1.Volume{
Name: "userfunc", Name: "userfunc",
VolumeSource: api.VolumeSource{ VolumeSource: v1.VolumeSource{
EmptyDir: &api.EmptyDirVolumeSource{}, EmptyDir: &v1.EmptyDirVolumeSource{},
}, },
}, },
}, },
Containers: []api.Container{ Containers: []v1.Container{
api.Container{ v1.Container{
Name: gp.env.Metadata.Name, Name: gp.env.Metadata.Name,
Image: gp.env.RunContainerImageUrl, Image: gp.env.RunContainerImageUrl,
ImagePullPolicy: api.PullIfNotPresent, ImagePullPolicy: v1.PullIfNotPresent,
TerminationMessagePath: "/dev/termination-log", TerminationMessagePath: "/dev/termination-log",
VolumeMounts: []api.VolumeMount{ VolumeMounts: []v1.VolumeMount{
api.VolumeMount{ v1.VolumeMount{
Name: "userfunc", Name: "userfunc",
MountPath: sharedMountPath, MountPath: sharedMountPath,
}, },
}, },
}, },
api.Container{ v1.Container{
Name: "fetcher", Name: "fetcher",
Image: "fission/fetcher", Image: "fission/fetcher",
ImagePullPolicy: api.PullIfNotPresent, ImagePullPolicy: v1.PullIfNotPresent,
TerminationMessagePath: "/dev/termination-log", TerminationMessagePath: "/dev/termination-log",
VolumeMounts: []api.VolumeMount{ VolumeMounts: []v1.VolumeMount{
api.VolumeMount{ v1.VolumeMount{
Name: "userfunc", Name: "userfunc",
MountPath: sharedMountPath, MountPath: sharedMountPath,
}, },
@@ -291,7 +292,7 @@ func (gp *GenericPool) createPool() error {
}, },
}, },
} }
depl, err := gp.kubernetesClient.ExtensionsClient.Deployments(gp.namespace).Create(deployment) depl, err := gp.kubernetesClient.Extensions().Deployments(gp.namespace).Create(deployment)
if err != nil { if err != nil {
return err return err
} }
@@ -303,7 +304,7 @@ func (gp *GenericPool) waitForReadyPod() error {
startTime := time.Now() startTime := time.Now()
for { for {
// TODO: for now we just poll; use a watch instead // TODO: for now we just poll; use a watch instead
depl, err := gp.kubernetesClient.ExtensionsClient.Deployments(gp.namespace).Get(gp.deployment.ObjectMeta.Name) depl, err := gp.kubernetesClient.Extensions().Deployments(gp.namespace).Get(gp.deployment.ObjectMeta.Name)
if err != nil { if err != nil {
log.Printf("err: %v", err) log.Printf("err: %v", err)
return err return err
@@ -320,23 +321,23 @@ func (gp *GenericPool) waitForReadyPod() error {
} }
} }
func (gp *GenericPool) createSvc(name string, labels map[string]string) (*api.Service, error) { func (gp *GenericPool) createSvc(name string, labels map[string]string) (*v1.Service, error) {
service := api.Service{ service := v1.Service{
ObjectMeta: api.ObjectMeta{ ObjectMeta: v1.ObjectMeta{
Name: name, Name: name,
}, },
Spec: api.ServiceSpec{ Spec: v1.ServiceSpec{
Type: api.ServiceTypeClusterIP, Type: v1.ServiceTypeClusterIP,
Ports: []api.ServicePort{ Ports: []v1.ServicePort{
api.ServicePort{ v1.ServicePort{
Protocol: api.ProtocolTCP, Protocol: v1.ProtocolTCP,
Port: 8888, Port: 8888,
}, },
}, },
Selector: labels, Selector: labels,
}, },
} }
svc, err := gp.kubernetesClient.Services(gp.namespace).Create(&service) svc, err := gp.kubernetesClient.Core().Services(gp.namespace).Create(&service)
return svc, err return svc, err
} }
+7 -5
View File
@@ -18,14 +18,15 @@ package poolmgr
import ( import (
"github.com/platform9/fission" "github.com/platform9/fission"
clientUnversioned "k8s.io/kubernetes/pkg/client/unversioned" "k8s.io/client-go/1.4/kubernetes"
) )
type ( type (
GenericPoolManager struct { GenericPoolManager struct {
pools map[fission.Environment]*GenericPool pools map[fission.Environment]*GenericPool
kubernetesClient *clientUnversioned.Client kubernetesClient *kubernetes.Clientset
namespace string namespace string
controllerUrl string
requestChannel chan *request requestChannel chan *request
} }
@@ -39,11 +40,12 @@ type (
} }
) )
func MakeGenericPoolManager(client *clientUnversioned.Client, namespace string) *GenericPoolManager { func MakeGenericPoolManager(controllerUrl string, kubernetesClient *kubernetes.Clientset, namespace string) *GenericPoolManager {
gpm := &GenericPoolManager{ gpm := &GenericPoolManager{
pools: make(map[fission.Environment]*GenericPool), pools: make(map[fission.Environment]*GenericPool),
kubernetesClient: client, kubernetesClient: kubernetesClient,
namespace: namespace, namespace: namespace,
controllerUrl: controllerUrl,
requestChannel: make(chan *request), requestChannel: make(chan *request),
} }
go gpm.service() go gpm.service()
@@ -56,7 +58,7 @@ func (gpm *GenericPoolManager) service() {
case req := <-gpm.requestChannel: case req := <-gpm.requestChannel:
pool, ok := gpm.pools[*req.env] pool, ok := gpm.pools[*req.env]
if !ok { if !ok {
pool, err := MakeGenericPool(gpm.kubernetesClient, req.env, 3, gpm.namespace) pool, err := MakeGenericPool(gpm.controllerUrl, gpm.kubernetesClient, req.env, 3, gpm.namespace)
if err != nil { if err != nil {
req.responseChannel <- &response{error: err} req.responseChannel <- &response{error: err}
continue continue