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

cherry pick #3192 #3205 to 2.0.0 #3203

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 81 additions & 11 deletions pkg/microservice/aslan/core/common/service/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package service

import (
"context"
"encoding/json"
"fmt"
"sort"
Expand All @@ -29,7 +30,10 @@ import (
"go.mongodb.org/mongo-driver/mongo"
"go.uber.org/zap"
"gopkg.in/yaml.v3"
"istio.io/client-go/pkg/apis/networking/v1alpha3"
versionedclient "istio.io/client-go/pkg/clientset/versioned"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/util/sets"
Expand All @@ -55,6 +59,7 @@ import (
"github.com/koderover/zadig/pkg/tool/kube/getter"
"github.com/koderover/zadig/pkg/tool/kube/informer"
"github.com/koderover/zadig/pkg/tool/log"
zadigtypes "github.com/koderover/zadig/pkg/types"
"github.com/koderover/zadig/pkg/util"
jsonutil "github.com/koderover/zadig/pkg/util/json"
)
Expand All @@ -80,17 +85,18 @@ func FillProductTemplateValuesYamls(tmpl *templatemodels.Product, production boo
}

type ServiceResp struct {
ServiceName string `json:"service_name"`
ReleaseName string `json:"release_name"`
IsHelmChartDeploy bool `json:"is_helm_chart_deploy"`
ServiceDisplayName string `json:"service_display_name"`
Type string `json:"type"`
Status string `json:"status"`
Error string `json:"error"`
Images []string `json:"images,omitempty"`
ProductName string `json:"product_name"`
EnvName string `json:"env_name"`
Ingress *IngressInfo `json:"ingress"`
ServiceName string `json:"service_name"`
ReleaseName string `json:"release_name"`
IsHelmChartDeploy bool `json:"is_helm_chart_deploy"`
ServiceDisplayName string `json:"service_display_name"`
Type string `json:"type"`
Status string `json:"status"`
Error string `json:"error"`
Images []string `json:"images,omitempty"`
ProductName string `json:"product_name"`
EnvName string `json:"env_name"`
Ingress *IngressInfo `json:"ingress"`
IstioGateway *IstioGatewayInfo `json:"istio_gateway"`
//deprecated
Ready string `json:"ready"`
EnvStatuses []*models.EnvStatus `json:"env_statuses,omitempty"`
Expand All @@ -109,6 +115,16 @@ type IngressInfo struct {
HostInfo []resource.HostInfo `json:"host_info"`
}

type IstioGatewayInfo struct {
Servers []IstioGatewayServer `json:"servers"`
}

type IstioGatewayServer struct {
Host string `json:"host"`
PortProtocol string `json:"port_protocol"`
PortNumber uint32 `json:"port_number"`
}

func UnMarshalSourceDetail(source interface{}) (*models.CreateFromRepo, error) {
bs, err := json.Marshal(source)
if err != nil {
Expand Down Expand Up @@ -664,10 +680,15 @@ func fillServiceName(envName, productName string, workloads []*Workload) error {
if err != nil {
return err
}
releaseServiceNameMap, err := commonutil.GetReleaseNameToServiceNameMap(productInfo)
if err != nil {
return err
}
for _, wl := range workloads {
if chartRelease, ok := wl.Annotation[setting.HelmReleaseNameAnnotation]; ok {
wl.ReleaseName = chartRelease
wl.ChartName = releaseChartNameMap[wl.ReleaseName]
wl.ServiceName = releaseServiceNameMap[wl.ReleaseName]
}
}
return nil
Expand Down Expand Up @@ -778,6 +799,15 @@ func ListWorkloadDetails(envName, clusterID, namespace, productName string, perP
log.Errorf("Failed to get server version info for cluster: %s, the error is: %s", clusterID, err)
return 0, resp, e.ErrListGroups.AddDesc(err.Error())
}
restConfig, err := kubeclient.GetRESTConfig(config.HubServerAddress(), clusterID)
if err != nil {
return 0, resp, e.ErrListGroups.AddErr(fmt.Errorf("failed to get rest config: %s", err))
}
istioClient, err := versionedclient.NewForConfig(restConfig)
if err != nil {
return 0, resp, e.ErrListGroups.AddErr(fmt.Errorf("failed to new istio client: %s", err))
}

count, workLoads, err := ListWorkloads(envName, productName, perPage, page, informer, version, log, filter...)
if err != nil {
log.Errorf("failed to list workloads, [%s][%s], error: %v", namespace, envName, err)
Expand Down Expand Up @@ -805,6 +835,16 @@ func ListWorkloadDetails(envName, clusterID, namespace, productName string, perP
}
}

zadigLabels := map[string]string{
zadigtypes.ZadigLabelKeyGlobalOwner: zadigtypes.Zadig,
}
gwObjs, err := istioClient.NetworkingV1alpha3().Gateways(namespace).List(context.TODO(), metav1.ListOptions{
LabelSelector: labels.FormatLabels(zadigLabels),
})
if err != nil {
return 0, resp, e.ErrListGroups.AddErr(fmt.Errorf("failed to list gateways in ns `%s`: %s", namespace, err))
}

// get all services
allServices, err := getter.ListServicesWithCache(nil, informer)
if err != nil {
Expand Down Expand Up @@ -836,6 +876,9 @@ func ListWorkloadDetails(envName, clusterID, namespace, productName string, perP
productRespInfo.Ingress = &IngressInfo{
HostInfo: FindServiceFromIngress(hostInfos, workload, allServices),
}
productRespInfo.IstioGateway = &IstioGatewayInfo{
Servers: FindServiceFromIstioGateway(gwObjs, workload.ServiceName),
}
} else if workload.Type == setting.CronJob {
productRespInfo.Status = workload.Status
}
Expand Down Expand Up @@ -876,6 +919,33 @@ func FindServiceFromIngress(hostInfos []resource.HostInfo, currentWorkload *Work
return resp
}

func FindServiceFromIstioGateway(gwObjs *v1alpha3.GatewayList, serviceName string) []IstioGatewayServer {
resp := []IstioGatewayServer{}
if len(gwObjs.Items) == 0 {
return resp
}
gatewayName := commonutil.GenIstioGatewayName(serviceName)
for _, gwObj := range gwObjs.Items {
if gwObj.Name == gatewayName {
for _, serverObj := range gwObj.Spec.Servers {
if len(serverObj.Hosts) == 0 {
continue
}

server := IstioGatewayServer{
Host: serverObj.Hosts[0],
PortProtocol: serverObj.Port.Protocol,
PortNumber: serverObj.Port.Number,
}
resp = append(resp, server)
}
break
}
}

return resp
}

// GetHelmServiceName get service name from annotations of resources deployed by helm
// resType currently only support Deployment, StatefulSet and CronJob
// this function needs to be optimized
Expand Down
6 changes: 3 additions & 3 deletions pkg/microservice/aslan/core/common/service/kube/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ func removeResources(currentItems, newItems []*unstructured.Unstructured, namesp
return errList.ErrorOrNil()
}

func manifestToUnstructured(manifest string) ([]*unstructured.Unstructured, error) {
func ManifestToUnstructured(manifest string) ([]*unstructured.Unstructured, error) {
if len(manifest) == 0 {
return nil, nil
}
Expand Down Expand Up @@ -224,13 +224,13 @@ func CreateOrPatchResource(applyParam *ResourceApplyParam, log *zap.SugaredLogge
kubeClient := applyParam.KubeClient
istioClient := applyParam.IstioClient

curResources, err := manifestToUnstructured(applyParam.CurrentResourceYaml)
curResources, err := ManifestToUnstructured(applyParam.CurrentResourceYaml)
if err != nil {
log.Errorf("Failed to convert currently deplyed resource yaml to Unstructured, manifest is\n%s\n, error: %v", applyParam.CurrentResourceYaml, err)
return nil, err
}

resources, err := manifestToUnstructured(applyParam.UpdateResourceYaml)
resources, err := ManifestToUnstructured(applyParam.UpdateResourceYaml)
if err != nil {
log.Errorf("Failed to convert yaml to Unstructured, manifest is\n%s\n, error: %v", applyParam.UpdateResourceYaml, err)
return nil, err
Expand Down
4 changes: 4 additions & 0 deletions pkg/microservice/aslan/core/common/util/enviroment.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,7 @@ func UpdateProductImage(envName, productName, serviceName string, targets map[st

return nil
}

func GenIstioGatewayName(serviceName string) string {
return fmt.Sprintf("%s-gateway-%s", "zadig", serviceName)
}
2 changes: 2 additions & 0 deletions pkg/microservice/aslan/core/environment/handler/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,8 @@ func (*Router) Inject(router *gin.RouterGroup) {
environments.POST("/:name/share/enable", EnableBaseEnv)
environments.DELETE("/:name/share/enable", DisableBaseEnv)
environments.GET("/:name/check/sharenv/:op/ready", CheckShareEnvReady)
environments.GET("/:name/share/portal/:serviceName", GetPortalService)
environments.POST("/:name/share/portal/:serviceName", SetupPortalService)

environments.GET("/:name/services/:serviceName/pmexec", ConnectSshPmExec)

Expand Down
101 changes: 97 additions & 4 deletions pkg/microservice/aslan/core/environment/handler/share_env.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"fmt"

"github.com/gin-gonic/gin"
e "github.com/koderover/zadig/pkg/tool/errors"
"github.com/koderover/zadig/pkg/types"

"github.com/koderover/zadig/pkg/microservice/aslan/core/environment/service"
Expand All @@ -32,7 +33,6 @@ func CheckWorkloadsK8sServices(c *gin.Context) {
defer func() { internalhandler.JSONResponse(c, ctx) }()

if err != nil {

ctx.Err = fmt.Errorf("authorization Info Generation failed: err %s", err)
ctx.UnAuthorized = true
return
Expand Down Expand Up @@ -65,7 +65,6 @@ func EnableBaseEnv(c *gin.Context) {
defer func() { internalhandler.JSONResponse(c, ctx) }()

if err != nil {

ctx.Err = fmt.Errorf("authorization Info Generation failed: err %s", err)
ctx.UnAuthorized = true
return
Expand Down Expand Up @@ -100,7 +99,6 @@ func DisableBaseEnv(c *gin.Context) {
defer func() { internalhandler.JSONResponse(c, ctx) }()

if err != nil {

ctx.Err = fmt.Errorf("authorization Info Generation failed: err %s", err)
ctx.UnAuthorized = true
return
Expand Down Expand Up @@ -137,7 +135,6 @@ func CheckShareEnvReady(c *gin.Context) {
defer func() { internalhandler.JSONResponse(c, ctx) }()

if err != nil {

ctx.Err = fmt.Errorf("authorization Info Generation failed: err %s", err)
ctx.UnAuthorized = true
return
Expand All @@ -164,3 +161,99 @@ func CheckShareEnvReady(c *gin.Context) {

ctx.Resp, ctx.Err = service.CheckShareEnvReady(c, envName, c.Param("op"), projectKey)
}

// @Summary Get Portal Service for Share Env
// @Description Get Portal Service for Share Env
// @Tags environment
// @Accept json
// @Produce json
// @Param projectName query string true "project name"
// @Param name path string true "env name"
// @Param serviceName path string true "service name"
// @Success 200 {object} service.GetPortalServiceResponse
// @Router /api/aslan/environment/environments/{name}/share/portal/{serviceName} [get]
func GetPortalService(c *gin.Context) {
ctx, err := internalhandler.NewContextWithAuthorization(c)
defer func() { internalhandler.JSONResponse(c, ctx) }()

if err != nil {
ctx.Err = fmt.Errorf("authorization Info Generation failed: err %s", err)
ctx.UnAuthorized = true
return
}

envName := c.Param("name")
serviceName := c.Param("serviceName")
projectKey := c.Query("projectName")

// authorization checks
if !ctx.Resources.IsSystemAdmin {
if _, ok := ctx.Resources.ProjectAuthInfo[projectKey]; !ok {
ctx.UnAuthorized = true
return
}
if !ctx.Resources.ProjectAuthInfo[projectKey].IsProjectAdmin &&
!ctx.Resources.ProjectAuthInfo[projectKey].Env.EditConfig {
permitted, err := internalhandler.GetCollaborationModePermission(ctx.UserID, projectKey, types.ResourceTypeEnvironment, envName, types.EnvActionEditConfig)
if err != nil || !permitted {
ctx.UnAuthorized = true
return
}
}
}

ctx.Resp, ctx.Err = service.GetPortalService(c, projectKey, envName, serviceName)
return
}

// @Summary Setup Portal Service for Share Env
// @Description Setup Portal Service for Share Env
// @Tags environment
// @Accept json
// @Produce json
// @Param projectName query string true "project name"
// @Param name path string true "env name"
// @Param serviceName path string true "service name"
// @Param body body []service.SetupPortalServiceRequest true "body"
// @Success 200
// @Router /api/aslan/environment/environments/{name}/share/portal/{serviceName} [post]
func SetupPortalService(c *gin.Context) {
ctx, err := internalhandler.NewContextWithAuthorization(c)
defer func() { internalhandler.JSONResponse(c, ctx) }()

if err != nil {
ctx.Err = fmt.Errorf("authorization Info Generation failed: err %s", err)
ctx.UnAuthorized = true
return
}

envName := c.Param("name")
serviceName := c.Param("serviceName")
projectKey := c.Query("projectName")

// authorization checks
if !ctx.Resources.IsSystemAdmin {
if _, ok := ctx.Resources.ProjectAuthInfo[projectKey]; !ok {
ctx.UnAuthorized = true
return
}
if !ctx.Resources.ProjectAuthInfo[projectKey].IsProjectAdmin &&
!ctx.Resources.ProjectAuthInfo[projectKey].Env.EditConfig {
permitted, err := internalhandler.GetCollaborationModePermission(ctx.UserID, projectKey, types.ResourceTypeEnvironment, envName, types.EnvActionEditConfig)
if err != nil || !permitted {
ctx.UnAuthorized = true
return
}
}
}

req := []service.SetupPortalServiceRequest{}
err = c.ShouldBindJSON(&req)
if err != nil {
ctx.Err = e.ErrInvalidParam.AddErr(err)
return
}

ctx.Err = service.SetupPortalService(c, projectKey, envName, serviceName, req)
return
}
Original file line number Diff line number Diff line change
Expand Up @@ -2024,7 +2024,6 @@ func deleteK8sProductServices(productInfo *commonmodels.Product, serviceNames []
}

selector := labels.Set{setting.ProductLabel: productInfo.ProductName, setting.ServiceLabel: name}.AsSelector()

err = EnsureDeleteZadigService(ctx, productInfo, selector, kclient, istioClient)
if err != nil {
// Only record and do not block subsequent traversals.
Expand Down
Loading
Loading