Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: add fetch ingress list and ingress detail from k8s cluster api to backend #169

Merged
merged 9 commits into from
Jan 3, 2019
79 changes: 77 additions & 2 deletions src/backend/controllers/kubernetes/ingress/ingress.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ func (c *KubeIngressController) URLMapping() {
c.Mapping("Get", c.Get)
c.Mapping("Offline", c.Offline)
c.Mapping("Deploy", c.Deploy)
c.Mapping("List", c.List)
c.Mapping("GetDetail", c.GetDetail)
}

func (c *KubeIngressController) Prepare() {
Expand All @@ -40,6 +42,39 @@ func (c *KubeIngressController) Prepare() {
}
}

// @Title List ingress
// @Description get all ingress in a kubernetes cluster
// @Param pageNo query int false "the page current no"
// @Param pageSize query int false "the page size"
// @Param filter query string false "column filter, ex. filter=name=test"
// @Param sortby query string false "column sorted by, ex. sortby=-id, '-' representation desc, and sortby=id representation asc"
// @Param cluster path string true "the cluster name"
// @Param namespace path string true "the namespace name"
// @Success 200 {object} common.Page success
// @router /namespaces/:namespace/clusters/:cluster [get]
func (c *KubeIngressController) List() {
param := c.BuildQueryParam()
cluster := c.Ctx.Input.Param(":cluster")
namespace := c.Ctx.Input.Param(":namespace")

k8sClient, err := client.Client(cluster)
if err != nil {
c.AbortBadRequestFormat("Cluster")
}
res, err := ingress.GetIngressPage(k8sClient, namespace, param)
if err != nil {
logs.Error("list kubernetes(%s) namespace(%s) ingresses error %v", cluster, namespace, err)
c.HandleError(err)
return
}
c.Success(res)
}

// @Title deploy
// @Description deploy tpl
// @Param body body string true "The tpl content"
// @Success 200 return ok success
// @router /:ingressId([0-9]+)/tpls/:tplId([0-9]+)/clusters/:cluster [post]
func (c *KubeIngressController) Deploy() {
ingressId := c.GetIntParamFromURL(":ingressId")
tplId := c.GetIntParamFromURL(":tplId")
Expand Down Expand Up @@ -69,6 +104,7 @@ func (c *KubeIngressController) Deploy() {
logs.Critical("insert log into database failed: %s", err)
}
}()
// ingressDetail include endpoints
_, err = ingress.CreateOrUpdateIngress(k8sClient, &kubeIngress)
if err != nil {
publishHistory.Status = models.ReleaseFailure
Expand All @@ -77,6 +113,7 @@ func (c *KubeIngressController) Deploy() {
c.HandleError(err)
return
}

publishHistory.Status = models.ReleaseSuccess
publishStatus := models.PublishStatus{
ResourceId: int64(ingressId),
Expand All @@ -103,16 +140,47 @@ func (c *KubeIngressController) Deploy() {
c.Success("ok")
}

// @Title GetDetail
// @Description find ingress detail in kubernetes
// @Param ingress path string true "the ingress name"
// @Param cluster path string true "the cluster name"
// @Param namespace path string true "the namespace name"
// @Success 200 {object} ingress.Ingress success
// @router /:ingress/detail/namespaces/:namespace/clusters/:cluster [get]

func (c *KubeIngressController) GetDetail() {
cluster := c.Ctx.Input.Param(":cluster")
namespace := c.Ctx.Input.Param(":namespace")
name := c.Ctx.Input.Param(":ingress")
k8sClient, err := client.Client(cluster)
if err != nil {
c.AbortBadRequest("Cluster")
}
res, err := ingress.GetIngressDetail(k8sClient, name, namespace)
if err != nil {
logs.Error("get kubernetes ingress detail err %v", err)
c.HandleError(err)
return
}
c.Success(res)
}

// @Title Get
// @Description find Deployment by cluster
// @Param cluster path string true "the cluster name"
// @Param namespace path string true "the namespace name"
// @Success 200 {object} models.Deployment success
// @router /:ingress/namespaces/:namespace/clusters/:cluster [get]
func (c *KubeIngressController) Get() {
cluster := c.Ctx.Input.Param(":cluster")
namespace := c.Ctx.Input.Param(":namespace")
name := c.Ctx.Input.Param(":ingress")
k8sClinet, err := client.Client(cluster)
k8sClient, err := client.Client(cluster)
if err != nil {
c.AbortBadRequestFormat("Cluster")
return
}
res, err := ingress.GetIngressDetail(k8sClinet, name, namespace)
res, err := ingress.GetIngress(k8sClient, name, namespace)
if err != nil {
logs.Error("get ingress error cluster: %s, namespace: %s", cluster, namespace)
c.HandleError(err)
Expand All @@ -121,6 +189,13 @@ func (c *KubeIngressController) Get() {
c.Success(res)
}

// @Title Delete
// @Description delete the Ingress
// @Param cluster path string true "the cluster want to delete"
// @Param namespace path string true "the namespace want to delete"
// @Param deployment path string true "the deployment name want to delete"
// @Success 200 {string} delete success!
// @router /:ingress/namespaces/:namespace/clusters/:cluster [delete]
func (c *KubeIngressController) Offline() {
cluster := c.Ctx.Input.Param(":cluster")
namespace := c.Ctx.Input.Param(":namespace")
Expand Down
39 changes: 39 additions & 0 deletions src/backend/resources/ingress/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package ingress

import (
"github.com/Qihoo360/wayne/src/backend/resources/dataselector"
)

// The code below allows to perform complex data section on []extensions.Ingress

type IngressCell Ingress

func (self IngressCell) GetProperty(name dataselector.PropertyName) dataselector.ComparableValue {
switch name {
case dataselector.NameProperty:
return dataselector.StdComparableString(self.ObjectMeta.Name)
case dataselector.CreationTimestampProperty:
return dataselector.StdComparableTime(self.ObjectMeta.CreationTimestamp.Time)
case dataselector.NamespaceProperty:
return dataselector.StdComparableString(self.ObjectMeta.Namespace)
default:
// if name is not supported then just return a constant dummy value, sort will have no effect.
return nil
}
}

func toCells(std []Ingress) []dataselector.DataCell {
cells := make([]dataselector.DataCell, len(std))
for i := range std {
cells[i] = IngressCell(std[i])
}
return cells
}

func fromCells(cells []dataselector.DataCell) []Ingress {
std := make([]Ingress, len(cells))
for i := range std {
std[i] = Ingress(cells[i].(IngressCell))
}
return std
}
39 changes: 33 additions & 6 deletions src/backend/resources/ingress/ingress.go
Original file line number Diff line number Diff line change
@@ -1,32 +1,59 @@
package ingress

import (
k8sv1beta1 "k8s.io/api/extensions/v1beta1"
"k8s.io/api/extensions/v1beta1"
"k8s.io/apimachinery/pkg/api/errors"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)

func CreateOrUpdateIngress(c *kubernetes.Clientset, ingress *k8sv1beta1.Ingress) (*k8sv1beta1.Ingress, error) {
func CreateOrUpdateIngress(c *kubernetes.Clientset, ingress *v1beta1.Ingress) (*Ingress, error) {
old, err := c.ExtensionsV1beta1().Ingresses(ingress.Namespace).Get(ingress.Name, metaV1.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
return c.ExtensionsV1beta1().Ingresses(ingress.Namespace).Create(ingress)
kubeIngress, err := c.ExtensionsV1beta1().Ingresses(ingress.Namespace).Create(ingress)
if err != nil {
return nil, err
}
return toIngress(kubeIngress), nil
}
return nil, err
}
ingress.Spec.DeepCopyInto(&old.Spec)
return c.ExtensionsV1beta1().Ingresses(ingress.Namespace).Update(old)
kubeIngress, err := c.ExtensionsV1beta1().Ingresses(ingress.Namespace).Update(old)
if err != nil {
return nil, err
}
return toIngress(kubeIngress), nil
}

func GetIngressDetail(c *kubernetes.Clientset, name, namespace string) (*k8sv1beta1.Ingress, error) {
func GetIngressDetail(c *kubernetes.Clientset, name, namespace string) (*Ingress, error) {
ingress, err := c.ExtensionsV1beta1().Ingresses(namespace).Get(name, metaV1.GetOptions{})
if err != nil {
return nil, err
}
return ingress, nil
return toIngress(ingress), nil
}

func GetIngress(c *kubernetes.Clientset, name, namespace string) (ingress *v1beta1.Ingress, err error) {
ingress, err = c.ExtensionsV1beta1().Ingresses(namespace).Get(name, metaV1.GetOptions{})
if err != nil {
return nil, err
}
return
}

func DeleteIngress(c *kubernetes.Clientset, name, namespace string) error {
return c.ExtensionsV1beta1().Ingresses(namespace).Delete(name, &metaV1.DeleteOptions{})
}

func GetIngressList(cli *kubernetes.Clientset, namespace string, opts metaV1.ListOptions) (list []*Ingress, err error) {
kubeIngressList, err := cli.ExtensionsV1beta1().Ingresses(namespace).List(opts)
if err != nil {
return nil, err
}
for _, kubeIngress := range kubeIngressList.Items {
list = append(list, toIngress(&kubeIngress))
}
return
}
48 changes: 48 additions & 0 deletions src/backend/resources/ingress/list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package ingress

import (
backendCommon "github.com/Qihoo360/wayne/src/backend/common"
"github.com/Qihoo360/wayne/src/backend/resources/common"
"github.com/Qihoo360/wayne/src/backend/resources/dataselector"
extensions "k8s.io/api/extensions/v1beta1"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)

type Ingress struct {
common.ObjectMeta `json:"objectMeta"`
common.TypeMeta `json:"typeMeta"`
Endpoints []common.Endpoint `json:"endpoints"`
}

func getEndpoints(ingress *extensions.Ingress) []common.Endpoint {
endpoints := make([]common.Endpoint, 0)
if len(ingress.Status.LoadBalancer.Ingress) > 0 {
for _, status := range ingress.Status.LoadBalancer.Ingress {
endpoint := common.Endpoint{Host: status.IP}
endpoints = append(endpoints, endpoint)
}
}
return endpoints
}

func toIngress(ingress *extensions.Ingress) *Ingress {
modelIngress := &Ingress{
ObjectMeta: common.NewObjectMeta(ingress.ObjectMeta),
TypeMeta: common.NewTypeMeta("ingress"),
Endpoints: getEndpoints(ingress),
}
return modelIngress
}

func GetIngressPage(cli *kubernetes.Clientset, namespace string, q *backendCommon.QueryParam) (page *backendCommon.Page, err error) {
ingressPtrs, err := GetIngressList(cli, namespace, metaV1.ListOptions{})
if err != nil {
return nil, err
}
ingresses := make([]Ingress, len(ingressPtrs))
for i := range ingressPtrs {
ingresses[i] = *ingressPtrs[i]
}
return dataselector.DataSelectPage(toCells(ingresses), q), nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,45 @@ import (
)

func init() {

beego.GlobalControllerRouter["github.com/Qihoo360/wayne/src/backend/controllers/kubernetes/ingress:KubeIngressController"] = append(beego.GlobalControllerRouter["github.com/Qihoo360/wayne/src/backend/controllers/kubernetes/ingress:KubeIngressController"],
beego.ControllerComments{
Method: "GetDetail",
Router: `/:ingress/detail/namespaces/:namespace/clusters/:cluster`,
AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(),
Params: nil})

beego.GlobalControllerRouter["github.com/Qihoo360/wayne/src/backend/controllers/kubernetes/ingress:KubeIngressController"] = append(beego.GlobalControllerRouter["github.com/Qihoo360/wayne/src/backend/controllers/kubernetes/ingress:KubeIngressController"],
beego.ControllerComments{
Method: "Get",
Router: `/:ingress/namespaces/:namespace/clusters/:cluster`,
AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(),
Params: nil,
},
Params: nil})

beego.GlobalControllerRouter["github.com/Qihoo360/wayne/src/backend/controllers/kubernetes/ingress:KubeIngressController"] = append(beego.GlobalControllerRouter["github.com/Qihoo360/wayne/src/backend/controllers/kubernetes/ingress:KubeIngressController"],
beego.ControllerComments{
Method: "Offline",
Router: `/:ingress/namespaces/:namespace/clusters/:cluster`,
AllowHTTPMethods: []string{"delete"},
MethodParams: param.Make(),
Params: nil,
},
Params: nil})

beego.GlobalControllerRouter["github.com/Qihoo360/wayne/src/backend/controllers/kubernetes/ingress:KubeIngressController"] = append(beego.GlobalControllerRouter["github.com/Qihoo360/wayne/src/backend/controllers/kubernetes/ingress:KubeIngressController"],
beego.ControllerComments{
Method: "Deploy",
Router: `/:ingressId/tpls/:tplId/clusters/:cluster`,
Router: `/:ingressId([0-9]+)/tpls/:tplId([0-9]+)/clusters/:cluster`,
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Params: nil,
})
Params: nil})

beego.GlobalControllerRouter["github.com/Qihoo360/wayne/src/backend/controllers/kubernetes/ingress:KubeIngressController"] = append(beego.GlobalControllerRouter["github.com/Qihoo360/wayne/src/backend/controllers/kubernetes/ingress:KubeIngressController"],
beego.ControllerComments{
Method: "List",
Router: `/namespaces/:namespace/clusters/:cluster`,
AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(),
Params: nil})

}