add route
This commit is contained in:
@@ -1,5 +1,10 @@
|
||||
FROM alpine:3.6
|
||||
RUN apk add --update ca-certificates && update-ca-certificates
|
||||
COPY ./* /usr/local/bin/
|
||||
|
||||
RUN apk add --update ca-certificates \
|
||||
&& update-ca-certificates \
|
||||
&& mkdir -p /etc/kubesphere/ingress-controller
|
||||
|
||||
COPY ./bin/* /usr/local/bin/
|
||||
COPY ./ingress-controller /etc/kubesphere/ingress-controller
|
||||
|
||||
CMD ["sh"]
|
||||
|
||||
4
Makefile
4
Makefile
@@ -86,10 +86,10 @@ fmt-check: fmt-all
|
||||
|
||||
.PHONY: build
|
||||
build: fmt
|
||||
mkdir -p ./tmp/bin
|
||||
mkdir -p ./tmp/bin && cp -r ./install/ ./tmp/
|
||||
$(call get_build_flags)
|
||||
$(RUN_IN_DOCKER) time go install -ldflags '$(BUILD_FLAG)' $(TRAG.Gopkg)/cmd/...
|
||||
@docker build -t $(TARG.Name) -f ./Dockerfile.dev ./tmp/bin
|
||||
@docker build -t $(TARG.Name) -f ./Dockerfile.dev ./tmp
|
||||
@docker image prune -f 1>/dev/null 2>&1
|
||||
@echo "build done"
|
||||
|
||||
|
||||
51
install/ingress-controller/1-clusterrole.yaml
Normal file
51
install/ingress-controller/1-clusterrole.yaml
Normal file
@@ -0,0 +1,51 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kubesphere-router-clusterrole
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- configmaps
|
||||
- endpoints
|
||||
- nodes
|
||||
- pods
|
||||
- secrets
|
||||
verbs:
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- nodes
|
||||
verbs:
|
||||
- get
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- services
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- "extensions"
|
||||
resources:
|
||||
- ingresses
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
- patch
|
||||
- apiGroups:
|
||||
- "extensions"
|
||||
resources:
|
||||
- ingresses/status
|
||||
verbs:
|
||||
- update
|
||||
39
install/ingress-controller/2-role.yaml
Normal file
39
install/ingress-controller/2-role.yaml
Normal file
@@ -0,0 +1,39 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: kubesphere-router-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- configmaps
|
||||
- pods
|
||||
- secrets
|
||||
- namespaces
|
||||
verbs:
|
||||
- get
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- configmaps
|
||||
resourceNames:
|
||||
# Defaults to "<election-id>-<ingress-class>"
|
||||
# Here: "<ingress-controller-leader>-<nginx>"
|
||||
# This has to be adapted if you change either parameter
|
||||
# when launching the nginx-ingress-controller.
|
||||
- "ingress-controller-leader-nginx"
|
||||
verbs:
|
||||
- get
|
||||
- update
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- configmaps
|
||||
verbs:
|
||||
- create
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- endpoints
|
||||
verbs:
|
||||
- get
|
||||
4
install/ingress-controller/3-serviceaccount.yaml
Normal file
4
install/ingress-controller/3-serviceaccount.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: kubesphere-router-serviceaccount
|
||||
11
install/ingress-controller/4-clusterrolebinding.yaml
Normal file
11
install/ingress-controller/4-clusterrolebinding.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: nginx-ingress-clusterrole-nisa-binding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: kubesphere-roter-clusterrole
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: kubesphere-router-serviceaccount
|
||||
11
install/ingress-controller/5-rolebinding.yaml
Normal file
11
install/ingress-controller/5-rolebinding.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: nginx-ingress-role-nisa-binding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: kubesphere-router-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: kubesphere-router-serviceaccount
|
||||
42
install/ingress-controller/6-default-backend.yaml
Normal file
42
install/ingress-controller/6-default-backend.yaml
Normal file
@@ -0,0 +1,42 @@
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: default-http-backend
|
||||
labels:
|
||||
app: kubesphere
|
||||
component: kubesphere-router
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: kubesphere
|
||||
component: kubesphere-router
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: kubesphere
|
||||
component: kubesphere-router
|
||||
spec:
|
||||
terminationGracePeriodSeconds: 60
|
||||
containers:
|
||||
- name: default-http-backend
|
||||
# Any image is permissible as long as:
|
||||
# 1. It serves a 404 page at /
|
||||
# 2. It serves 200 on a /healthz endpoint
|
||||
image: googlecontainer/defaultbackend-amd64:1.4
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 8080
|
||||
scheme: HTTP
|
||||
initialDelaySeconds: 30
|
||||
timeoutSeconds: 5
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
resources:
|
||||
limits:
|
||||
cpu: 10m
|
||||
memory: 20Mi
|
||||
requests:
|
||||
cpu: 10m
|
||||
memory: 20Mi
|
||||
14
install/ingress-controller/7-default-backend-svc.yaml
Normal file
14
install/ingress-controller/7-default-backend-svc.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: default-http-backend
|
||||
labels:
|
||||
app: kubesphere
|
||||
component: kubesphere-router
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: kubespshere
|
||||
component: kubesphere-router
|
||||
6
install/ingress-controller/8-configmap.yaml
Normal file
6
install/ingress-controller/8-configmap.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
kind: ConfigMap
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: nginx-configuration
|
||||
labels:
|
||||
app: ingress-nginx
|
||||
63
install/ingress-controller/9-with-rbac.yaml
Normal file
63
install/ingress-controller/9-with-rbac.yaml
Normal file
@@ -0,0 +1,63 @@
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: kubesphere-router
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: kubesphere-router
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: kubesphere-router
|
||||
annotations:
|
||||
prometheus.io/port: '10254'
|
||||
prometheus.io/scrape: 'true'
|
||||
spec:
|
||||
serviceAccountName: nginx-ingress-serviceaccount
|
||||
containers:
|
||||
- name: nginx-ingress-controller
|
||||
image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.14.0
|
||||
args:
|
||||
- /nginx-ingress-controller
|
||||
- --default-backend-service=$(POD_NAMESPACE)/default-http-backend
|
||||
- --configmap=$(POD_NAMESPACE)/nginx-configuration
|
||||
- --annotations-prefix=nginx.ingress.kubernetes.io
|
||||
- --watch-namespace=$(POD_NAMESPACE)
|
||||
env:
|
||||
- name: POD_NAME
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.name
|
||||
- name: POD_NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 80
|
||||
- name: https
|
||||
containerPort: 443
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 10254
|
||||
scheme: HTTP
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 10
|
||||
successThreshold: 1
|
||||
timeoutSeconds: 1
|
||||
readinessProbe:
|
||||
failureThreshold: 3
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 10254
|
||||
scheme: HTTP
|
||||
periodSeconds: 10
|
||||
successThreshold: 1
|
||||
timeoutSeconds: 1
|
||||
securityContext:
|
||||
runAsNonRoot: false
|
||||
|
||||
21
install/ingress-controller/9.1-static-ip-svc.yaml
Normal file
21
install/ingress-controller/9.1-static-ip-svc.yaml
Normal file
@@ -0,0 +1,21 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: kubesphere-router-gateway
|
||||
labels:
|
||||
app: kubesphere
|
||||
component: kubesphere-router
|
||||
spec:
|
||||
selector:
|
||||
app:
|
||||
type: LoadBalancer
|
||||
ports:
|
||||
- name: http
|
||||
protocol: TCP
|
||||
port: 80
|
||||
targetPort: 80
|
||||
- name: https
|
||||
protocol: TCP
|
||||
port: 443
|
||||
targetPort: 443
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
"kubesphere.io/kubesphere/pkg/apis/v1alpha/volumes"
|
||||
"kubesphere.io/kubesphere/pkg/apis/v1alpha/iam"
|
||||
"kubesphere.io/kubesphere/pkg/apis/v1alpha/components"
|
||||
"kubesphere.io/kubesphere/pkg/apis/v1alpha/routes"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -45,6 +46,9 @@ func init() {
|
||||
containers.Register(ws)
|
||||
iam.Register(ws)
|
||||
components.Register(ws,"/components")
|
||||
|
||||
routes.Register(ws)
|
||||
|
||||
// add webservice to default container
|
||||
restful.Add(ws)
|
||||
|
||||
|
||||
195
pkg/apis/v1alpha/routes/routes_handler.go
Normal file
195
pkg/apis/v1alpha/routes/routes_handler.go
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
Copyright 2018 The KubeSphere 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 routes
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/api/core/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/filter/route"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
)
|
||||
|
||||
func Register(ws *restful.WebService) {
|
||||
ws.Route(ws.GET("/routers").To(GetAllRouters).
|
||||
Doc("Get all routers").
|
||||
Filter(route.RouteLogging).
|
||||
Produces(restful.MIME_JSON))
|
||||
|
||||
ws.Route(ws.GET("/{namespace}/router").To(GetRouter).
|
||||
Doc("Get router of a specified project").
|
||||
Param(ws.PathParameter("namespace", "name of the project").DataType("string")).
|
||||
Filter(route.RouteLogging).
|
||||
Produces(restful.MIME_JSON))
|
||||
|
||||
ws.Route(ws.DELETE("/{namespace}/router").To(DeleteRouter).
|
||||
Doc("Get router of a specified project").
|
||||
Param(ws.PathParameter("namespace", "name of the project").DataType("string")).
|
||||
Filter(route.RouteLogging).
|
||||
Produces(restful.MIME_JSON))
|
||||
|
||||
ws.Route(ws.POST("/{namespace}/router").To(CreateRouter).
|
||||
Doc("Create a router for a specified project").
|
||||
Param(ws.PathParameter("namespace", "name of the project").DataType("string")).
|
||||
Filter(route.RouteLogging).
|
||||
Consumes(restful.MIME_JSON).
|
||||
Produces(restful.MIME_JSON))
|
||||
|
||||
ws.Route(ws.PUT("/{namespace}/router").To(UpdateRouter).
|
||||
Doc("Update a router for a specified project").
|
||||
Param(ws.PathParameter("namespace", "name of the project").DataType("string")).
|
||||
Filter(route.RouteLogging).
|
||||
Consumes(restful.MIME_JSON).
|
||||
Produces(restful.MIME_JSON))
|
||||
}
|
||||
|
||||
// Get all namespace ingress controller services
|
||||
func GetAllRouters(request *restful.Request, response *restful.Response) {
|
||||
|
||||
routers, err := models.GetAllRouters()
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
|
||||
} else {
|
||||
response.WriteAsJson(routers)
|
||||
}
|
||||
}
|
||||
|
||||
// Get ingress controller service for specified namespace
|
||||
func GetRouter(request *restful.Request, response *restful.Response) {
|
||||
|
||||
namespace := request.PathParameter("namespace")
|
||||
router, err := models.GetRouter(namespace)
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
|
||||
} else if router == nil {
|
||||
response.WriteHeaderAndEntity(http.StatusNotFound, constants.MessageResponse{Message: "Reseource Not Found"})
|
||||
} else {
|
||||
response.WriteAsJson(router)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Create ingress controller and related services
|
||||
func CreateRouter(request *restful.Request, response *restful.Response) {
|
||||
|
||||
namespace := request.PathParameter("namespace")
|
||||
|
||||
newRouter := models.Router{}
|
||||
err := request.ReadEntity(&newRouter)
|
||||
|
||||
if err != nil {
|
||||
response.WriteAsJson(err)
|
||||
return
|
||||
}
|
||||
|
||||
var router *v1.Service
|
||||
|
||||
serviceType, annotationMap, err := ParseParameter(newRouter)
|
||||
|
||||
if err != nil {
|
||||
glog.Error("Wrong annotations, missing key or value")
|
||||
response.WriteHeaderAndEntity(http.StatusBadRequest,
|
||||
constants.MessageResponse{Message: "Wrong annotations, missing key or value"})
|
||||
return
|
||||
}
|
||||
|
||||
router, err = models.CreateRouter(namespace, serviceType, annotationMap)
|
||||
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
|
||||
} else {
|
||||
response.WriteAsJson(*router)
|
||||
}
|
||||
}
|
||||
|
||||
// Delete ingress controller and services
|
||||
func DeleteRouter(request *restful.Request, response *restful.Response) {
|
||||
namespace := request.PathParameter("namespace")
|
||||
|
||||
router, err := models.DeleteRouter(namespace)
|
||||
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
|
||||
return
|
||||
} else {
|
||||
response.WriteAsJson(router)
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateRouter(request *restful.Request, response *restful.Response) {
|
||||
|
||||
namespace := request.PathParameter("namespace")
|
||||
|
||||
newRouter := models.Router{}
|
||||
err := request.ReadEntity(&newRouter)
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
serviceType, annotationMap, err := ParseParameter(newRouter)
|
||||
|
||||
router, err := models.UpdateRouter(namespace, serviceType, annotationMap)
|
||||
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
|
||||
return
|
||||
} else {
|
||||
response.WriteAsJson(router)
|
||||
}
|
||||
}
|
||||
|
||||
func ParseParameter(router models.Router) (routerType v1.ServiceType, annotationMap map[string]string, err error) {
|
||||
|
||||
routerType = v1.ServiceTypeNodePort
|
||||
annotationMap = make(map[string]string)
|
||||
|
||||
if strings.Compare(strings.ToLower(router.RouterType), "loadbalancer") == 0 {
|
||||
annotations := router.Annotations
|
||||
|
||||
annotation := strings.FieldsFunc(annotations, func(r rune) bool {
|
||||
return r == ',' || r == '='
|
||||
})
|
||||
|
||||
if len(annotation)%2 != 0 {
|
||||
glog.Error("Wrong annotations, missing key or value")
|
||||
return routerType, annotationMap, errors.New("wrong annotations, missing key or value")
|
||||
}
|
||||
|
||||
for i := 0; i < len(annotation); i += 2 {
|
||||
annotationMap[annotation[i]] = annotation[i+1]
|
||||
}
|
||||
|
||||
return v1.ServiceTypeLoadBalancer, annotationMap, nil
|
||||
} else {
|
||||
return v1.ServiceTypeNodePort, nil, nil
|
||||
}
|
||||
|
||||
}
|
||||
325
pkg/models/routes.go
Normal file
325
pkg/models/routes.go
Normal file
@@ -0,0 +1,325 @@
|
||||
/*
|
||||
Copyright 2018 The KubeSphere 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 models
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"io/ioutil"
|
||||
|
||||
coreV1 "k8s.io/api/core/v1"
|
||||
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
extensionsV1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
"k8s.io/api/rbac/v1beta1"
|
||||
"github.com/golang/glog"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/client"
|
||||
)
|
||||
|
||||
const RouterYamlDirectory = "/etc/kubesphere/ingress-controller/"
|
||||
|
||||
type Router struct {
|
||||
RouterType string `json:"type"`
|
||||
Annotations string `json:"annotations"`
|
||||
}
|
||||
|
||||
func GetAllRouters() ([] *coreV1.Service, error) {
|
||||
|
||||
k8sClient := client.NewK8sClient()
|
||||
|
||||
routers := []*coreV1.Service{}
|
||||
|
||||
opts := metaV1.ListOptions{}
|
||||
|
||||
namespaces, err := k8sClient.CoreV1().Namespaces().List(opts)
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return routers, err
|
||||
}
|
||||
|
||||
opts = metaV1.ListOptions{
|
||||
LabelSelector: "app=kubesphere,component=kubesphere-router",
|
||||
FieldSelector: "metadata.name=kubesphere-router-gateway",
|
||||
}
|
||||
|
||||
for _, namespace := range namespaces.Items {
|
||||
services, err := k8sClient.CoreV1().Services(namespace.Name).List(opts)
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(services.Items) > 0 {
|
||||
routers = append(routers, &services.Items[0])
|
||||
}
|
||||
}
|
||||
|
||||
return routers, nil
|
||||
}
|
||||
|
||||
// Get router from a namespace
|
||||
func GetRouter(namespace string) (*coreV1.Service, error) {
|
||||
k8sClient := client.NewK8sClient()
|
||||
|
||||
var router *coreV1.Service
|
||||
|
||||
opts := metaV1.ListOptions{
|
||||
LabelSelector: "app=kubesphere,component=kubesphere-router",
|
||||
FieldSelector: "metadata.name=kubesphere-router-gateway",
|
||||
}
|
||||
|
||||
services, err := k8sClient.CoreV1().Services(namespace).List(opts)
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(services.Items) > 0 {
|
||||
router = &services.Items[0]
|
||||
}
|
||||
|
||||
return router, nil
|
||||
}
|
||||
|
||||
// Load all resource yamls
|
||||
func LoadYamls() ([]string, error) {
|
||||
|
||||
var yamls []string
|
||||
|
||||
files, err := ioutil.ReadDir(RouterYamlDirectory)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
content, err := ioutil.ReadFile(RouterYamlDirectory + "/" + file.Name())
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return nil, err
|
||||
} else {
|
||||
yamls = append(yamls, string(content))
|
||||
}
|
||||
}
|
||||
|
||||
return yamls, nil
|
||||
}
|
||||
|
||||
func IsRouterService(serviceName string) bool {
|
||||
if strings.Compare(strings.ToLower(serviceName), "default-http-backend") == 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Create a ingress controller in a namespace
|
||||
func CreateRouter(namespace string, routerType coreV1.ServiceType, annotations map[string]string) (*coreV1.Service, error) {
|
||||
|
||||
k8sClient := client.NewK8sClient()
|
||||
|
||||
var router *coreV1.Service
|
||||
|
||||
yamls, err := LoadYamls()
|
||||
|
||||
if err != nil {
|
||||
glog.Error(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 *v1beta1.Role:
|
||||
role := obj.(*v1beta1.Role)
|
||||
role, err := k8sClient.RbacV1beta1().Roles(namespace).Create(role)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
}
|
||||
|
||||
case *v1beta1.ClusterRole:
|
||||
clusterRole := obj.(*v1beta1.ClusterRole)
|
||||
|
||||
clusterRole, err := k8sClient.RbacV1beta1().ClusterRoles().Create(clusterRole)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
}
|
||||
case *v1beta1.ClusterRoleBinding:
|
||||
clusterRoleBinding := obj.(*v1beta1.ClusterRoleBinding)
|
||||
clusterRoleBinding.Subjects[0].Namespace = namespace
|
||||
clusterRoleBinding, err := k8sClient.RbacV1beta1().ClusterRoleBindings().Create(clusterRoleBinding)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
}
|
||||
case *v1beta1.RoleBinding:
|
||||
roleBinding := obj.(*v1beta1.RoleBinding)
|
||||
roleBinding.Subjects[0].Namespace = namespace
|
||||
roleBinding, err := k8sClient.RbacV1beta1().RoleBindings(namespace).Create(roleBinding)
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
}
|
||||
case *coreV1.ServiceAccount:
|
||||
sa := obj.(*coreV1.ServiceAccount)
|
||||
sa, err := k8sClient.CoreV1().ServiceAccounts(namespace).Create(sa)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
}
|
||||
case *coreV1.Service:
|
||||
service := obj.(*coreV1.Service)
|
||||
|
||||
if IsRouterService(service.Name) {
|
||||
service.SetAnnotations(annotations)
|
||||
service.Spec.Type = routerType
|
||||
}
|
||||
|
||||
service, err := k8sClient.CoreV1().Services(namespace).Create(service)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if IsRouterService(service.Name) {
|
||||
router = service
|
||||
}
|
||||
|
||||
case *extensionsV1beta1.Deployment:
|
||||
deployment := obj.(*extensionsV1beta1.Deployment)
|
||||
deployment, err := k8sClient.ExtensionsV1beta1().Deployments(namespace).Create(deployment)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
}
|
||||
default:
|
||||
//glog.Info("Default resource")
|
||||
}
|
||||
}
|
||||
|
||||
return router, nil
|
||||
}
|
||||
|
||||
// DeleteRouter is used to delete ingress controller related resources in namespace
|
||||
// It will not delete ClusterRole resource cause it maybe used other controllers
|
||||
func DeleteRouter(namespace string) (*coreV1.Service, error) {
|
||||
k8sClient := client.NewK8sClient()
|
||||
|
||||
var router *coreV1.Service
|
||||
yamls, err := LoadYamls()
|
||||
|
||||
if err != nil {
|
||||
glog.Error(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
|
||||
}
|
||||
|
||||
options := metaV1.DeleteOptions{}
|
||||
|
||||
switch obj.(type) {
|
||||
case *v1beta1.Role:
|
||||
role := obj.(*v1beta1.Role)
|
||||
err = k8sClient.RbacV1beta1().Roles(namespace).Delete(role.Name, &options)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
}
|
||||
case *v1beta1.ClusterRoleBinding:
|
||||
clusterRoleBinding := obj.(*v1beta1.ClusterRoleBinding)
|
||||
err = k8sClient.RbacV1beta1().ClusterRoleBindings().Delete(clusterRoleBinding.Name, &options)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
}
|
||||
case *v1beta1.RoleBinding:
|
||||
roleBinding := obj.(*v1beta1.RoleBinding)
|
||||
err = k8sClient.RbacV1beta1().RoleBindings(namespace).Delete(roleBinding.Name, &options)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
}
|
||||
case *coreV1.ServiceAccount:
|
||||
sa := obj.(*coreV1.ServiceAccount)
|
||||
err = k8sClient.CoreV1().ServiceAccounts(namespace).Delete(sa.Name, &options)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
}
|
||||
case *coreV1.Service:
|
||||
service := obj.(*coreV1.Service)
|
||||
|
||||
err = k8sClient.CoreV1().Services(namespace).Delete(service.Name, &options)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
}
|
||||
|
||||
if IsRouterService(service.Name) {
|
||||
router = service
|
||||
}
|
||||
|
||||
case *extensionsV1beta1.Deployment:
|
||||
deployment := obj.(*extensionsV1beta1.Deployment)
|
||||
err = k8sClient.ExtensionsV1beta1().Deployments(namespace).Delete(deployment.Name, &options)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
}
|
||||
default:
|
||||
//glog.Info("Default resource")
|
||||
}
|
||||
}
|
||||
|
||||
return router, nil
|
||||
|
||||
}
|
||||
|
||||
// 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) {
|
||||
k8sClient := client.NewK8sClient()
|
||||
|
||||
var router *coreV1.Service
|
||||
|
||||
router, err := GetRouter(namespace)
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return router, nil
|
||||
}
|
||||
|
||||
if router.Spec.Type != routerType {
|
||||
router.Spec.Type = routerType
|
||||
router.SetAnnotations(annotations)
|
||||
|
||||
router, err = k8sClient.CoreV1().Services(namespace).Update(router)
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return router, err
|
||||
}
|
||||
}
|
||||
|
||||
return router, nil
|
||||
|
||||
}
|
||||
33
vendor/k8s.io/kubernetes/pkg/util/slice/BUILD
generated
vendored
Normal file
33
vendor/k8s.io/kubernetes/pkg/util/slice/BUILD
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["slice.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/util/slice",
|
||||
deps = ["//vendor/k8s.io/apimachinery/pkg/util/rand:go_default_library"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["slice_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
91
vendor/k8s.io/kubernetes/pkg/util/slice/slice.go
generated
vendored
Normal file
91
vendor/k8s.io/kubernetes/pkg/util/slice/slice.go
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes 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 slice provides utility methods for common operations on slices.
|
||||
package slice
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
utilrand "k8s.io/apimachinery/pkg/util/rand"
|
||||
)
|
||||
|
||||
// CopyStrings copies the contents of the specified string slice
|
||||
// into a new slice.
|
||||
func CopyStrings(s []string) []string {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
c := make([]string, len(s))
|
||||
copy(c, s)
|
||||
return c
|
||||
}
|
||||
|
||||
// SortStrings sorts the specified string slice in place. It returns the same
|
||||
// slice that was provided in order to facilitate method chaining.
|
||||
func SortStrings(s []string) []string {
|
||||
sort.Strings(s)
|
||||
return s
|
||||
}
|
||||
|
||||
// ShuffleStrings copies strings from the specified slice into a copy in random
|
||||
// order. It returns a new slice.
|
||||
func ShuffleStrings(s []string) []string {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
shuffled := make([]string, len(s))
|
||||
perm := utilrand.Perm(len(s))
|
||||
for i, j := range perm {
|
||||
shuffled[j] = s[i]
|
||||
}
|
||||
return shuffled
|
||||
}
|
||||
|
||||
// ContainsString checks if a given slice of strings contains the provided string.
|
||||
// If a modifier func is provided, it is called with the slice item before the comparation.
|
||||
func ContainsString(slice []string, s string, modifier func(s string) string) bool {
|
||||
for _, item := range slice {
|
||||
if item == s {
|
||||
return true
|
||||
}
|
||||
if modifier != nil && modifier(item) == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// RemoveString returns a newly created []string that contains all items from slice that
|
||||
// are not equal to s and modifier(s) in case modifier func is provided.
|
||||
func RemoveString(slice []string, s string, modifier func(s string) string) []string {
|
||||
newSlice := make([]string, 0)
|
||||
for _, item := range slice {
|
||||
if item == s {
|
||||
continue
|
||||
}
|
||||
if modifier != nil && modifier(item) == s {
|
||||
continue
|
||||
}
|
||||
newSlice = append(newSlice, item)
|
||||
}
|
||||
if len(newSlice) == 0 {
|
||||
// Sanitize for unit tests so we don't need to distinguish empty array
|
||||
// and nil.
|
||||
newSlice = nil
|
||||
}
|
||||
return newSlice
|
||||
}
|
||||
172
vendor/k8s.io/kubernetes/pkg/util/slice/slice_test.go
generated
vendored
Normal file
172
vendor/k8s.io/kubernetes/pkg/util/slice/slice_test.go
generated
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes 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 slice
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCopyStrings(t *testing.T) {
|
||||
var src1 []string
|
||||
dest1 := CopyStrings(src1)
|
||||
|
||||
if !reflect.DeepEqual(src1, dest1) {
|
||||
t.Errorf("%v and %v are not equal", src1, dest1)
|
||||
}
|
||||
|
||||
src2 := []string{}
|
||||
dest2 := CopyStrings(src2)
|
||||
|
||||
if !reflect.DeepEqual(src2, dest2) {
|
||||
t.Errorf("%v and %v are not equal", src2, dest2)
|
||||
}
|
||||
|
||||
src3 := []string{"a", "c", "b"}
|
||||
dest3 := CopyStrings(src3)
|
||||
|
||||
if !reflect.DeepEqual(src3, dest3) {
|
||||
t.Errorf("%v and %v are not equal", src3, dest3)
|
||||
}
|
||||
|
||||
src3[0] = "A"
|
||||
if reflect.DeepEqual(src3, dest3) {
|
||||
t.Errorf("CopyStrings didn't make a copy")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSortStrings(t *testing.T) {
|
||||
src := []string{"a", "c", "b"}
|
||||
dest := SortStrings(src)
|
||||
expected := []string{"a", "b", "c"}
|
||||
|
||||
if !reflect.DeepEqual(dest, expected) {
|
||||
t.Errorf("SortString didn't sort the strings")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(src, expected) {
|
||||
t.Errorf("SortString didn't sort in place")
|
||||
}
|
||||
}
|
||||
|
||||
func TestShuffleStrings(t *testing.T) {
|
||||
var src []string
|
||||
dest := ShuffleStrings(src)
|
||||
|
||||
if dest != nil {
|
||||
t.Errorf("ShuffleStrings for a nil slice got a non-nil slice")
|
||||
}
|
||||
|
||||
src = []string{"a", "b", "c", "d", "e", "f"}
|
||||
dest = ShuffleStrings(src)
|
||||
|
||||
if len(src) != len(dest) {
|
||||
t.Errorf("Shuffled slice is wrong length, expected %v got %v", len(src), len(dest))
|
||||
}
|
||||
|
||||
m := make(map[string]bool, len(dest))
|
||||
for _, s := range dest {
|
||||
m[s] = true
|
||||
}
|
||||
|
||||
for _, k := range src {
|
||||
if _, exists := m[k]; !exists {
|
||||
t.Errorf("Element %v missing from shuffled slice", k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestContainsString(t *testing.T) {
|
||||
src := []string{"aa", "bb", "cc"}
|
||||
if !ContainsString(src, "bb", nil) {
|
||||
t.Errorf("ContainsString didn't find the string as expected")
|
||||
}
|
||||
|
||||
modifier := func(s string) string {
|
||||
if s == "cc" {
|
||||
return "ee"
|
||||
}
|
||||
return s
|
||||
}
|
||||
if !ContainsString(src, "ee", modifier) {
|
||||
t.Errorf("ContainsString didn't find the string by modifier")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveString(t *testing.T) {
|
||||
modifier := func(s string) string {
|
||||
if s == "ab" {
|
||||
return "ee"
|
||||
}
|
||||
return s
|
||||
}
|
||||
tests := []struct {
|
||||
testName string
|
||||
input []string
|
||||
remove string
|
||||
modifier func(s string) string
|
||||
want []string
|
||||
}{
|
||||
{
|
||||
testName: "Nil input slice",
|
||||
input: nil,
|
||||
remove: "",
|
||||
modifier: nil,
|
||||
want: nil,
|
||||
},
|
||||
{
|
||||
testName: "Slice doesn't contain the string",
|
||||
input: []string{"a", "ab", "cdef"},
|
||||
remove: "NotPresentInSlice",
|
||||
modifier: nil,
|
||||
want: []string{"a", "ab", "cdef"},
|
||||
},
|
||||
{
|
||||
testName: "All strings removed, result is nil",
|
||||
input: []string{"a"},
|
||||
remove: "a",
|
||||
modifier: nil,
|
||||
want: nil,
|
||||
},
|
||||
{
|
||||
testName: "No modifier func, one string removed",
|
||||
input: []string{"a", "ab", "cdef"},
|
||||
remove: "ab",
|
||||
modifier: nil,
|
||||
want: []string{"a", "cdef"},
|
||||
},
|
||||
{
|
||||
testName: "No modifier func, all(three) strings removed",
|
||||
input: []string{"ab", "a", "ab", "cdef", "ab"},
|
||||
remove: "ab",
|
||||
modifier: nil,
|
||||
want: []string{"a", "cdef"},
|
||||
},
|
||||
{
|
||||
testName: "Removed both the string and the modifier func result",
|
||||
input: []string{"a", "cd", "ab", "ee"},
|
||||
remove: "ee",
|
||||
modifier: modifier,
|
||||
want: []string{"a", "cd"},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
if got := RemoveString(tt.input, tt.remove, tt.modifier); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("%v: RemoveString(%v, %q, %T) = %v WANT %v", tt.testName, tt.input, tt.remove, tt.modifier, got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user