|
|
|
|
@@ -19,9 +19,11 @@
|
|
|
|
|
package routers
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"github.com/golang/glog"
|
|
|
|
|
"io/ioutil"
|
|
|
|
|
"k8s.io/apimachinery/pkg/api/errors"
|
|
|
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
|
|
|
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
|
|
|
|
"sort"
|
|
|
|
|
|
|
|
|
|
@@ -48,6 +50,37 @@ const (
|
|
|
|
|
SIDECAR_INJECT = "sidecar.istio.io/inject"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var routerTemplates map[string]runtime.Object
|
|
|
|
|
|
|
|
|
|
// Load yamls
|
|
|
|
|
func init() {
|
|
|
|
|
yamls, err := LoadYamls()
|
|
|
|
|
routerTemplates = make(map[string]runtime.Object, 2)
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
glog.Error(err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, f := range yamls {
|
|
|
|
|
decode := scheme.Codecs.UniversalDeserializer().Decode
|
|
|
|
|
obj, _, err := decode([]byte(f), nil, nil)
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
glog.Error(err)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch obj.(type) {
|
|
|
|
|
case *corev1.Service:
|
|
|
|
|
routerTemplates["SERVICE"] = obj
|
|
|
|
|
case *extensionsv1beta1.Deployment:
|
|
|
|
|
routerTemplates["DEPLOYMENT"] = obj
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// get master node ip, if there are multiple master nodes,
|
|
|
|
|
// choose first one according by their names alphabetically
|
|
|
|
|
func getMasterNodeIp() string {
|
|
|
|
|
@@ -115,6 +148,12 @@ func GetAllRouters() ([]*corev1.Service, error) {
|
|
|
|
|
|
|
|
|
|
// Get router from a namespace
|
|
|
|
|
func GetRouter(namespace string) (*corev1.Service, error) {
|
|
|
|
|
service, err := getRouterService(namespace)
|
|
|
|
|
addLoadBalancerIp(service)
|
|
|
|
|
return service, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getRouterService(namespace string) (*corev1.Service, error) {
|
|
|
|
|
serviceName := constants.IngressControllerPrefix + namespace
|
|
|
|
|
|
|
|
|
|
serviceLister := informers.SharedInformerFactory().Core().V1().Services().Lister()
|
|
|
|
|
@@ -127,8 +166,6 @@ func GetRouter(namespace string) (*corev1.Service, error) {
|
|
|
|
|
glog.Error(err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addLoadBalancerIp(service)
|
|
|
|
|
return service, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -163,12 +200,6 @@ func LoadYamls() ([]string, error) {
|
|
|
|
|
// Create a ingress controller in a namespace
|
|
|
|
|
func CreateRouter(namespace string, routerType corev1.ServiceType, annotations map[string]string) (*corev1.Service, error) {
|
|
|
|
|
|
|
|
|
|
k8sClient := k8s.Client()
|
|
|
|
|
|
|
|
|
|
var router *corev1.Service
|
|
|
|
|
|
|
|
|
|
yamls, err := LoadYamls()
|
|
|
|
|
|
|
|
|
|
injectSidecar := false
|
|
|
|
|
if enabled, ok := annotations[SERVICEMESH_ENABLED]; ok {
|
|
|
|
|
if enabled == "true" {
|
|
|
|
|
@@ -176,74 +207,17 @@ func CreateRouter(namespace string, routerType corev1.ServiceType, annotations m
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err := createRouterWorkload(namespace, routerType == corev1.ServiceTypeLoadBalancer, injectSidecar)
|
|
|
|
|
if err != nil {
|
|
|
|
|
glog.Error(err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, f := range yamls {
|
|
|
|
|
decode := scheme.Codecs.UniversalDeserializer().Decode
|
|
|
|
|
obj, _, err := decode([]byte(f), nil, nil)
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
glog.Error(err)
|
|
|
|
|
return router, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch obj.(type) {
|
|
|
|
|
case *corev1.Service:
|
|
|
|
|
service := obj.(*corev1.Service)
|
|
|
|
|
|
|
|
|
|
service.SetAnnotations(annotations)
|
|
|
|
|
service.Spec.Type = routerType
|
|
|
|
|
service.Name = constants.IngressControllerPrefix + namespace
|
|
|
|
|
|
|
|
|
|
// Add project selector
|
|
|
|
|
service.Labels["project"] = namespace
|
|
|
|
|
|
|
|
|
|
service.Spec.Selector["project"] = namespace
|
|
|
|
|
|
|
|
|
|
service, err := k8sClient.CoreV1().Services(constants.IngressControllerNamespace).Create(service)
|
|
|
|
|
if err != nil {
|
|
|
|
|
glog.Error(err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
router = service
|
|
|
|
|
|
|
|
|
|
case *extensionsv1beta1.Deployment:
|
|
|
|
|
deployment := obj.(*extensionsv1beta1.Deployment)
|
|
|
|
|
deployment.Name = constants.IngressControllerPrefix + namespace
|
|
|
|
|
|
|
|
|
|
// Add project label
|
|
|
|
|
deployment.Spec.Selector.MatchLabels["project"] = namespace
|
|
|
|
|
deployment.Spec.Template.Labels["project"] = namespace
|
|
|
|
|
|
|
|
|
|
if injectSidecar {
|
|
|
|
|
if deployment.Spec.Template.Annotations == nil {
|
|
|
|
|
deployment.Spec.Template.Annotations = make(map[string]string, 0)
|
|
|
|
|
}
|
|
|
|
|
deployment.Spec.Template.Annotations[SIDECAR_INJECT] = "true"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Isolate namespace
|
|
|
|
|
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--watch-namespace="+namespace)
|
|
|
|
|
|
|
|
|
|
// Choose self as master
|
|
|
|
|
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--election-id="+deployment.Name)
|
|
|
|
|
|
|
|
|
|
if routerType == corev1.ServiceTypeLoadBalancer {
|
|
|
|
|
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--publish-service="+constants.IngressControllerNamespace+"/"+constants.IngressControllerPrefix+namespace)
|
|
|
|
|
} else {
|
|
|
|
|
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--report-node-internal-ip-address")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
deployment, err := k8sClient.ExtensionsV1beta1().Deployments(constants.IngressControllerNamespace).Create(deployment)
|
|
|
|
|
if err != nil {
|
|
|
|
|
glog.Error(err)
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
//glog.Info("Default resource")
|
|
|
|
|
}
|
|
|
|
|
router, err := createRouterService(namespace, routerType, annotations)
|
|
|
|
|
if err != nil {
|
|
|
|
|
glog.Error(err)
|
|
|
|
|
_ = deleteRouterWorkload(namespace)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addLoadBalancerIp(router)
|
|
|
|
|
@@ -253,10 +227,85 @@ func CreateRouter(namespace string, routerType corev1.ServiceType, annotations m
|
|
|
|
|
// DeleteRouter is used to delete ingress controller related resources in namespace
|
|
|
|
|
// It will not delete ClusterRole resource cause it maybe used by other controllers
|
|
|
|
|
func DeleteRouter(namespace string) (*corev1.Service, error) {
|
|
|
|
|
err := deleteRouterWorkload(namespace)
|
|
|
|
|
if err != nil {
|
|
|
|
|
glog.Error(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
router, err := deleteRouterService(namespace)
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
glog.Error(err)
|
|
|
|
|
return router, err
|
|
|
|
|
}
|
|
|
|
|
return router, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func createRouterService(namespace string, routerType corev1.ServiceType, annotations map[string]string) (*corev1.Service, error) {
|
|
|
|
|
|
|
|
|
|
obj, ok := routerTemplates["SERVICE"]
|
|
|
|
|
if !ok {
|
|
|
|
|
glog.Error("service template not loaded")
|
|
|
|
|
return nil, fmt.Errorf("service template not loaded")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
k8sClient := k8s.Client()
|
|
|
|
|
|
|
|
|
|
var err error
|
|
|
|
|
var router *corev1.Service
|
|
|
|
|
service := obj.(*corev1.Service)
|
|
|
|
|
|
|
|
|
|
service.SetAnnotations(annotations)
|
|
|
|
|
service.Spec.Type = routerType
|
|
|
|
|
service.Name = constants.IngressControllerPrefix + namespace
|
|
|
|
|
|
|
|
|
|
// Add project selector
|
|
|
|
|
service.Labels["project"] = namespace
|
|
|
|
|
|
|
|
|
|
service.Spec.Selector["project"] = namespace
|
|
|
|
|
|
|
|
|
|
service, err := k8sClient.CoreV1().Services(constants.IngressControllerNamespace).Create(service)
|
|
|
|
|
if err != nil {
|
|
|
|
|
glog.Error(err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return service, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func updateRouterService(namespace string, routerType corev1.ServiceType, annotations map[string]string) (*corev1.Service, error) {
|
|
|
|
|
|
|
|
|
|
k8sClient := k8s.Client()
|
|
|
|
|
|
|
|
|
|
service, err := getRouterService(namespace)
|
|
|
|
|
if err != nil {
|
|
|
|
|
glog.Error(err, "get router failed")
|
|
|
|
|
return service, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
service.Spec.Type = routerType
|
|
|
|
|
|
|
|
|
|
originalAnnotations := service.GetAnnotations()
|
|
|
|
|
|
|
|
|
|
for key, val := range annotations {
|
|
|
|
|
originalAnnotations[key] = val
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
service.SetAnnotations(originalAnnotations)
|
|
|
|
|
|
|
|
|
|
service, err = k8sClient.CoreV1().Services(constants.IngressControllerNamespace).Update(service)
|
|
|
|
|
|
|
|
|
|
return service, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func deleteRouterService(namespace string) (*corev1.Service, error) {
|
|
|
|
|
|
|
|
|
|
service, err := getRouterService(namespace)
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
glog.Error(err)
|
|
|
|
|
return service, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
k8sClient := k8s.Client()
|
|
|
|
|
|
|
|
|
|
// delete controller service
|
|
|
|
|
serviceName := constants.IngressControllerPrefix + namespace
|
|
|
|
|
@@ -265,11 +314,63 @@ func DeleteRouter(namespace string) (*corev1.Service, error) {
|
|
|
|
|
err = k8sClient.CoreV1().Services(constants.IngressControllerNamespace).Delete(serviceName, &deleteOptions)
|
|
|
|
|
if err != nil {
|
|
|
|
|
glog.Error(err)
|
|
|
|
|
return service, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return service, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func createRouterWorkload(namespace string, publishService bool, servicemeshEnabled bool) error {
|
|
|
|
|
obj, ok := routerTemplates["DEPLOYMENT"]
|
|
|
|
|
if !ok {
|
|
|
|
|
glog.Error("Deployment template file not loaded")
|
|
|
|
|
return fmt.Errorf("deployment template file not loaded")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
k8sClient := k8s.Client()
|
|
|
|
|
|
|
|
|
|
deployment := obj.(*extensionsv1beta1.Deployment)
|
|
|
|
|
deployment.Name = constants.IngressControllerPrefix + namespace
|
|
|
|
|
|
|
|
|
|
// Add project label
|
|
|
|
|
deployment.Spec.Selector.MatchLabels["project"] = namespace
|
|
|
|
|
deployment.Spec.Template.Labels["project"] = namespace
|
|
|
|
|
|
|
|
|
|
if servicemeshEnabled {
|
|
|
|
|
if deployment.Spec.Template.Annotations == nil {
|
|
|
|
|
deployment.Spec.Template.Annotations = make(map[string]string, 0)
|
|
|
|
|
}
|
|
|
|
|
deployment.Spec.Template.Annotations[SIDECAR_INJECT] = "true"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Isolate namespace
|
|
|
|
|
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--watch-namespace="+namespace)
|
|
|
|
|
|
|
|
|
|
// Choose self as master
|
|
|
|
|
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--election-id="+deployment.Name)
|
|
|
|
|
|
|
|
|
|
if publishService {
|
|
|
|
|
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--publish-service="+constants.IngressControllerNamespace+"/"+constants.IngressControllerPrefix+namespace)
|
|
|
|
|
} else {
|
|
|
|
|
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--report-node-internal-ip-address")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
deployment, err := k8sClient.ExtensionsV1beta1().Deployments(constants.IngressControllerNamespace).Create(deployment)
|
|
|
|
|
if err != nil {
|
|
|
|
|
glog.Error(err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func deleteRouterWorkload(namespace string) error {
|
|
|
|
|
k8sClient := k8s.Client()
|
|
|
|
|
|
|
|
|
|
deleteOptions := meta_v1.DeleteOptions{}
|
|
|
|
|
// delete controller deployment
|
|
|
|
|
deploymentName := constants.IngressControllerPrefix + namespace
|
|
|
|
|
err = k8sClient.ExtensionsV1beta1().Deployments(constants.IngressControllerNamespace).Delete(deploymentName, &deleteOptions)
|
|
|
|
|
err := k8sClient.ExtensionsV1beta1().Deployments(constants.IngressControllerNamespace).Delete(deploymentName, &deleteOptions)
|
|
|
|
|
if err != nil {
|
|
|
|
|
glog.Error(err)
|
|
|
|
|
}
|
|
|
|
|
@@ -280,45 +381,60 @@ func DeleteRouter(namespace string) (*corev1.Service, error) {
|
|
|
|
|
"app": "kubesphere",
|
|
|
|
|
"component": "ks-router",
|
|
|
|
|
"tier": "backend",
|
|
|
|
|
"project": deploymentName,
|
|
|
|
|
"project": namespace,
|
|
|
|
|
})
|
|
|
|
|
replicaSetLister := informers.SharedInformerFactory().Apps().V1().ReplicaSets().Lister()
|
|
|
|
|
replicaSets, err := replicaSetLister.ReplicaSets(constants.IngressControllerNamespace).List(selector)
|
|
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
if err != nil {
|
|
|
|
|
glog.Error(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for i := range replicaSets {
|
|
|
|
|
err = k8sClient.AppsV1().ReplicaSets(constants.IngressControllerNamespace).Delete(replicaSets[i].Name, &deleteOptions)
|
|
|
|
|
glog.Error(err)
|
|
|
|
|
if err != nil {
|
|
|
|
|
glog.Error(err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return router, nil
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update Ingress Controller Service, change type from NodePort to Loadbalancer or vice versa.
|
|
|
|
|
// Update Ingress Controller Service, change type from NodePort to loadbalancer or vice versa.
|
|
|
|
|
func UpdateRouter(namespace string, routerType corev1.ServiceType, annotations map[string]string) (*corev1.Service, error) {
|
|
|
|
|
var router *corev1.Service
|
|
|
|
|
|
|
|
|
|
router, err := GetRouter(namespace)
|
|
|
|
|
router, err := getRouterService(namespace)
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
glog.Error(err)
|
|
|
|
|
return router, nil
|
|
|
|
|
return router, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
router, err = DeleteRouter(namespace)
|
|
|
|
|
routerAnnotations := router.GetAnnotations()
|
|
|
|
|
|
|
|
|
|
if routerAnnotations[SERVICEMESH_ENABLED] != annotations[SERVICEMESH_ENABLED] || routerType != router.Spec.Type {
|
|
|
|
|
err = deleteRouterWorkload(namespace)
|
|
|
|
|
if err != nil {
|
|
|
|
|
glog.Error(err)
|
|
|
|
|
return router, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enableServicemesh := annotations[SERVICEMESH_ENABLED] == "true"
|
|
|
|
|
|
|
|
|
|
err := createRouterWorkload(namespace, routerType == corev1.ServiceTypeLoadBalancer, enableServicemesh)
|
|
|
|
|
if err != nil {
|
|
|
|
|
glog.Error(err)
|
|
|
|
|
return router, err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
newRouter, err := updateRouterService(namespace, routerType, annotations)
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
glog.Error(err)
|
|
|
|
|
return newRouter, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
router, err = CreateRouter(namespace, routerType, annotations)
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
glog.Error(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return router, nil
|
|
|
|
|
return newRouter, nil
|
|
|
|
|
}
|
|
|
|
|
|