diff --git a/.github/labeler.yml b/.github/labeler.yml index fa949ecb21df89c3073573b97bb04f7abd9724cb..c31f7da476f7b97509ba14585f06ba6e6ff06885 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -2,6 +2,18 @@ service/aslan: - pkg/microservice/aslan/**/* +service/picket: +- pkg/microservice/picket/**/* + +service/user: +- pkg/microservice/user/**/* + +service/policy: +- pkg/microservice/policy/**/* + +service/config: +- pkg/microservice/systemconfig/**/* + service/cron: - pkg/microservice/cron/**/* diff --git a/Makefile b/Makefile index d46ca9fbc2fdebec8c2b184020381599c9689dda..08428072aa08ce8302100798d3b18c883854d7d8 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ IMAGE_REPOSITORY = ccr.ccs.tencentyun.com/koderover-rc VERSION ?= $(shell date +'%Y%m%d%H%M%S') -TARGETS = aslan cron hub-agent hub-server jenkins-plugin podexec predator-plugin resource-server ua warpdrive policy picket +TARGETS = aslan cron hub-agent hub-server jenkins-plugin podexec predator-plugin resource-server ua warpdrive policy user picket config init REAPER_OS= focal xenial bionic ALL_IMAGES=$(TARGETS:=.image) diff --git a/README-zh-CN.md b/README-zh-CN.md index beba21f0e28716985f22060b1f974093a42ba3e3..3bd629bace746e12316ebde00f4e36948333ad85 100644 --- a/README-zh-CN.md +++ b/README-zh-CN.md @@ -42,6 +42,8 @@ Zadig 是一款面向开发者设计的云原生持续交付(Continuous Delivery ![业务架构图](./Zadig-Business-Architecture-zh.jpg) +想了解更多系统架构信息,参考 [系统架构简介](System-Architecture-Overview-zh-CN.md). + 产品特性介绍:
diff --git a/README.md b/README.md index 374fa483aeee1f10d2a381e2c51bf975c623ae67..7ba402d46c964a0559f558ab2c6ba89ce529a86a 100644 --- a/README.md +++ b/README.md @@ -41,10 +41,12 @@ Zadig is non-invasive, it does not exclude any of your existing development proc > Our vision is: Developer + Zadig = Business success -The architecture is as follows: +The business architecture is as follows: ![Business Architecture](./Zadig-Business-Architecture.jpg) +For more details about system architecture, see [Zadig System Architecture Overview](System-Architecture-Overview.md). + The Highlighted Features:
diff --git a/System-Architecture-Overview-zh-CN.md b/System-Architecture-Overview-zh-CN.md new file mode 100644 index 0000000000000000000000000000000000000000..4f10c078aea0e1280cc4481a1592aca3ce853eb1 --- /dev/null +++ b/System-Architecture-Overview-zh-CN.md @@ -0,0 +1,39 @@ +# Zadig 系统架构简介 + +## 系统架构图 + +![Architecture_diagram](./Zadig-System-Architecture.svg) + +## 核心组件介绍 + +用户入口: +- zadig-portal:Zadig 前端组件 +- kodespace:Zadig 开发者命令行工具 +- Zadig Toolkit:vscode 开发者插件 + +API 网关: +- Gloo Edge:Zadig 的 API 网关组件 +- OPA:认证和授权组件 +- User:用户管理,Token 生成 +- Dex:Zadig 的身份认证服务,用于连接其他第三方认证系统,比如 AD / LDAP / OAuth2 / GitHub / .. + +Zadig 核心业务: +- Picket:数据聚合服务 +- Aslan:项目 / 环境 / 服务 / 工作流 / 构建配置 / 系统配置等系统功能 +- Policy:OPA 数据源,策略注册中心 +- Config:系统配置 +- Workflow Runner: + - warpdrive:工作流引擎,负责 reaper、predator 实例的创建销毁等管理操作 + - reaper:负责执行单个工作流作业中的构建、测试等任务 + - predator:负责执行单个工作流作业中的镜像分发任务 + - plugins:工作流插件 + - Jenkins-plugin:用于触发 Jenkins job,显示状态和结果等 +- Cron:定时任务,包括环境的回收,K8s 资源的清理等 +- NSQ:消息队列(第三方组件) + +数据平面: +- MongoDB:业务数据数据库 +- MySQL:存储 dex 配置、用户信息的数据库 + +K8s 集群: +- Zadig 业务运行在各种云厂商的标准 K8s 集群 \ No newline at end of file diff --git a/System-Architecture-Overview.md b/System-Architecture-Overview.md new file mode 100644 index 0000000000000000000000000000000000000000..61e0597798d97af0fe6f6a06d78f990004b1e9af --- /dev/null +++ b/System-Architecture-Overview.md @@ -0,0 +1,39 @@ +# Zadig System Architecture Overview + +## System Architecture + +![Architecture_diagram](./Zadig-System-Architecture.svg) + +## Main Components + +User Interface: +- zadig-portal:Zadig web component +- kodespace:Zadig command line tools +- Zadig Toolkit:vscode plugin + +API Gateway: +- Gloo Edge:Zadig API gateway +- OPA:Authentication and authorization +- User:User management, token generation +- Dex:Identity service for Zadig, acts as a portal to other identity providers like AD / LDAP / OAuth2 / GitHub / .. + +Zadig Core: +- Picket:backend for frontend service. +- Aslan:main service for all business logic. Project, environment, service, workflow, build, system management are all in this service. +- Policy:data source of OPA and policy registration center. +- Config:system configuration center. +- Workflow Runner: + - warpdrive:workflow engine, manages reaper and predator + - reaper:workflow runner. Used for building, testing tasks. + - predator:workflow runner. Used for distribute tasks. + - plugins:workflow plugins + - Jenkins-plugin:workflow runner. Used as connector to trigger Jenkins job and retrieve job information. +- Cron:cronjob runner +- NSQ:message queue + +Data Plane: +- MongoDB:database for business data. +- MySQL:dex configuration,database for user. + +Kubernetes Cluster: +- Zadig business runs on standard K8s clusters from cloud vendors diff --git a/Zadig-System-Architecture.svg b/Zadig-System-Architecture.svg new file mode 100644 index 0000000000000000000000000000000000000000..c53a8eacdabc009d1c555c0a6de3c201d713d740 --- /dev/null +++ b/Zadig-System-Architecture.svg @@ -0,0 +1 @@ +
User
Interface
User...
API
Gateway
API...
OAuth 2.0
OAuth 2.0
LDAP/AD
LDAP/AD
GitHub
GitHub
……
……
OpenID Provider
OpenID Provider
Zadig Core
Zadig...
Data Plane
Data Plane
MongoDB
MongoDB
MySQL
MySQL
Engineer (development, testing, SRE etc.)
Engineer (development, testing, SRE etc.)
Workflow Runner
Workflow Runner
warpdrive
warpdrive
Dind Replicas
Dind Replicas
dind
dind
dind
dind
NSQ
NSQ
Cron
Cron
workflow controller
workflow controller
project
project
service
service
environment
environment
cronjob controller
cronjob controller
Zadig Portal
Zadig Portal
Zadig Toolkit
Zadig Toolkit
Kodespace
Kodespace
reaper
reaper
predator
predat...
plugins
plugins
warpdrive
warpdr...
warpdrive
warpdr...
Picket
Picket
Aslan
Aslan
Dex
Dex
User
User
Gloo Edge
Gloo Edge
Opa
Opa
Kubernetes
Cluster
Kubern...
Ali ACK 
Ali ACK 
AWS EKS
AWS EKS
Tencent TKE
Tencent TKE
Huawei CCE
Huawei CCE
......
......
Config
Config
Policy
Policy
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/cmd/initconfig/main.go b/cmd/initconfig/main.go new file mode 100644 index 0000000000000000000000000000000000000000..6d10e2d038b6eafc5d298e0a966edc2df7944f25 --- /dev/null +++ b/cmd/initconfig/main.go @@ -0,0 +1,25 @@ +/* +Copyright 2021 The KodeRover 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 main + +import ( + "github.com/koderover/zadig/pkg/cli/initconfig/cmd" +) + +func main() { + cmd.Execute() +} diff --git a/pkg/shared/poetry/org.go b/cmd/systemconfig/main.go similarity index 48% rename from pkg/shared/poetry/org.go rename to cmd/systemconfig/main.go index 463a7c07e803ba70b16a26daa97636fd0301c4f8..3df10041fcaf3373bf0151575fc74641422e7e57 100644 --- a/pkg/shared/poetry/org.go +++ b/cmd/systemconfig/main.go @@ -14,33 +14,37 @@ See the License for the specific language governing permissions and limitations under the License. */ -package poetry +package main import ( - "fmt" + "context" + "flag" + "log" + "os/signal" + "syscall" - "github.com/koderover/zadig/pkg/tool/httpclient" -) + "github.com/spf13/pflag" + "github.com/spf13/viper" -const ( - DefaultOrganization = iota + 1 + "github.com/koderover/zadig/pkg/microservice/systemconfig/config" + "github.com/koderover/zadig/pkg/microservice/systemconfig/server" ) -type Organization struct { - ID int `json:"id"` - Name string `json:"name"` - Token string `json:"orgToken"` - Website string `json:"website"` -} +func main() { -func (c *Client) GetOrganization(orgID int) (*Organization, error) { - url := fmt.Sprintf("/directory/organization/%d", orgID) + flag.String(config.FeatureFlag, "", "turn a set of features on or off") - org := &Organization{} - _, err := c.Get(url, httpclient.SetResult(org)) - if err != nil { - return nil, err - } + pflag.CommandLine.AddGoFlagSet(flag.CommandLine) + pflag.Parse() + viper.BindPFlags(pflag.CommandLine) - return org, nil + ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT) + go func() { + <-ctx.Done() + stop() + }() + + if err := server.Serve(ctx); err != nil { + log.Fatal(err) + } } diff --git a/cmd/user/main.go b/cmd/user/main.go new file mode 100644 index 0000000000000000000000000000000000000000..2f8f7c699280caa206d914658a629e04c980188d --- /dev/null +++ b/cmd/user/main.go @@ -0,0 +1,38 @@ +/* +Copyright 2021 The KodeRover 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 main + +import ( + "context" + "log" + "os/signal" + "syscall" + + "github.com/koderover/zadig/pkg/microservice/user/server" +) + +func main() { + ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT) + go func() { + <-ctx.Done() + stop() + }() + + if err := server.Serve(ctx); err != nil { + log.Fatal(err) + } +} diff --git a/docker/service/config.Dockerfile b/docker/service/config.Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..83a3f2ffd5df02395eec82343c8990960b03e745 --- /dev/null +++ b/docker/service/config.Dockerfile @@ -0,0 +1,11 @@ +#golang.Dockerfile + +RUN go build -v -o /config ./cmd/systemconfig/main.go + +#alpine.Dockerfile + +WORKDIR /app + +COPY --from=build /config . + +ENTRYPOINT ["/app/config"] diff --git a/docker/service/init.Dockerfile b/docker/service/init.Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..d8acda07a0d46d51a6feab941c45d35e3a24796f --- /dev/null +++ b/docker/service/init.Dockerfile @@ -0,0 +1,10 @@ +#golang.Dockerfile + +RUN go build -o /init ./cmd/initconfig/main.go + +#alpine.Dockerfile + +WORKDIR /app +COPY --from=build /init /app/init + +ENTRYPOINT ["/app/init"] diff --git a/docker/service/user.Dockerfile b/docker/service/user.Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..2ff142037f287921dd0d52cd8a62961bf30ec166 --- /dev/null +++ b/docker/service/user.Dockerfile @@ -0,0 +1,11 @@ +#golang.Dockerfile + +RUN go build -v -o /user ./cmd/user/main.go + +#alpine.Dockerfile + +WORKDIR /app + +COPY --from=build /user . + +ENTRYPOINT ["/app/user"] diff --git a/go.mod b/go.mod index 908353cf5cafd80c1853d101b03015f33e13b643..3c65dad558071ed39fe1527fc09ad22cf233369c 100644 --- a/go.mod +++ b/go.mod @@ -15,17 +15,21 @@ require ( github.com/bugsnag/panicwrap v1.3.1 // indirect github.com/cenkalti/backoff/v4 v4.1.1 github.com/coocood/freecache v1.1.0 + github.com/coreos/go-oidc/v3 v3.0.0 + github.com/dexidp/dex v0.0.0-20210802203454-3fac2ab6bc3b github.com/docker/distribution v2.7.1+incompatible github.com/docker/docker v20.10.7+incompatible github.com/docker/go-connections v0.4.0 github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect github.com/dsnet/compress v0.0.1 // indirect github.com/garyburd/redigo v1.6.2 // indirect - github.com/gin-contrib/sessions v0.0.3 github.com/gin-contrib/sse v0.1.0 github.com/gin-gonic/gin v1.7.2 + github.com/go-ldap/ldap/v3 v3.3.0 github.com/go-resty/resty/v2 v2.6.0 + github.com/go-sql-driver/mysql v1.6.0 github.com/gofrs/uuid v4.0.0+incompatible // indirect + github.com/golang-jwt/jwt v3.2.2+incompatible github.com/google/go-github/v35 v35.3.0 github.com/google/uuid v1.2.0 github.com/gorilla/mux v1.8.0 @@ -49,6 +53,7 @@ require ( github.com/satori/go.uuid v1.2.0 github.com/sirupsen/logrus v1.8.1 github.com/spf13/cobra v1.2.1 + github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.8.1 github.com/stevvooe/resumable v0.0.0-20180830230917-22b14a53ba50 // indirect github.com/stretchr/testify v1.7.0 @@ -61,13 +66,17 @@ require ( github.com/yvasiyarov/newrelic_platform_go v0.0.0-20160601141957-9c099fbc30e9 // indirect go.mongodb.org/mongo-driver v1.5.0 go.uber.org/zap v1.19.0 + golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 - golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602 + golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c - golang.org/x/tools v0.1.5 // indirect + gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect + gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df gopkg.in/mholt/archiver.v3 v3.1.1 gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b + gorm.io/driver/mysql v1.1.2 + gorm.io/gorm v1.21.16 helm.sh/helm/v3 v3.7.1 k8s.io/api v0.22.1 k8s.io/apimachinery v0.22.1 diff --git a/go.sum b/go.sum index 8a052bb37ba9e71e3f42c9a79d132bd74a5eddac..7fa362e8a2d3fd24b15d48bb068bb44ad0815c0c 100644 --- a/go.sum +++ b/go.sum @@ -25,6 +25,10 @@ cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmW cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.88.0 h1:MZ2cf9Elnv1wqccq8ooKO2MqHQLc+ChCp/+QWObCpxg= +cloud.google.com/go v0.88.0/go.mod h1:dnKwfYbP9hQhefiUvpbcAyoGSHUrOxR20JVElLiUvEY= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -50,11 +54,13 @@ contrib.go.opencensus.io/exporter/stackdriver v0.12.1/go.mod h1:iwB6wGarfphGGe/e contrib.go.opencensus.io/integrations/ocsql v0.1.4/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE= contrib.go.opencensus.io/resource v0.1.1/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcigGlFvXwEGEnkRLA= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +entgo.io/ent v0.8.0/go.mod h1:KNjsukat/NJi6zJh1utwRadsbGOZsBbAZNDxkW7tMCc= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= git.apache.org/thrift.git v0.12.0/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= github.com/27149chen/afero v1.6.2 h1:WRPUOreB90qGRQs8fxXcvi0srBPHy2octiJme7C7XCA= github.com/27149chen/afero v1.6.2/go.mod h1:68wFWsZwQPvguVWn5di+KCOLI0KQtSRve2mPFVg6VWY= github.com/AkihiroSuda/containerd-fuse-overlayfs v1.0.0/go.mod h1:0mMDvQFeLbbn1Wy8P2j3hwFhqBq+FKn8OZPno8WLmp8= +github.com/AppsFlyer/go-sundheit v0.4.0/go.mod h1:iZ8zWMS7idcvmqewf5mEymWWgoOiG/0WD4+aeh+heX4= github.com/Azure/azure-amqp-common-go/v2 v2.1.0/go.mod h1:R8rea+gJRuJR6QxTir/XuEd+YuKoUiazDC/N96FiDEU= github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= @@ -103,6 +109,8 @@ github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6L github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c h1:/IBSNwUN8+eKzUzbJPqhK839ygXJ82sde8x3ogr6R28= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= @@ -223,6 +231,7 @@ github.com/aws/aws-sdk-go v1.34.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU github.com/aws/aws-sdk-go v1.34.28 h1:sscPpn/Ns3i0F4HPEWAVcwdIRaZZCuL7llJ2/60yPIk= github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= +github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -246,16 +255,13 @@ github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2y github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bndr/gojenkins v1.1.0 h1:TWyJI6ST1qDAfH33DQb3G4mD8KkrBfyfSUoZBHQAvPI= github.com/bndr/gojenkins v1.1.0/go.mod h1:QeskxN9F/Csz0XV/01IC8y37CapKKWvOHa0UHLLX1fM= -github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P97fT2CiHkbFQwkK3mjsFAP6zCYV2aXtjw= github.com/bombsimon/wsl/v2 v2.0.0/go.mod h1:mf25kr/SqFEPhhcxW1+7pxzGlW+hIl/hYTKY95VwV8U= github.com/bombsimon/wsl/v2 v2.2.0/go.mod h1:Azh8c3XGEJl9LyX0/sFC+CKMc7Ssgua0g+6abzXN4Pg= github.com/bombsimon/wsl/v3 v3.0.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2Pm1FNZIc= github.com/bombsimon/wsl/v3 v3.1.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2Pm1FNZIc= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= -github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= github.com/bradleyfalzon/ghinstallation v1.1.1 h1:pmBXkxgM1WeF8QYvDLT5kuQiHMcmf+X015GI0KM/E3I= github.com/bradleyfalzon/ghinstallation v1.1.1/go.mod h1:vyCmHTciHx/uuyN82Zc3rXN3X2KTK8nUTCrTMwAhcug= -github.com/bradleypeabody/gorilla-sessions-memcache v0.0.0-20181103040241-659414f458e1/go.mod h1:dkChI7Tbtx7H1Tj7TqGSZMOeGpMP5gLHtjroHd4agiI= github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70= github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= @@ -294,6 +300,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= @@ -403,7 +410,10 @@ github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= +github.com/coreos/go-oidc v2.1.0+incompatible h1:sdJrfw8akMnCuUlaZU3tE/uYXFgfqom8DBE9so9EBsM= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-oidc/v3 v3.0.0 h1:/mAA0XMgYJw2Uqm7WKGCsKnjitE/+A0FFbOmiRJm7LQ= +github.com/coreos/go-oidc/v3 v3.0.0/go.mod h1:rEJ/idjfUyfkBit1eI1fvyr+64/g9dcKpAm8MJMesvo= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= @@ -437,6 +447,9 @@ github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1 github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY= +github.com/dexidp/dex v0.0.0-20210802203454-3fac2ab6bc3b h1:ovHbNjGAQsGEs67tYU6C6ex2D2shDkeZ7pPprx58f2k= +github.com/dexidp/dex v0.0.0-20210802203454-3fac2ab6bc3b/go.mod h1:g64CEwk9b4oLTREOu8mFkjTkDUvyxzWGqhnPwQlfrq8= +github.com/dexidp/dex/api/v2 v2.0.0/go.mod h1:k5arBJT1QYvpsEY3sEd0NXJp3hKWKuUUfzJ3BlcqPdM= github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= @@ -491,6 +504,7 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= @@ -525,20 +539,20 @@ github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2H github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/gzip v0.0.1 h1:ezvKOL6jH+jlzdHNE4h9h8q8uMpDQjyl0NN0Jd7jozc= github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w= -github.com/gin-contrib/sessions v0.0.3 h1:PoBXki+44XdJdlgDqDrY5nDVe3Wk7wDV/UCOuLP6fBI= -github.com/gin-contrib/sessions v0.0.3/go.mod h1:8C/J6cad3Il1mWYYgtw0w+hqasmpvy25mPkXdOgeB9I= github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= -github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do= github.com/gin-gonic/gin v1.7.2 h1:Tg03T9yM2xa8j6I3Z3oqLaQRSmKvxPd6g/2HJ6zICFA= github.com/gin-gonic/gin v1.7.2/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/go-asn1-ber/asn1-ber v1.5.1 h1:pDbRAunXzIUXfx4CB2QJFv5IuPiuoW+sWvr/Us009o8= +github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-bindata/go-bindata v1.0.1-0.20190711162640-ee3c2418e368/go.mod h1:7xCgX1lzlrXPHkfvn3EhumqHkmSlzt8at9q7v0ax19c= github.com/go-critic/go-critic v0.4.1/go.mod h1:7/14rZGnZbY6E38VEGk2kVhoq6itzc1E68facVDK23g= github.com/go-critic/go-critic v0.4.3/go.mod h1:j4O3D4RoIwRqlZw5jJpx0BNfXWWbpcJoKu5cYSe4YmQ= github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= @@ -550,6 +564,8 @@ github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3I github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-ldap/ldap/v3 v3.3.0 h1:lwx+SJpgOHd8tG6SumBQZXCmNX51zM8B1cfxJ5gv4tQ= +github.com/go-ldap/ldap/v3 v3.3.0/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= @@ -569,6 +585,7 @@ github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2 github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= +github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= @@ -617,10 +634,8 @@ github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2K github.com/go-openapi/validate v0.19.8/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= @@ -629,8 +644,10 @@ github.com/go-resty/resty/v2 v2.6.0 h1:joIR5PNLM2EFqqESUjCMGXrWmXNHEU9CEiK813oKY github.com/go-resty/resty/v2 v2.6.0/go.mod h1:PwvJS6hvaPkjtjNg9ph+VrSD92bi5Zq73w/BIH7cC3Q= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.5.1-0.20200311113236-681ffa848bae/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= @@ -704,6 +721,8 @@ github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -767,9 +786,8 @@ github.com/golangci/revgrep v0.0.0-20180526074752-d9c87f5ffaf0/go.mod h1:qOQCunE github.com/golangci/revgrep v0.0.0-20180812185044-276a5c0a1039/go.mod h1:qOQCunEYvmd/TLamH+7LlVccLvUH5kZNhbCgTHoBbp4= github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= +github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k= github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= -github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0= -github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -811,6 +829,7 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -822,6 +841,8 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210715191844-86eeefc3e471/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/rpmpack v0.0.0-20191226140753-aa36bfddb3a0/go.mod h1:RaTPr0KUf2K7fnZYLNDrr8rxAamWs3iNywJLtQ2AzBg= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= @@ -835,8 +856,10 @@ github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/wire v0.3.0/go.mod h1:i1DMg/Lu8Sz5yYl25iOdmc5CT5qusaa+zmRWs16741s= github.com/google/wire v0.4.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +github.com/googleapis/gax-go v2.0.2+incompatible h1:silFMLAnr330+NRuag/VjIGF7TLp/LBrV2CJKFLWEww= github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= @@ -851,7 +874,6 @@ github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORR github.com/goreleaser/goreleaser v0.136.0/go.mod h1:wiKrPUeSNh6Wu8nUHxZydSOVQ/OZvOaO7DTtFqie904= github.com/goreleaser/nfpm v1.2.1/go.mod h1:TtWrABZozuLOttX2uDlYyECfQX7x5XYkVxhjYcR6G9w= github.com/goreleaser/nfpm v1.3.0/go.mod h1:w0p7Kc9TAUgWMyrub63ex3M2Mgw88M4GZXoTq5UCb40= -github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= @@ -859,11 +881,6 @@ github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= -github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= -github.com/gorilla/sessions v1.1.1/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= -github.com/gorilla/sessions v1.1.3 h1:uXoZdcdA5XdXF3QzuSlheVRUvjl+1rKY7zBXL68L9RU= -github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= @@ -957,7 +974,10 @@ github.com/jasonlvhit/gocron v0.0.0-20171226191223-3c914c8681c3 h1:s2ARkZWJfkyjr github.com/jasonlvhit/gocron v0.0.0-20171226191223-3c914c8681c3/go.mod h1:rwi/esz/h+4oWLhbWWK7f6dtmgLzxeZhnwGr7MCsTNk= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jingyugao/rowserrcheck v0.0.0-20191204022205-72ab7603b68a/go.mod h1:xRskid8CManxVta/ALEhJha/pweKBaVG6fWgc0yH25s= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.2 h1:eVKgfIdy9b6zbWBMgFpfDPoAMifwSZagU9HmEU6zgiI= github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jirfag/go-printf-func-name v0.0.0-20191110105641-45db9963cdd3/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= @@ -975,6 +995,7 @@ github.com/jmoiron/sqlx v1.3.1/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXL github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.2.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= @@ -1002,7 +1023,6 @@ github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaR github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/karrick/godirwalk v1.15.8 h1:7+rWAZPn9zuRxaIqqT8Ohs2Q2Ac0msBqwRdxNCr2VVs= github.com/karrick/godirwalk v1.15.8/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= -github.com/kidstuff/mongostore v0.0.0-20181113001930-e650cd85ee4b/go.mod h1:g2nVr8KZVXJSS97Jo8pJ0jgq29P6H7dG0oplUA86MQw= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -1034,18 +1054,20 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= -github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.10.0 h1:Zx5DJFEYQXio93kgXnQ09fXNiUKsqv4OUEu2UtGcB1E= github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= +github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= @@ -1073,6 +1095,7 @@ github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= github.com/matoous/godox v0.0.0-20190911065817-5d6d842e92eb/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= +github.com/mattermost/xml-roundtrip-validator v0.1.0/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -1087,7 +1110,6 @@ github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= @@ -1100,8 +1122,9 @@ github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vq github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/mattn/go-shellwords v1.0.11/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.8 h1:gDp86IdQsN/xWjIEmr9MF6o9mpksUgh0fu+9ByFxzIU= +github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/mattomatic/dijkstra v0.0.0-20130617153013-6f6d134eb237 h1:acuCHBjzG7MFTugvx3buC4m5rLDLaKC9J8C9jtlraRc= @@ -1110,7 +1133,6 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5 github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= -github.com/memcachier/mc v2.0.1+incompatible/go.mod h1:7bkvFE61leUBvXz+yxsOnGBQSZpBSPIMUQSmmSHvuXc= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= @@ -1194,6 +1216,7 @@ github.com/nwaples/rardecode v1.0.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWk github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= @@ -1333,7 +1356,6 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI= github.com/quasilyte/go-ruleguard v0.1.2-0.20200318202121-b00d7a75d3d8/go.mod h1:CGFX09Ci3pq9QZdj86B+VGIdNj4VyCo2iPOGS9esB/k= -github.com/quasoft/memstore v0.0.0-20180925164028-84a050167438/go.mod h1:wTPjTepVu7uJBYgZ0SdWHQlIas582j6cn2jgk4DDdlg= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= github.com/rfyiamcool/cronlib v1.0.0 h1:PNTF7pgtbL7TedrqnC6syhHwj4d1bCKxH3XmPqqgxvg= @@ -1349,6 +1371,7 @@ github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rubenv/sql-migrate v0.0.0-20210614095031-55d5740dbbcc h1:BD7uZqkN8CpjJtN/tScAKiccBikU4dlqe/gNrkRaPY4= github.com/rubenv/sql-migrate v0.0.0-20210614095031-55d5740dbbcc/go.mod h1:HFLT6i9iR4QBOF5rdCyjddC9t59ArqWJV2xx+jwcCMo= github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= +github.com/russellhaering/goxmldsig v1.1.0/go.mod h1:QK8GhXPB3+AfuCrfo0oRISa9NfzeCpWmxeGnqEpDF9o= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -1660,6 +1683,7 @@ golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -1754,6 +1778,7 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200505041828-1ed23360d12c/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= @@ -1774,6 +1799,7 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 h1:ADo5wSpq2gqaCGQWzk7S5vd//0iyyLeAratkEoG5dLE= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180724155351-3d292e4d0cdc/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1792,8 +1818,10 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602 h1:0Ja1LBD+yisY6RWM/BH7TJVXWsSjs2VwBSmvSX4HdBc= golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 h1:3B43BWw0xEBsLZ/NO1VALz6fppU3481pik+2Ksv45z8= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1845,7 +1873,6 @@ golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1914,8 +1941,11 @@ golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 h1:c8PlLMqBbOHoqtjteWm5/kbe6rNY2pbRfbIMVnepueo= golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -2034,6 +2064,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2078,6 +2110,11 @@ google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjR google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.52.0 h1:m5FLEd6dp5CU1F0tMWyqDi2XjchviIz8ntzOSz7w8As= +google.golang.org/api v0.52.0/go.mod h1:Him/adpjt0sxtkWViy0b6xyKW/SD71CwdJ7HqJo7SrU= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -2141,8 +2178,14 @@ google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210721163202-f1cecdd8b78a/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f h1:YORWxaStkWBnWgELOHTmDrqNlFXuVGEbhwbB5iK94bQ= +google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= @@ -2171,8 +2214,10 @@ google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0 h1:Klz8I9kdtkIN6EpHHUOMLCYhTn/2WAe5a0s1hcBkdTI= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -2184,10 +2229,13 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -2202,7 +2250,8 @@ gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= -gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= +gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= +gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= gopkg.in/gorp.v1 v1.7.2 h1:j3DWlAyGVv8whO7AcIWznQ2Yj7yJkn34B8s63GViAAw= gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= @@ -2219,6 +2268,8 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= @@ -2237,6 +2288,11 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/mysql v1.1.2 h1:OofcyE2lga734MxwcCW9uB4mWNXMr50uaGRVwQL2B0M= +gorm.io/driver/mysql v1.1.2/go.mod h1:4P/X9vSc3WTrhTLZ259cpFd6xKNYiSSdSZngkSBGIMM= +gorm.io/gorm v1.21.12/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= +gorm.io/gorm v1.21.16 h1:YBIQLtP5PLfZQz59qfrq7xbrK7KWQ+JsXXCH/THlMqs= +gorm.io/gorm v1.21.16/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= diff --git a/pkg/cli/initconfig/cmd/admin.yaml b/pkg/cli/initconfig/cmd/admin.yaml new file mode 100644 index 0000000000000000000000000000000000000000..b64adb5c09fe014b6ae98ca46f509234bc4d8b78 --- /dev/null +++ b/pkg/cli/initconfig/cmd/admin.yaml @@ -0,0 +1,6 @@ +name: admin +rules: + - verbs: + - "*" + resources: + - "*" \ No newline at end of file diff --git a/pkg/cli/initconfig/cmd/contributor.yaml b/pkg/cli/initconfig/cmd/contributor.yaml new file mode 100644 index 0000000000000000000000000000000000000000..34a8ebd2e6a55b72a9b1bb7ec55c35a49be12ddb --- /dev/null +++ b/pkg/cli/initconfig/cmd/contributor.yaml @@ -0,0 +1,27 @@ +name: contributor +rules: + - verbs: + - get_workflow + - run_workflow + resources: + - Workflow + kind: resource + - verbs: + - get_environment + - config_environment + - manage_environment + - delete_environment + resources: + - Environment + kind: resource + - verbs: + - get_build + - get_service + resources: + - Service + kind: resource + - verbs: + - get_test + resources: + - Test + kind: resource diff --git a/pkg/cli/initconfig/cmd/init.go b/pkg/cli/initconfig/cmd/init.go new file mode 100644 index 0000000000000000000000000000000000000000..1d0d679308ea50359e34412e5adc54e481c2adc1 --- /dev/null +++ b/pkg/cli/initconfig/cmd/init.go @@ -0,0 +1,186 @@ +/* +Copyright 2021 The KodeRover 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 cmd + +import ( + _ "embed" + "encoding/base64" + "encoding/json" + "fmt" + "time" + + "github.com/spf13/cobra" + "golang.org/x/sync/errgroup" + + "sigs.k8s.io/yaml" + + "github.com/koderover/zadig/pkg/config" + "github.com/koderover/zadig/pkg/setting" + "github.com/koderover/zadig/pkg/shared/client/policy" + "github.com/koderover/zadig/pkg/shared/client/user" + "github.com/koderover/zadig/pkg/tool/httpclient" + "github.com/koderover/zadig/pkg/tool/log" +) + +func init() { + rootCmd.AddCommand(initCmd) + log.Init(&log.Config{ + Level: config.LogLevel(), + }) +} + +//go:embed contributor.yaml +var contributor []byte + +//go:embed read-only.yaml +var readOnly []byte + +//go:embed admin.yaml +var admin []byte + +//go:embed project-admin.yaml +var projectAdmin []byte + +var initCmd = &cobra.Command{ + Use: "init", + Short: "init system config", + Long: `init system config.`, + Run: func(cmd *cobra.Command, args []string) { + if err := run(); err != nil { + log.Fatal(err) + } + }, +} + +func run() error { + return initSystemConfig() +} + +func initSystemConfig() error { + email := config.AdminEmail() + password := config.AdminPassword() + domain := config.SystemAddress() + + uid, err := presetSystemAdmin(email, password, domain) + if err != nil { + log.Errorf("presetSystemAdmin err:%s", err) + return err + } + if err := presetRole(); err != nil { + log.Errorf("presetRole err:%s", err) + return err + } + + if err := presetRoleBinding(uid); err != nil { + log.Errorf("presetRoleBinding :%s", err) + return err + } + return nil +} + +func presetSystemAdmin(email string, password, domain string) (string, error) { + r, err := user.New().SearchUser(&user.SearchUserArgs{Account: setting.PresetAccount}) + if err != nil { + log.Errorf("SearchUser err:%s", err) + return "", err + } + if len(r.Users) > 0 { + log.Infof("User admin exists, skip it.") + return r.Users[0].UID, nil + } + user, err := user.New().CreateUser(&user.CreateUserArgs{ + Name: setting.PresetAccount, + Password: password, + Account: setting.PresetAccount, + Email: email, + }) + if err != nil { + log.Errorf("created admin err:%s", err) + return "", err + } + // report register + err = reportRegister(domain, email) + if err != nil { + log.Errorf("reportRegister err: %s", err) + } + return user.Uid, nil +} + +type Operation struct { + Data string `json:"data"` +} +type Register struct { + Domain string `json:"domain"` + Username string `json:"username"` + Email string `json:"email"` + CreatedAt int64 `json:"created_at"` +} + +func reportRegister(domain, email string) error { + register := Register{ + Domain: domain, + Username: "admin", + Email: email, + CreatedAt: time.Now().Unix(), + } + registerByte, _ := json.Marshal(register) + encrypt, err := RSAEncrypt([]byte(registerByte)) + if err != nil { + log.Errorf("RSAEncrypt err: %s", err) + return err + } + encodeString := base64.StdEncoding.EncodeToString(encrypt) + reqBody := Operation{Data: encodeString} + _, err = httpclient.Post("https://api.koderover.com/api/operation/admin/user", httpclient.SetBody(reqBody)) + return err +} + +func presetRoleBinding(uid string) error { + return policy.NewDefault().CreateOrUpdateSystemRoleBinding(&policy.RoleBinding{ + Name: fmt.Sprintf(setting.RoleBindingNameFmt, setting.RoleAdmin, setting.PresetAccount, ""), + UID: uid, + Role: setting.RoleAdmin, + }) + +} + +func presetRole() error { + g := new(errgroup.Group) + g.Go(func() error { + systemRole := &policy.Role{} + if err := yaml.Unmarshal(admin, systemRole); err != nil { + log.DPanic(err) + } + return policy.NewDefault().CreateSystemRole(systemRole.Name, systemRole) + }) + + rolesArray := [][]byte{readOnly, contributor, projectAdmin} + + for _, v := range rolesArray { + role := &policy.Role{} + if err := yaml.Unmarshal(v, role); err != nil { + log.DPanic(err) + } + g.Go(func() error { + return policy.NewDefault().CreatePublicRole(role.Name, role) + }) + } + if err := g.Wait(); err != nil { + return err + } + return nil +} diff --git a/pkg/cli/initconfig/cmd/project-admin.yaml b/pkg/cli/initconfig/cmd/project-admin.yaml new file mode 100644 index 0000000000000000000000000000000000000000..68938e3f1fb769e8f65981627d283cb0be783504 --- /dev/null +++ b/pkg/cli/initconfig/cmd/project-admin.yaml @@ -0,0 +1,6 @@ +name: project-admin +rules: + - verbs: + - "*" + resources: + - "*" \ No newline at end of file diff --git a/pkg/cli/initconfig/cmd/read-only.yaml b/pkg/cli/initconfig/cmd/read-only.yaml new file mode 100644 index 0000000000000000000000000000000000000000..d6bd5d64b7185a69b4c9cf0ec466a4eab59fb8d1 --- /dev/null +++ b/pkg/cli/initconfig/cmd/read-only.yaml @@ -0,0 +1,28 @@ +name: read-only +rules: + - verbs: + - get_workflow + resources: + - Workflow + kind: resource + - verbs: + - get_environment + resources: + - Environment + kind: resource + - verbs: + - get_build + - get_service + resources: + - Service + kind: resource + - verbs: + - get_test + resources: + - Test + kind: resource + - verbs: + - get_delivery + resources: + - Delivery + kind: resource \ No newline at end of file diff --git a/pkg/middleware/gin/product_name.go b/pkg/cli/initconfig/cmd/root.go similarity index 54% rename from pkg/middleware/gin/product_name.go rename to pkg/cli/initconfig/cmd/root.go index d66bff4044ac0b1036e68a630eff65419696719a..082fdcd40f4534ca29e7b5b242f6713efd5ef8d6 100644 --- a/pkg/middleware/gin/product_name.go +++ b/pkg/cli/initconfig/cmd/root.go @@ -14,34 +14,35 @@ See the License for the specific language governing permissions and limitations under the License. */ -package gin +package cmd import ( - "bytes" - "encoding/json" - "io/ioutil" - - "github.com/gin-gonic/gin" + "github.com/spf13/cobra" + "github.com/spf13/viper" "github.com/koderover/zadig/pkg/tool/log" ) -type productName struct { - ProductName string `json:"product_name"` +var rootCmd = &cobra.Command{ + Use: "config", + Short: "init config for zadig", + Long: `init system config for zadig`, +} + +// Execute executes the root command. +func Execute() error { + return rootCmd.Execute() } -func StoreProductName(c *gin.Context) { - pn := &productName{} - data, err := c.GetRawData() - if err != nil { - log.Errorf("c.GetRawData() err : %v", err) - return - } - if err = json.Unmarshal(data, pn); err != nil { - log.Errorf("json.Unmarshal err : %v", err) - return - } - c.Set("productName", pn.ProductName) - c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) - c.Next() +func init() { + cobra.OnInitialize(initConfig) +} + +func initConfig() { + viper.AutomaticEnv() + + log.Init(&log.Config{ + Level: "debug", + NoCaller: true, + }) } diff --git a/pkg/cli/initconfig/cmd/rsa.go b/pkg/cli/initconfig/cmd/rsa.go new file mode 100644 index 0000000000000000000000000000000000000000..0d299d768e043e4150f8852b574197f250a72aca --- /dev/null +++ b/pkg/cli/initconfig/cmd/rsa.go @@ -0,0 +1,62 @@ +package cmd + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "errors" + "os" +) + +var pub *rsa.PublicKey + +func RSAEncrypt(plainText []byte) ([]byte, error) { + if err := LoadPubKey(""); err != nil { + return nil, err + } + //对明文进行加密 + cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, pub, plainText) + if err != nil { + return nil, err + } + //返回密文 + return cipherText, nil +} + +// LoadPubKey ... +func LoadPubKey(filename string) (err error) { + var block *pem.Block + if filename == "" { + block, _ = pem.Decode([]byte(defaultPublicKey)) + } else { + b, err := os.ReadFile(filename) + if err != nil { + return err + } + block, _ = pem.Decode(b) + } + if block == nil { + return errors.New("public key error") + } + pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes) + if err != nil { + return + } + pub = pubInterface.(*rsa.PublicKey) + return +} + +var defaultPublicKey = ` +-----BEGIN RSA PUBLIC KEY----- +MIIBpTANBgkqhkiG9w0BAQEFAAOCAZIAMIIBjQKCAYQAz5IqagSbovHGXmUf7wTB +XrR+DZ0u3p5jsgJW08ISJl83t0rCCGMEtcsRXJU8bE2dIIfndNwvmBiqh13/WnJd ++jgyIm6i1ZfNmf/R8pEqVXpOAOuyoD3VLT9tfWvz9nPQbjVI+PsUHH7nVR0Jwxem +NsH/7MC2O15t+2DVC1533UlhjT/pKFDdTri0mgDrLZHp6gPF5d7/yQ7cPbzv6/0p +0UgIdStT7IhkDfsJDRmLAz09znv5tQQtHfJIMdAKxwHw9mExcL2gE40sOezrgj7m +srOnJd65N8anoMGxQqNv+ycAHB9aI1Yrtgue2KKzpI/Fneghd/ZavGVFWKDYoFP3 +531Ga/CiCwtKfM0vQezfLZKAo3qpb0Edy2BcDHhLwidmaFwh8ZlXuaHbNaF/FiVR +h7uu0/9B/gn81o2f+c8GSplWB5bALhQH8tJZnvmWZGI9OnrIlWmQZsuUBooTul9Q +ZJ/w3sE1Zoxa+Or1/eWijqtIfhukOJBNyGaj+esFg6uEeBgHAgMBAAE= +-----END RSA PUBLIC KEY----- +` diff --git a/pkg/cli/upgradeassistant/cmd/migrate/170.go b/pkg/cli/upgradeassistant/cmd/migrate/170.go new file mode 100644 index 0000000000000000000000000000000000000000..677d5c1b8ff1670cb5729b676bddcdb5ceb33789 --- /dev/null +++ b/pkg/cli/upgradeassistant/cmd/migrate/170.go @@ -0,0 +1,190 @@ +/* +Copyright 2021 The KodeRover 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 migrate + +import ( + internalmongodb "github.com/koderover/zadig/pkg/cli/upgradeassistant/internal/repository/mongodb" + "github.com/koderover/zadig/pkg/cli/upgradeassistant/internal/upgradepath" + "github.com/koderover/zadig/pkg/microservice/aslan/config" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" + gitservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/git" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/github" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/gitlab" + "github.com/koderover/zadig/pkg/setting" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" + "github.com/koderover/zadig/pkg/tool/log" +) + +func init() { + upgradepath.AddHandler(upgradepath.V160, upgradepath.V170, V160ToV170) + upgradepath.AddHandler(upgradepath.V170, upgradepath.V160, V170ToV160) +} + +// V160ToV170 refreshes the secret of all webhooks +func V160ToV170() error { + log.Info("Migrating data from 1.6.0 to 1.7.0") + + err := changeCodehostType() + if err != nil { + log.Errorf("Failed to change codehost type, err: %s", err) + return err + } + + err = refreshWebHookSecret(gitservice.GetHookSecret()) + if err != nil { + log.Errorf("Failed to refresh webhook secret, err: %s", err) + return err + } + + return nil +} + +func V170ToV160() error { + log.Info("Rollback data from 1.7.0 to 1.6.0") + err := rollbackCodehostType() + if err != nil { + log.Errorf("Failed to rollback codehost type, err: %s", err) + return err + } + token := getWebHookTokenFromOrganization() + if token == "" { + return nil + } + + log.Info("Start to rollback all webhook secrets") + err = refreshWebHookSecret(token) + if err != nil { + log.Errorf("Failed to refresh webhook secret, err: %s", err) + return err + } + + return nil +} + +type hookRefresher interface { + RefreshWebHookSecret(secret, owner, repo, hookID string) error +} + +func refreshWebHookSecret(secret string) error { + hooks, err := mongodb.NewWebHookColl().List() + if err != nil { + log.Errorf("Failed to list webhooks, err: %s", err) + return err + } + + codeHosts, err := systemconfig.New().ListCodeHosts() + if err != nil { + log.Errorf("Failed to list codehosts, err: %s", err) + return err + } + + for _, hook := range hooks { + var cl hookRefresher + ch := getCodeHostByAddressAndOwner(hook.Address, hook.Owner, codeHosts) + if ch == nil { + log.Warnf("Failed to get codehost for %s/%s", hook.Address, hook.Owner) + continue + } + + switch ch.Type { + case setting.SourceFromGithub: + cl = github.NewClient(ch.AccessToken, config.ProxyHTTPSAddr()) + case setting.SourceFromGitlab: + cl, err = gitlab.NewClient(ch.Address, ch.AccessToken) + if err != nil { + log.Warnf("Failed to create gitlab client, err: %s", err) + continue + } + default: + log.Warnf("Invalid type: %s", ch.Type) + continue + } + + if err = cl.RefreshWebHookSecret(secret, hook.Owner, hook.Repo, hook.HookID); err != nil { + log.Warnf("Failed to refresh webhook secret for hook %d in %s/%s, err: %s", hook.HookID, hook.Owner, hook.Repo, err) + continue + } + } + + return nil +} + +func getCodeHostByAddressAndOwner(address, owner string, all []*systemconfig.CodeHost) *systemconfig.CodeHost { + for _, one := range all { + if one.Address != address { + continue + } + // it is a limitation, we support only one gitlab account before + if one.Type == "gitlab" { + return one + } + if one.Namespace == owner { + return one + } + } + + return nil +} + +// change type "1,2,3,4" to "github,gitlab..." +func changeCodehostType() error { + // get all codehosts + codeHosts, err := internalmongodb.NewCodehostColl().ListCodeHosts() + if err != nil { + log.Errorf("fail to list codehosts, err: %s", err) + return err + } + var finalErr error + // change type to readable string + for _, v := range codeHosts { + if err := internalmongodb.NewCodehostColl().ChangeType(v.ID, v.Type); err != nil { + log.Warnf("fail to change id:%d type:%s , err: %s", v.ID, v.Type, err) + finalErr = err + } + } + return finalErr +} + +// rollback type "github,gitlab..." to "1,2..." +func rollbackCodehostType() error { + // get all codehosts + codeHosts, err := internalmongodb.NewCodehostColl().ListCodeHosts() + if err != nil { + log.Errorf("fail to list codehosts, err: %s", err) + return err + } + var finalErr error + // rollback change type to readable string + for _, v := range codeHosts { + if err := internalmongodb.NewCodehostColl().RollbackType(v.ID, v.Type); err != nil { + log.Warnf("fail to rollback id:%d type:%s , err: %s", v.ID, v.Type, err) + finalErr = err + continue + } + } + return finalErr +} + +func getWebHookTokenFromOrganization() string { + org, found, err := internalmongodb.NewOrganizationColl().Get(1) + if err != nil || !found { + log.Warnf("Failed to get organization, err: %s", err) + return "" + } + + return org.Token +} diff --git a/pkg/cli/upgradeassistant/internal/repository/models/codehost.go b/pkg/cli/upgradeassistant/internal/repository/models/codehost.go new file mode 100644 index 0000000000000000000000000000000000000000..57945fa66bdf2fe415ce6b18c8ef38420db2a3a5 --- /dev/null +++ b/pkg/cli/upgradeassistant/internal/repository/models/codehost.go @@ -0,0 +1,10 @@ +package models + +type CodeHost struct { + ID int `bson:"id" json:"id"` + Type string `bson:"type" json:"type"` +} + +func (CodeHost) TableName() string { + return "code_host" +} diff --git a/pkg/cli/upgradeassistant/internal/repository/models/organization.go b/pkg/cli/upgradeassistant/internal/repository/models/organization.go new file mode 100644 index 0000000000000000000000000000000000000000..33b2ccd93daf5a2ba4442b830157f575856617eb --- /dev/null +++ b/pkg/cli/upgradeassistant/internal/repository/models/organization.go @@ -0,0 +1,10 @@ +package models + +type Organization struct { + ID int `bson:"id" json:"id"` + Token string `bson:"token,omitempty" json:"token,omitempty"` +} + +func (Organization) TableName() string { + return "organization" +} diff --git a/pkg/cli/upgradeassistant/internal/repository/mongodb/codehost.go b/pkg/cli/upgradeassistant/internal/repository/mongodb/codehost.go new file mode 100644 index 0000000000000000000000000000000000000000..b308b11d06f67e4fef1fa7fc5a9f995c43a12b22 --- /dev/null +++ b/pkg/cli/upgradeassistant/internal/repository/mongodb/codehost.go @@ -0,0 +1,100 @@ +package mongodb + +import ( + "context" + + "github.com/koderover/zadig/pkg/cli/upgradeassistant/internal/repository/models" + "github.com/koderover/zadig/pkg/config" + "github.com/koderover/zadig/pkg/tool/log" + mongotool "github.com/koderover/zadig/pkg/tool/mongo" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" +) + +func (c *CodehostColl) ChangeType(ID int, sourceType string) error { + query := bson.M{"id": ID} + + preType := sourceType + if sourceType == "1" { + sourceType = "gitlab" + } else if sourceType == "2" { + sourceType = "github" + } else if sourceType == "3" { + sourceType = "gerrit" + } else if sourceType == "4" { + sourceType = "codehub" + } else { + return nil + } + + change := bson.M{"$set": bson.M{ + "type": sourceType, + }} + _, err := c.Collection.UpdateOne(context.TODO(), query, change) + if err != nil { + log.Errorf("repository update fail,err:%s", err) + return err + } + log.Infof("success to change id:%d type:%s to type:%s", ID, preType, sourceType) + return nil +} + +func (c *CodehostColl) RollbackType(ID int, sourceType string) error { + query := bson.M{"id": ID} + + if sourceType == "gitlab" { + sourceType = "1" + } else if sourceType == "github" { + sourceType = "2" + } else if sourceType == "gerrit" { + sourceType = "3" + } else if sourceType == "codehub" { + sourceType = "4" + } else { + return nil + } + + change := bson.M{"$set": bson.M{ + "type": sourceType, + }} + _, err := c.Collection.UpdateOne(context.TODO(), query, change) + if err != nil { + log.Errorf("repository update fail,err:%s", err) + return err + } + log.Infof("success to rollback id:%d to type:%s", ID, sourceType) + return nil +} + +func (c *CodehostColl) ListCodeHosts() ([]*models.CodeHost, error) { + codeHosts := make([]*models.CodeHost, 0) + + cursor, err := c.Collection.Find(context.TODO(), bson.M{}) + if err != nil { + return nil, err + } + err = cursor.All(context.TODO(), &codeHosts) + if err != nil { + return nil, err + } + return codeHosts, nil +} + +type CodehostColl struct { + *mongo.Collection + + coll string +} + +type ListArgs struct { + Owner string + Address string + Source string +} + +func NewCodehostColl() *CodehostColl { + name := models.CodeHost{}.TableName() + coll := &CodehostColl{Collection: mongotool.Database(config.MongoDatabase()).Collection(name), coll: name} + + return coll +} diff --git a/pkg/cli/upgradeassistant/internal/repository/mongodb/organization.go b/pkg/cli/upgradeassistant/internal/repository/mongodb/organization.go new file mode 100644 index 0000000000000000000000000000000000000000..41452b31c6a426325cc99044d87e0f52d6c225cd --- /dev/null +++ b/pkg/cli/upgradeassistant/internal/repository/mongodb/organization.go @@ -0,0 +1,40 @@ +package mongodb + +import ( + "context" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + + "github.com/koderover/zadig/pkg/cli/upgradeassistant/internal/repository/models" + "github.com/koderover/zadig/pkg/config" + mongotool "github.com/koderover/zadig/pkg/tool/mongo" +) + +type OrganizationColl struct { + *mongo.Collection + + coll string +} + +func NewOrganizationColl() *OrganizationColl { + name := models.Organization{}.TableName() + return &OrganizationColl{ + Collection: mongotool.Database(config.MongoDatabase()).Collection(name), + coll: name, + } +} + +func (c *OrganizationColl) Get(id int) (*models.Organization, bool, error) { + org := &models.Organization{} + query := bson.M{"id": id} + + err := c.FindOne(context.TODO(), query).Decode(org) + if err != nil { + if err == mongo.ErrNoDocuments { + return nil, false, nil + } + return nil, false, err + } + return org, true, nil +} diff --git a/pkg/cli/upgradeassistant/internal/upgradepath/versions.go b/pkg/cli/upgradeassistant/internal/upgradepath/versions.go index 562dfd39609a0b2426a27743dda439d1b5900185..0304cee031ac557794566231b42e17c59f34f36c 100644 --- a/pkg/cli/upgradeassistant/internal/upgradepath/versions.go +++ b/pkg/cli/upgradeassistant/internal/upgradepath/versions.go @@ -29,6 +29,7 @@ const ( V140 V150 V160 + V170 ) var versionMap versions = map[string]int{ @@ -37,6 +38,7 @@ var versionMap versions = map[string]int{ "1.4.0": V140, "1.5.0": V150, "1.6.0": V160, + "1.7.0": V170, } type versions map[string]int @@ -91,7 +93,7 @@ func init() { sort.Strings(versionList) - for i := 0; i < len(versionList)-2; i++ { + for i := 0; i < len(versionList)-1; i++ { lowVersion := versionList[i] highVersion := versionList[i+1] AddHandler(versionMap[lowVersion], versionMap[highVersion], defaultUpgradeHandler) diff --git a/pkg/config/config.go b/pkg/config/config.go index 69855b8350ba8aff08a4a779c052e30b10b0f749..92c0d23fc48ab6c8a981448632a491f4fdde1390 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -73,10 +73,6 @@ func RequestLogFile() string { return LogPath() + RequestLogName() } -func PoetryAPIRootKey() string { - return viper.GetString(setting.ENVPoetryAPIRootKey) -} - func GetServiceByCode(code int) *setting.ServiceInfo { return setting.Services[code] } @@ -85,6 +81,10 @@ func AslanServiceInfo() *setting.ServiceInfo { return GetServiceByCode(setting.Aslan) } +func SecretKey() string { + return viper.GetString(setting.ENVSecretKey) +} + func AslanServiceAddress() string { s := AslanServiceInfo() return GetServiceAddress(s.Name, s.Port) @@ -142,12 +142,12 @@ func CollieServiceAddress() string { return GetServiceAddress(s.Name, s.Port) } -func PoetryServiceInfo() *setting.ServiceInfo { - return GetServiceByCode(setting.Poetry) +func ConfigServiceInfo() *setting.ServiceInfo { + return GetServiceByCode(setting.Config) } -func PoetryServiceAddress() string { - s := PoetryServiceInfo() +func ConfigServiceAddress() string { + s := ConfigServiceInfo() return GetServiceAddress(s.Name, s.Port) } @@ -168,6 +168,24 @@ func OPAServiceAddress() string { return GetServiceAddress(s.Name, s.Port) } +func PolicyServiceInfo() *setting.ServiceInfo { + return GetServiceByCode(setting.Policy) +} + +func PolicyServiceAddress() string { + s := PolicyServiceInfo() + return GetServiceAddress(s.Name, s.Port) +} + +func UserServiceInfo() *setting.ServiceInfo { + return GetServiceByCode(setting.User) +} + +func UserServiceAddress() string { + s := UserServiceInfo() + return GetServiceAddress(s.Name, s.Port) +} + func GetServiceAddress(name string, port int32) string { return fmt.Sprintf("http://%s:%d", name, port) } @@ -215,3 +233,23 @@ func MongoURI() string { func MongoDatabase() string { return viper.GetString(setting.ENVAslanDBName) } + +func MysqlUser() string { + return viper.GetString(setting.ENVMysqlUser) +} + +func MysqlPassword() string { + return viper.GetString(setting.ENVMysqlPassword) +} + +func MysqlHost() string { + return viper.GetString(setting.ENVMysqlHost) +} + +func AdminEmail() string { + return viper.GetString(setting.ENVAdminEmail) +} + +func AdminPassword() string { + return viper.GetString(setting.ENVAdminPassword) +} diff --git a/pkg/microservice/aslan/config/config.go b/pkg/microservice/aslan/config/config.go index d27203b6352cdfe2552df1bbc34da8707666eae9..818381138d04228f075c8ffe0cc06828590b085c 100644 --- a/pkg/microservice/aslan/config/config.go +++ b/pkg/microservice/aslan/config/config.go @@ -74,14 +74,6 @@ func LogLevel() int { return viper.GetInt(setting.ENVLogLevel) } -func PoetryAPIServer() string { - return configbase.PoetryServiceAddress() -} - -func PoetryAPIRootKey() string { - return viper.GetString(setting.ENVPoetryAPIRootKey) -} - func CollieAPIAddress() string { return configbase.CollieServiceAddress() } diff --git a/pkg/microservice/aslan/core/build/handler/build.go b/pkg/microservice/aslan/core/build/handler/build.go index 5cf11416c0ad0f5f7f700de46858d69b20a433c1..b335d85f4e1347b9e2276fd8a98804c98b87fce1 100644 --- a/pkg/microservice/aslan/core/build/handler/build.go +++ b/pkg/microservice/aslan/core/build/handler/build.go @@ -34,14 +34,14 @@ func FindBuildModule(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - ctx.Resp, ctx.Err = buildservice.FindBuild(c.Param("name"), c.Query("productName"), ctx.Logger) + ctx.Resp, ctx.Err = buildservice.FindBuild(c.Param("name"), c.Query("projectName"), ctx.Logger) } func ListBuildModules(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - ctx.Resp, ctx.Err = buildservice.ListBuild(c.Query("name"), c.Query("targets"), c.Query("productName"), ctx.Logger) + ctx.Resp, ctx.Err = buildservice.ListBuild(c.Query("name"), c.Query("targets"), c.Query("projectName"), ctx.Logger) } func CreateBuildModule(c *gin.Context) { @@ -56,7 +56,7 @@ func CreateBuildModule(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("CreateBuildModule json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, args.ProductName, "新增", "项目管理-构建", args.Name, string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, args.ProductName, "新增", "项目管理-构建", args.Name, string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) err = c.BindJSON(args) @@ -65,7 +65,7 @@ func CreateBuildModule(c *gin.Context) { return } - ctx.Err = buildservice.CreateBuild(ctx.Username, args, ctx.Logger) + ctx.Err = buildservice.CreateBuild(ctx.UserName, args, ctx.Logger) } func UpdateBuildModule(c *gin.Context) { @@ -80,7 +80,7 @@ func UpdateBuildModule(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("UpdateBuildModule json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, args.ProductName, "更新", "项目管理-构建", args.Name, string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, args.ProductName, "更新", "项目管理-构建", args.Name, string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) err = c.BindJSON(args) @@ -88,7 +88,7 @@ func UpdateBuildModule(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("invalid Build args") return } - ctx.Err = buildservice.UpdateBuild(ctx.Username, args, ctx.Logger) + ctx.Err = buildservice.UpdateBuild(ctx.UserName, args, ctx.Logger) } func DeleteBuildModule(c *gin.Context) { @@ -96,8 +96,8 @@ func DeleteBuildModule(c *gin.Context) { defer func() { internalhandler.JSONResponse(c, ctx) }() name := c.Query("name") - productName := c.Query("productName") - internalhandler.InsertOperationLog(c, ctx.Username, productName, "删除", "项目管理-构建", name, "", ctx.Logger) + productName := c.Query("projectName") + internalhandler.InsertOperationLog(c, ctx.UserName, productName, "删除", "项目管理-构建", name, "", ctx.Logger) if name == "" { ctx.Err = e.ErrInvalidParam.AddDesc("empty Name") @@ -126,7 +126,7 @@ func UpdateBuildTargets(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddErr(err) return } - internalhandler.InsertOperationLog(c, ctx.Username, c.Query("productName"), "更新", "项目管理-服务组件", args.Name, string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, c.Query("projectName"), "更新", "项目管理-服务组件", args.Name, string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) if err := c.BindJSON(args); err != nil { @@ -134,5 +134,5 @@ func UpdateBuildTargets(c *gin.Context) { return } - ctx.Err = buildservice.UpdateBuildTargets(args.Name, c.Query("productName"), args.Targets, ctx.Logger) + ctx.Err = buildservice.UpdateBuildTargets(args.Name, c.Query("projectName"), args.Targets, ctx.Logger) } diff --git a/pkg/microservice/aslan/core/build/handler/router.go b/pkg/microservice/aslan/core/build/handler/router.go index f55bd25c153ed46c6b6f6789cfe745cd9f4d56ec..44811e7d3386b1ffd01ed31afcfb351cefd9d03c 100644 --- a/pkg/microservice/aslan/core/build/handler/router.go +++ b/pkg/microservice/aslan/core/build/handler/router.go @@ -20,22 +20,19 @@ import ( "github.com/gin-gonic/gin" gin2 "github.com/koderover/zadig/pkg/middleware/gin" - "github.com/koderover/zadig/pkg/types/permission" ) type Router struct{} func (*Router) Inject(router *gin.RouterGroup) { - router.Use(gin2.Auth()) - build := router.Group("build") { build.GET("/:name", FindBuildModule) build.GET("", ListBuildModules) - build.POST("", gin2.StoreProductName, gin2.IsHavePermission([]string{permission.BuildManageUUID}, permission.ContextKeyType), gin2.UpdateOperationLogStatus, CreateBuildModule) - build.PUT("", gin2.StoreProductName, gin2.IsHavePermission([]string{permission.BuildManageUUID}, permission.ContextKeyType), gin2.UpdateOperationLogStatus, UpdateBuildModule) - build.DELETE("", gin2.IsHavePermission([]string{permission.BuildDeleteUUID}, permission.QueryType), gin2.UpdateOperationLogStatus, DeleteBuildModule) - build.POST("/targets", gin2.IsHavePermission([]string{permission.BuildManageUUID}, permission.QueryType), gin2.UpdateOperationLogStatus, UpdateBuildTargets) + build.POST("", gin2.UpdateOperationLogStatus, CreateBuildModule) + build.PUT("", gin2.UpdateOperationLogStatus, UpdateBuildModule) + build.DELETE("", gin2.UpdateOperationLogStatus, DeleteBuildModule) + build.POST("/targets", gin2.UpdateOperationLogStatus, UpdateBuildTargets) } target := router.Group("targets") diff --git a/pkg/microservice/aslan/core/build/handler/target.go b/pkg/microservice/aslan/core/build/handler/target.go index 71f5e160084ebee3b9e02d3bf2e7112c3d6baf19..2978c4020390a1f126ffea7f8d8cbd888846a4f4 100644 --- a/pkg/microservice/aslan/core/build/handler/target.go +++ b/pkg/microservice/aslan/core/build/handler/target.go @@ -27,7 +27,7 @@ func ListDeployTarget(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - ctx.Resp, ctx.Err = buildservice.ListDeployTarget(c.Query("productName"), ctx.Logger) + ctx.Resp, ctx.Err = buildservice.ListDeployTarget(c.Query("projectName"), ctx.Logger) } func ListBuildModulesForProduct(c *gin.Context) { diff --git a/pkg/microservice/aslan/core/code/handler/codehost.go b/pkg/microservice/aslan/core/code/handler/codehost.go index 85a7198e115d38a0036db559033af590eed757e9..5c2ac180ece93a77b9da5231764ea5c8e66b2ae0 100644 --- a/pkg/microservice/aslan/core/code/handler/codehost.go +++ b/pkg/microservice/aslan/core/code/handler/codehost.go @@ -24,9 +24,8 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/core/code/service" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/codehost" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" internalhandler "github.com/koderover/zadig/pkg/shared/handler" - "github.com/koderover/zadig/pkg/shared/poetry" e "github.com/koderover/zadig/pkg/tool/errors" ) @@ -34,8 +33,8 @@ func GetCodeHostList(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - codeHostSlice := make([]*poetry.CodeHost, 0) - codeHosts, err := codehost.GetCodeHostList() + codeHostSlice := make([]*systemconfig.CodeHost, 0) + codeHosts, err := systemconfig.New().ListCodeHosts() ctx.Err = err for _, codeHost := range codeHosts { codeHost.AccessToken = setting.MaskValue diff --git a/pkg/microservice/aslan/core/code/handler/router.go b/pkg/microservice/aslan/core/code/handler/router.go index 74244b59ec21660a24c7bb14f0cff866b5dfa106..9627fc2d2167cad4212422371d41d58351d1ed5d 100644 --- a/pkg/microservice/aslan/core/code/handler/router.go +++ b/pkg/microservice/aslan/core/code/handler/router.go @@ -20,14 +20,11 @@ import ( "github.com/gin-gonic/gin" gin2 "github.com/koderover/zadig/pkg/middleware/gin" - "github.com/koderover/zadig/pkg/types/permission" ) type Router struct{} func (*Router) Inject(router *gin.RouterGroup) { - router.Use(gin2.Auth()) - codehost := router.Group("codehost") { codehost.GET("", GetCodeHostList) @@ -45,7 +42,7 @@ func (*Router) Inject(router *gin.RouterGroup) { // --------------------------------------------------------------------------------------- workspace := router.Group("workspace") { - workspace.DELETE("", GetProductNameByWorkspacePipeline, gin2.IsHavePermission([]string{permission.WorkflowUpdateUUID}, permission.ContextKeyType), gin2.UpdateOperationLogStatus, CleanWorkspace) + workspace.DELETE("", GetProductNameByWorkspacePipeline, gin2.UpdateOperationLogStatus, CleanWorkspace) workspace.GET("/file", GetWorkspaceFile) workspace.GET("/git/:codehostId/:repoName/:branchName/:remoteName", GetGitRepoInfo) diff --git a/pkg/microservice/aslan/core/code/handler/workspace.go b/pkg/microservice/aslan/core/code/handler/workspace.go index ae46b2e0835466375d9712bd52cc5d61b6b01b64..1d980ace88c5d275b4e39b8051bc3b5a2674cc64 100644 --- a/pkg/microservice/aslan/core/code/handler/workspace.go +++ b/pkg/microservice/aslan/core/code/handler/workspace.go @@ -31,7 +31,7 @@ import ( func GetProductNameByWorkspacePipeline(c *gin.Context) { ctx := internalhandler.NewContext(c) - pipeline, err := commonservice.GetPipelineInfo(ctx.User.ID, c.Query("pipelineName"), ctx.Logger) + pipeline, err := commonservice.GetPipelineInfo(c.Query("pipelineName"), ctx.Logger) if err != nil { log.Errorf("GetProductNameByWorkspacePipeline err : %v", err) return @@ -43,13 +43,13 @@ func GetProductNameByWorkspacePipeline(c *gin.Context) { func CleanWorkspace(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - internalhandler.InsertOperationLog(c, ctx.Username, c.GetString("productName"), "清理", "单服务工作流-工作目录", c.Query("pipelineName"), "", ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, c.GetString("productName"), "清理", "单服务工作流-工作目录", c.Query("pipelineName"), "", ctx.Logger) name := c.Query("pipelineName") if name == "" { ctx.Err = e.ErrInvalidParam.AddDesc("empty pipeline name") return } - ctx.Err = service.CleanWorkspace(ctx.Username, name, ctx.Logger) + ctx.Err = service.CleanWorkspace(ctx.UserName, name, ctx.Logger) } func GetWorkspaceFile(c *gin.Context) { @@ -69,7 +69,7 @@ func GetWorkspaceFile(c *gin.Context) { return } - fileRealPath, err := service.GetWorkspaceFilePath(ctx.Username, name, file, ctx.Logger) + fileRealPath, err := service.GetWorkspaceFilePath(ctx.UserName, name, file, ctx.Logger) if err != nil { c.JSON(e.ErrorMessage(err)) c.Abort() diff --git a/pkg/microservice/aslan/core/code/service/branch.go b/pkg/microservice/aslan/core/code/service/branch.go index 3945aa41cd2c89c85ef6bb22c9b6a9f4a029a93e..91c2fcf8e10be45dd80f1668a97ade3d12a5c468 100644 --- a/pkg/microservice/aslan/core/code/service/branch.go +++ b/pkg/microservice/aslan/core/code/service/branch.go @@ -23,7 +23,7 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/config" git "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/github" - "github.com/koderover/zadig/pkg/shared/codehost" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" "github.com/koderover/zadig/pkg/tool/codehub" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/gerrit" @@ -31,10 +31,7 @@ import ( ) func CodeHostListBranches(codeHostID int, projectName, namespace string, log *zap.SugaredLogger) ([]*Branch, error) { - opt := &codehost.Option{ - CodeHostID: codeHostID, - } - ch, err := codehost.GetCodeHostInfo(opt) + ch, err := systemconfig.New().GetCodeHost(codeHostID) if err != nil { return nil, e.ErrCodehostListBranches.AddDesc("git client is nil") } diff --git a/pkg/microservice/aslan/core/code/service/merge_request.go b/pkg/microservice/aslan/core/code/service/merge_request.go index 4f0d78e0d599d53ff7f47c9a14fb4cbaef4fec96..bbf8c40ef68d9cd6d9b788b890928bf3167a1bb8 100644 --- a/pkg/microservice/aslan/core/code/service/merge_request.go +++ b/pkg/microservice/aslan/core/code/service/merge_request.go @@ -24,17 +24,14 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/config" git "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/github" - "github.com/koderover/zadig/pkg/shared/codehost" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/gerrit" "github.com/koderover/zadig/pkg/tool/git/gitlab" ) func CodeHostListPRs(codeHostID int, projectName, namespace, targetBr string, log *zap.SugaredLogger) ([]*PullRequest, error) { - opt := &codehost.Option{ - CodeHostID: codeHostID, - } - ch, err := codehost.GetCodeHostInfo(opt) + ch, err := systemconfig.New().GetCodeHost(codeHostID) if err != nil { return nil, e.ErrCodehostListPrs.AddDesc("git client is nil") } diff --git a/pkg/microservice/aslan/core/code/service/namespace.go b/pkg/microservice/aslan/core/code/service/namespace.go index 5b5923de03e21d2f51978ca8749f1a4362865ad8..4633e85b16a03c15fe0f9c94cbf40b77b91cbd80 100644 --- a/pkg/microservice/aslan/core/code/service/namespace.go +++ b/pkg/microservice/aslan/core/code/service/namespace.go @@ -23,7 +23,7 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/config" git "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/github" - "github.com/koderover/zadig/pkg/shared/codehost" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" "github.com/koderover/zadig/pkg/tool/codehub" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/gerrit" @@ -41,10 +41,7 @@ const ( ) func CodeHostListNamespaces(codeHostID int, keyword string, log *zap.SugaredLogger) ([]*Namespace, error) { - opt := &codehost.Option{ - CodeHostID: codeHostID, - } - ch, err := codehost.GetCodeHostInfo(opt) + ch, err := systemconfig.New().GetCodeHost(codeHostID) if err != nil { return nil, e.ErrCodehostListNamespaces.AddDesc("git client is nil") } diff --git a/pkg/microservice/aslan/core/code/service/project.go b/pkg/microservice/aslan/core/code/service/project.go index 38103faf25476dbd3cb517e626bdc32e1e603b24..3a210a1cf8085d6e0dca732e17103ef608b9594b 100644 --- a/pkg/microservice/aslan/core/code/service/project.go +++ b/pkg/microservice/aslan/core/code/service/project.go @@ -23,7 +23,7 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/config" git "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/github" - "github.com/koderover/zadig/pkg/shared/codehost" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" "github.com/koderover/zadig/pkg/tool/codehub" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/gerrit" @@ -31,10 +31,7 @@ import ( ) func CodeHostListProjects(codeHostID int, namespace, namespaceType, keyword string, log *zap.SugaredLogger) ([]*Project, error) { - opt := &codehost.Option{ - CodeHostID: codeHostID, - } - ch, err := codehost.GetCodeHostInfo(opt) + ch, err := systemconfig.New().GetCodeHost(codeHostID) if err != nil { log.Error(err) return nil, e.ErrCodehostListProjects.AddDesc("git client is nil") diff --git a/pkg/microservice/aslan/core/code/service/tag.go b/pkg/microservice/aslan/core/code/service/tag.go index 90dd3cc31919ee28eec75d808ea4004d731cc0c2..4b9af5a01d8b9da67caa67df48079b6722112e03 100644 --- a/pkg/microservice/aslan/core/code/service/tag.go +++ b/pkg/microservice/aslan/core/code/service/tag.go @@ -23,7 +23,7 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/config" git "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/github" - "github.com/koderover/zadig/pkg/shared/codehost" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" "github.com/koderover/zadig/pkg/tool/codehub" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/gerrit" @@ -31,10 +31,7 @@ import ( ) func CodeHostListTags(codeHostID int, projectName string, namespace string, log *zap.SugaredLogger) ([]*Tag, error) { - opt := &codehost.Option{ - CodeHostID: codeHostID, - } - ch, err := codehost.GetCodeHostInfo(opt) + ch, err := systemconfig.New().GetCodeHost(codeHostID) if err != nil { log.Error(err) return nil, e.ErrCodehostListTags.AddDesc("git client is nil") diff --git a/pkg/microservice/aslan/core/code/service/workspace.go b/pkg/microservice/aslan/core/code/service/workspace.go index 751e008ac1277423668907cde686b139441bd1e0..a3b30f5ff740d25fb70c74e66876586676037c6c 100644 --- a/pkg/microservice/aslan/core/code/service/workspace.go +++ b/pkg/microservice/aslan/core/code/service/workspace.go @@ -28,7 +28,7 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/command" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/fs" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/git" - "github.com/koderover/zadig/pkg/shared/codehost" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" "github.com/koderover/zadig/pkg/tool/codehub" e "github.com/koderover/zadig/pkg/tool/errors" ) @@ -145,7 +145,7 @@ func GetGitRepoInfo(codehostID int, repoOwner, repoName, branchName, remoteName, if err := os.RemoveAll(base); err != nil { log.Errorf("dir remove err:%v", err) } - detail, err := codehost.GetCodehostDetail(codehostID) + detail, err := systemconfig.New().GetCodeHost(codehostID) if err != nil { log.Errorf("GetGitRepoInfo GetCodehostDetail err:%v", err) return fis, e.ErrListRepoDir.AddDesc(err.Error()) @@ -189,7 +189,7 @@ type CodehostFileInfo struct { func GetCodehubRepoInfo(codehostID int, repoUUID, branchName, path string, log *zap.SugaredLogger) ([]*CodehostFileInfo, error) { fileInfos := make([]*CodehostFileInfo, 0) - detail, err := codehost.GetCodehostDetail(codehostID) + detail, err := systemconfig.New().GetCodeHost(codehostID) if err != nil { log.Errorf("GetCodehubRepoInfo GetCodehostDetail err:%s", err) return fileInfos, e.ErrListWorkspace.AddDesc(err.Error()) diff --git a/pkg/microservice/aslan/core/common/repository/models/delivery_version.go b/pkg/microservice/aslan/core/common/repository/models/delivery_version.go index 785bc63842f9d71df6a76eee3de96706fdb96c5d..459d7f96f70c9e62e184a5fc380fc318c9aa0d94 100644 --- a/pkg/microservice/aslan/core/common/repository/models/delivery_version.go +++ b/pkg/microservice/aslan/core/common/repository/models/delivery_version.go @@ -22,7 +22,6 @@ import ( type DeliveryVersion struct { ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` - OrgID int `bson:"org_id" json:"orgId"` Version string `bson:"version" json:"version"` ProductName string `bson:"product_name" json:"productName"` WorkflowName string `bson:"workflow_name" json:"workflowName"` diff --git a/pkg/microservice/aslan/core/common/repository/models/external_link.go b/pkg/microservice/aslan/core/common/repository/models/external_link.go new file mode 100644 index 0000000000000000000000000000000000000000..9afc405bacf3f0665146596b9a4b2927147cb5d5 --- /dev/null +++ b/pkg/microservice/aslan/core/common/repository/models/external_link.go @@ -0,0 +1,16 @@ +package models + +import "go.mongodb.org/mongo-driver/bson/primitive" + +type ExternalLink struct { + ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + Name string `bson:"name" json:"name"` + URL string `bson:"url" json:"url"` + CreateTime int64 `bson:"create_time" json:"create_time"` + UpdateTime int64 `bson:"update_time" json:"update_time"` + UpdateBy string `bson:"update_by" json:"update_by"` +} + +func (ExternalLink) TableName() string { + return "external_link" +} diff --git a/pkg/microservice/aslan/core/common/repository/models/favorite_pipeline.go b/pkg/microservice/aslan/core/common/repository/models/favorite_pipeline.go index 5e1ab74ef06cb8b1c32802c05effec26fae8ba91..b0bca8b794cfd48041c0ef5e182d6d5040868fe4 100644 --- a/pkg/microservice/aslan/core/common/repository/models/favorite_pipeline.go +++ b/pkg/microservice/aslan/core/common/repository/models/favorite_pipeline.go @@ -20,7 +20,7 @@ import "go.mongodb.org/mongo-driver/bson/primitive" type Favorite struct { ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` - UserID int `bson:"user_id" json:"user_id"` + UserID string `bson:"user_id" json:"user_id"` ProductName string `bson:"product_name" json:"product_name"` Name string `bson:"name" json:"name"` Type string `bson:"type" json:"type"` diff --git a/pkg/microservice/aslan/core/common/repository/models/pipeline.go b/pkg/microservice/aslan/core/common/repository/models/pipeline.go index 40cfe1561b54c960659c2860456cd7885e96aa68..8be7b23f063bc0f68025f648017d3e18395c5ea4 100644 --- a/pkg/microservice/aslan/core/common/repository/models/pipeline.go +++ b/pkg/microservice/aslan/core/common/repository/models/pipeline.go @@ -32,8 +32,6 @@ type Pipeline struct { Enabled bool `bson:"enabled" json:"enabled"` TeamName string `bson:"team" json:"team"` ProductName string `bson:"product_name" json:"product_name"` - // OrgID 单租户ID - OrgID int `bson:"org_id" json:"org_id"` // target 服务名称, k8s为容器名称, 物理机为服务名 Target string `bson:"target" json:"target"` // 使用预定义编译管理模块中的内容生成SubTasks, diff --git a/pkg/microservice/aslan/core/common/repository/models/queue.go b/pkg/microservice/aslan/core/common/repository/models/queue.go index cf8fc7a0ce90a68b675cc739fe2db4a31b0b3545..7801b2c461d2aa333e225199734147e45ef10b10 100644 --- a/pkg/microservice/aslan/core/common/repository/models/queue.go +++ b/pkg/microservice/aslan/core/common/repository/models/queue.go @@ -64,14 +64,12 @@ type Queue struct { // TestArgs 测试任务参数 TestArgs *TestTaskArgs `bson:"test_args,omitempty" json:"test_args,omitempty"` // ServiceTaskArgs 脚本部署工作流任务参数 - ServiceTaskArgs *ServiceTaskArgs `bson:"service_args,omitempty" json:"service_args,omitempty"` - ConfigPayload *ConfigPayload `json:"config_payload,omitempty"` - Error string `bson:"error,omitempty" json:"error,omitempty"` - // OrgID 单租户ID - OrgID int `bson:"org_id,omitempty" json:"org_id,omitempty"` - Services [][]*ProductService `bson:"services" json:"services"` - Render *RenderInfo `bson:"render" json:"render"` - StorageURI string `bson:"storage_uri,omitempty" json:"storage_uri,omitempty"` + ServiceTaskArgs *ServiceTaskArgs `bson:"service_args,omitempty" json:"service_args,omitempty"` + ConfigPayload *ConfigPayload `json:"config_payload,omitempty"` + Error string `bson:"error,omitempty" json:"error,omitempty"` + Services [][]*ProductService `bson:"services" json:"services"` + Render *RenderInfo `bson:"render" json:"render"` + StorageURI string `bson:"storage_uri,omitempty" json:"storage_uri,omitempty"` // interface{} 为types.TestReport TestReports map[string]interface{} `bson:"test_reports,omitempty" json:"test_reports,omitempty"` @@ -111,7 +109,6 @@ type ServiceTaskArgs struct { } type ConfigPayload struct { - APIToken string `json:"api_token"` Proxy Proxy `json:"proxy"` S3Storage S3Config `json:"s3_storage"` Github GithubConfig `json:"github"` @@ -203,13 +200,13 @@ type RegistryConfig struct { type ReleaseConfig struct { // ReaperImage sets build job image - // e.g. xxx.com/poetry-resources/reaper-plugin:1.0.0 + // e.g. xxx.com/resources/reaper-plugin:1.0.0 ReaperImage string // ReaperBinaryFile sets download url of reaper binary file in build job // e.g. http://resource.koderover.com/reaper-20201014203000 ReaperBinaryFile string // PredatorImage sets docker build image - // e.g. xxx.com/poetry-resources/predator-plugin:v0.1.0 + // e.g. xxx.com/resources/predator-plugin:v0.1.0 PredatorImage string } diff --git a/pkg/microservice/aslan/core/common/repository/models/registry_namespace.go b/pkg/microservice/aslan/core/common/repository/models/registry_namespace.go index 3c45ae9848660e67d7776c98d23147221add43be..707493e33c063f95e9445edbcf3a00a64d6c7166 100644 --- a/pkg/microservice/aslan/core/common/repository/models/registry_namespace.go +++ b/pkg/microservice/aslan/core/common/repository/models/registry_namespace.go @@ -24,7 +24,6 @@ import ( type RegistryNamespace struct { ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` - OrgID int `bson:"org_id" json:"org_id"` RegAddr string `bson:"reg_addr" json:"reg_addr"` RegType string `bson:"reg_type" json:"reg_type"` RegProvider string `bson:"reg_provider" json:"reg_provider"` @@ -38,9 +37,6 @@ type RegistryNamespace struct { } func (ns *RegistryNamespace) Validate() error { - if ns.OrgID == 0 { - return errors.New("empty org_id") - } if ns.RegAddr == "" { return errors.New("empty reg_addr") diff --git a/pkg/microservice/aslan/core/common/repository/models/task/model.go b/pkg/microservice/aslan/core/common/repository/models/task/model.go index b71dabdb5f82412a01510019c73f01a2df4fd14a..c503d9c6f71f74c47fae1387887d51e1656018c3 100644 --- a/pkg/microservice/aslan/core/common/repository/models/task/model.go +++ b/pkg/microservice/aslan/core/common/repository/models/task/model.go @@ -70,8 +70,6 @@ type Task struct { // ConfigPayload 系统配置信息 ConfigPayload *models.ConfigPayload `json:"config_payload,omitempty"` Error string `bson:"error,omitempty" json:"error,omitempty"` - // OrgID 单租户ID - OrgID int `bson:"org_id,omitempty" json:"org_id,omitempty"` Services [][]*models.ProductService `bson:"services" json:"services"` Render *models.RenderInfo `bson:"render" json:"render"` StorageURI string `bson:"storage_uri,omitempty" json:"storage_uri,omitempty"` diff --git a/pkg/microservice/aslan/core/common/repository/models/task/release_image.go b/pkg/microservice/aslan/core/common/repository/models/task/release_image.go index c697c08b6bd2c6f2599b5edbc40ec1137a1ea921..e113a715e269ea81809c3c1b3449b75d36c909d2 100644 --- a/pkg/microservice/aslan/core/common/repository/models/task/release_image.go +++ b/pkg/microservice/aslan/core/common/repository/models/task/release_image.go @@ -23,15 +23,6 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" ) -//type RepoImage struct { -// RepoID string `json:"repo_id" bson:"repo_id"` -// Name string `json:"name" bson:"name" yaml:"name"` -// Username string `json:"-" yaml:"username"` -// Password string `json:"-" yaml:"password"` -// Host string `json:"host" yaml:"host"` -// Namespace string `json:"namespace" yaml:"namespace"` -//} - type ReleaseImageItem struct { RepoID string `bson:"id" json:"id"` Image string `bson:"image" json:"image"` diff --git a/pkg/microservice/aslan/core/common/repository/models/template/product.go b/pkg/microservice/aslan/core/common/repository/models/template/product.go index 69bc08d9096f3712ed194eb901147a2e96fadbc1..64940bca6de8f2cd7811ec3aefb80ce9284c12cc 100644 --- a/pkg/microservice/aslan/core/common/repository/models/template/product.go +++ b/pkg/microservice/aslan/core/common/repository/models/template/product.go @@ -29,8 +29,6 @@ type Product struct { ProductName string `bson:"product_name" json:"product_name"` Revision int64 `bson:"revision" json:"revision"` CreateTime int64 `bson:"create_time" json:"create_time"` - Teams []*Team `bson:"teams" json:"teams"` - Team string `bson:"team" json:"team"` UpdateTime int64 `bson:"update_time" json:"update_time"` UpdateBy string `bson:"update_by" json:"update_by"` Enabled bool `bson:"enabled" json:"enabled"` @@ -41,8 +39,6 @@ type Product struct { Vars []*RenderKV `bson:"vars" json:"vars"` EnvVars []*EnvRenderKV `bson:"-" json:"env_vars,omitempty"` ChartInfos []*RenderChart `bson:"-" json:"chart_infos,omitempty"` - UserIDs []int `bson:"user_ids" json:"user_ids"` - TeamID int `bson:"team_id" json:"team_id"` Description string `bson:"description,omitempty" json:"desc,omitempty"` ProductFeature *ProductFeature `bson:"product_feature,omitempty" json:"product_feature,omitempty"` ImageSearchingRules []*ImageSearchingRule `bson:"image_searching_rules,omitempty" json:"image_searching_rules,omitempty"` @@ -68,10 +64,10 @@ type Product struct { LatestWorkflowUpdateTime int64 `bson:"-" json:"latest_workflow_update_time"` LatestWorkflowUpdateBy string `bson:"-" json:"latest_workflow_update_by"` TotalEnvTemplateServiceNum int `bson:"-" json:"total_env_template_service_num"` - ShowProject bool `bson:"-" json:"show_project"` IsOpensource bool `bson:"is_opensource" json:"is_opensource"` CustomImageRule *CustomRule `bson:"custom_image_rule,omitempty" json:"custom_image_rule,omitempty"` CustomTarRule *CustomRule `bson:"custom_tar_rule,omitempty" json:"custom_tar_rule,omitempty"` + Public bool `bson:"public,omitempty" json:"public"` } type ServiceInfo struct { diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/delivery_version.go b/pkg/microservice/aslan/core/common/repository/mongodb/delivery_version.go index 69b56e10bf49d5f8fb37f109b12d69b7b975d67e..bae5fc668297d8d018f4da5b3bec632bd2137955 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/delivery_version.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/delivery_version.go @@ -33,7 +33,6 @@ import ( type DeliveryVersionArgs struct { ID string `json:"id"` - OrgID int `json:"orgId"` ProductName string `json:"productName"` WorkflowName string `json:"workflowName"` TaskID int `json:"taskId"` @@ -91,7 +90,7 @@ func (c *DeliveryVersionColl) Find(args *DeliveryVersionArgs) ([]*models.Deliver } var resp []*models.DeliveryVersion - query := bson.M{"org_id": args.OrgID, "deleted_at": 0} + query := bson.M{"deleted_at": 0} if args.ProductName != "" { query["product_name"] = args.ProductName } @@ -137,9 +136,9 @@ func (c *DeliveryVersionColl) Delete(id string) error { return err } -func (c *DeliveryVersionColl) ListDeliveryVersions(productName string, orgID int) ([]*models.DeliveryVersion, error) { +func (c *DeliveryVersionColl) ListDeliveryVersions(productName string) ([]*models.DeliveryVersion, error) { var resp []*models.DeliveryVersion - query := bson.M{"org_id": orgID, "deleted_at": 0} + query := bson.M{"deleted_at": 0} if productName != "" { query["product_name"] = productName } @@ -167,7 +166,7 @@ func (c *DeliveryVersionColl) Get(args *DeliveryVersionArgs) (*models.DeliveryVe if args.ID != "" { query = bson.M{"_id": args.ID, "deleted_at": 0} } else { - query = bson.M{"org_id": args.OrgID, "product_name": args.ProductName, "workflow_name": args.WorkflowName, "task_id": args.TaskID, "deleted_at": 0} + query = bson.M{"product_name": args.ProductName, "workflow_name": args.WorkflowName, "task_id": args.TaskID, "deleted_at": 0} } err := c.FindOne(context.TODO(), query).Decode(&resp) @@ -205,9 +204,9 @@ func (c *DeliveryVersionColl) Update(args *models.DeliveryVersion) error { return err } -func (c *DeliveryVersionColl) FindProducts(orgID int) ([]string, error) { +func (c *DeliveryVersionColl) FindProducts() ([]string, error) { resp := make([]string, 0) - query := bson.M{"org_id": orgID, "deleted_at": 0} + query := bson.M{"deleted_at": 0} ret, err := c.Distinct(context.TODO(), "product_name", query) if err != nil { return nil, err diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/external_link.go b/pkg/microservice/aslan/core/common/repository/mongodb/external_link.go new file mode 100644 index 0000000000000000000000000000000000000000..5c67561380874fbd9be6035b0fb2ac253f5489a6 --- /dev/null +++ b/pkg/microservice/aslan/core/common/repository/mongodb/external_link.go @@ -0,0 +1,111 @@ +package mongodb + +import ( + "context" + "errors" + "time" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + + "github.com/koderover/zadig/pkg/microservice/aslan/config" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" + mongotool "github.com/koderover/zadig/pkg/tool/mongo" +) + +type ExternalLinkColl struct { + *mongo.Collection + + coll string +} + +func NewExternalLinkColl() *ExternalLinkColl { + name := models.ExternalLink{}.TableName() + return &ExternalLinkColl{ + Collection: mongotool.Database(config.MongoDatabase()).Collection(name), + coll: name, + } +} + +func (c *ExternalLinkColl) GetCollectionName() string { + return c.coll +} + +func (c *ExternalLinkColl) EnsureIndex(ctx context.Context) error { + mod := mongo.IndexModel{ + Keys: bson.D{ + bson.E{Key: "name", Value: 1}, + bson.E{Key: "url", Value: 1}, + }, + Options: options.Index().SetUnique(true), + } + _, err := c.Indexes().CreateOne(ctx, mod) + return err +} + +func (c *ExternalLinkColl) List() ([]*models.ExternalLink, error) { + query := bson.M{} + resp := make([]*models.ExternalLink, 0) + ctx := context.Background() + + cursor, err := c.Collection.Find(ctx, query) + if err != nil { + return nil, err + } + + err = cursor.All(ctx, &resp) + if err != nil { + return nil, err + } + + return resp, err +} + +func (c *ExternalLinkColl) Create(args *models.ExternalLink) error { + if args == nil { + return errors.New("nil externalLink info") + } + + args.CreateTime = time.Now().Unix() + args.UpdateTime = time.Now().Unix() + + _, err := c.InsertOne(context.TODO(), args) + + return err +} + +func (c *ExternalLinkColl) Update(id string, args *models.ExternalLink) error { + if args == nil { + return errors.New("nil externalLink info") + } + + oid, err := primitive.ObjectIDFromHex(id) + if err != nil { + return err + } + + query := bson.M{"_id": oid} + change := bson.M{"$set": bson.M{ + "name": args.Name, + "url": args.URL, + "update_by": args.UpdateBy, + "update_time": time.Now().Unix(), + }} + + _, err = c.UpdateOne(context.TODO(), query, change) + return err +} + +func (c *ExternalLinkColl) Delete(id string) error { + oid, err := primitive.ObjectIDFromHex(id) + if err != nil { + return err + } + + query := bson.M{"_id": oid} + + _, err = c.DeleteOne(context.TODO(), query) + return err +} diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/favorite_pipeline.go b/pkg/microservice/aslan/core/common/repository/mongodb/favorite_pipeline.go index fb20f134748604301cbf0464e429ecf3274de9a4..54e747df64b3c26bee063077165294612f9f9b4c 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/favorite_pipeline.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/favorite_pipeline.go @@ -31,7 +31,7 @@ import ( ) type FavoriteArgs struct { - UserID int + UserID string ProductName string Name string Type string @@ -99,7 +99,7 @@ func (c *FavoriteColl) List(args *FavoriteArgs) ([]*models.Favorite, error) { return resp, err } -func (c *FavoriteColl) Find(userID int, name, Type string) (*models.Favorite, error) { +func (c *FavoriteColl) Find(userID, name, Type string) (*models.Favorite, error) { resp := new(models.Favorite) query := bson.M{"user_id": userID, "name": name} if Type != "" { diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/product.go b/pkg/microservice/aslan/core/common/repository/mongodb/product.go index 564fdc796af64d4ddead57520574507b08697c00..3611104dd5def92cc28004aeefb38ec4647d1b91 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/product.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/product.go @@ -39,15 +39,16 @@ type ProductFindOptions struct { // ClusterId is a primitive.ObjectID{}.Hex() type ProductListOptions struct { - EnvName string - Name string - IsPublic bool - ClusterID string - IsSort bool - ExcludeStatus string - ExcludeSource string - Source string - InProjects []string + EnvName string + Name string + IsPublic bool + ClusterID string + IsSortByUpdateTime bool + IsSortByProductName bool + ExcludeStatus string + ExcludeSource string + Source string + InProjects []string } type projectEnvs struct { @@ -164,9 +165,12 @@ func (c *ProductColl) List(opt *ProductListOptions) ([]*models.Product, error) { ctx := context.Background() opts := options.Find() - if opt.IsSort { + if opt.IsSortByUpdateTime { opts.SetSort(bson.D{{"update_time", -1}}) } + if opt.IsSortByProductName { + opts.SetSort(bson.D{{"product_name", 1}}) + } cursor, err := c.Collection.Find(ctx, query, opts) if err != nil { return nil, err @@ -180,10 +184,15 @@ func (c *ProductColl) List(opt *ProductListOptions) ([]*models.Product, error) { return ret, nil } -func (c *ProductColl) ListProjects() ([]*projectEnvs, error) { +func (c *ProductColl) ListProjectsInNames(names []string) ([]*projectEnvs, error) { var res []*projectEnvs - pipeline := []bson.M{ - { + var pipeline []bson.M + if len(names) > 0 { + pipeline = append(pipeline, bson.M{"$match": bson.M{"product_name": bson.M{"$in": names}}}) + } + + pipeline = append(pipeline, + bson.M{ "$group": bson.M{ "_id": bson.M{ "product_name": "$product_name", @@ -192,7 +201,7 @@ func (c *ProductColl) ListProjects() ([]*projectEnvs, error) { "envs": bson.M{"$push": "$env_name"}, }, }, - } + ) cursor, err := c.Aggregate(context.TODO(), pipeline) if err != nil { diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/registry_namespace.go b/pkg/microservice/aslan/core/common/repository/mongodb/registry_namespace.go index 27c67248e5eae6305913f1062783056cdcb24997..d3df395c3493207a9f8ab626e3ea2b07afe7aeaa 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/registry_namespace.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/registry_namespace.go @@ -33,7 +33,6 @@ import ( type FindRegOps struct { ID string `json:"id"` - OrgID int `json:"org_id"` RegAddr string `json:"reg_addr"` RegType string `json:"reg_type"` RegProvider string `json:"reg_provider"` @@ -97,10 +96,6 @@ func (opt FindRegOps) getQuery() bson.M { query["is_default"] = true } - if opt.OrgID != 0 { - query["org_id"] = opt.OrgID - } - if opt.RegType != "" { query["reg_type"] = opt.RegType } @@ -148,28 +143,6 @@ func (r *RegistryNamespaceColl) FindAll(opt *FindRegOps) ([]*models.RegistryName return resp, err } -func (r *RegistryNamespaceColl) List(orgID int, regType string) ([]*models.RegistryNamespace, error) { - query := bson.M{"org_id": orgID} - if regType != "" { - query["reg_type"] = regType - } - - ctx := context.Background() - opts := options.Find() - resp := make([]*models.RegistryNamespace, 0) - cursor, err := r.Collection.Find(ctx, query, opts) - if err != nil { - return nil, err - } - - err = cursor.All(ctx, &resp) - if err != nil { - return nil, err - } - - return resp, err -} - func (r *RegistryNamespaceColl) Update(id string, args *models.RegistryNamespace) error { if args == nil { return errors.New("nil Install") diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/service.go b/pkg/microservice/aslan/core/common/repository/mongodb/service.go index 572ef8acf5b4ffd37c416da07269bee9325c786b..30342b4c472dc7dfdc0d9e7c60591f277cb28c6d 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/service.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/service.go @@ -329,6 +329,24 @@ func (c *ServiceColl) BatchUpdateExternalServicesStatus(productName, envName, st return err } +// UpdateExternalServiceEnvName only used by external services +func (c *ServiceColl) UpdateExternalServiceEnvName(serviceName, productName, envName string) error { + if serviceName == "" { + return fmt.Errorf("serviceName is empty") + } + if productName == "" { + return fmt.Errorf("productName is empty") + } + + query := bson.M{"service_name": serviceName, "product_name": productName} + change := bson.M{"$set": bson.M{ + "env_name": envName, + }} + + _, err := c.UpdateOne(context.TODO(), query, change) + return err +} + // UpdateExternalServicesStatus only used by external services func (c *ServiceColl) UpdateExternalServicesStatus(serviceName, productName, status, envName string) error { if serviceName == "" && envName == "" { diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/template/product.go b/pkg/microservice/aslan/core/common/repository/mongodb/template/product.go index 5f0dbd1517a1839b666ec844806afcd2fd777a88..c5d232276e1b1a0bfd2a1b12dc6a8451a39dd560 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/template/product.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/template/product.go @@ -31,6 +31,16 @@ import ( mongotool "github.com/koderover/zadig/pkg/tool/mongo" ) +type ProjectInfo struct { + Name string `bson:"product_name"` + Alias string `bson:"project_name"` + Desc string `bson:"description"` + UpdatedAt int64 `bson:"update_time"` + UpdatedBy string `bson:"update_by"` + OnboardStatus int `bson:"onboarding_status"` + Public bool `bson:"public"` +} + type ProductColl struct { *mongo.Collection @@ -71,47 +81,72 @@ func (c *ProductColl) FindProjectName(project string) (*template.Product, error) return resp, err } -func (c *ProductColl) List() ([]*template.Product, error) { - var resp []*template.Product - - cursor, err := c.Collection.Find(context.TODO(), bson.M{}) +func (c *ProductColl) ListNames(inNames []string) ([]string, error) { + res, err := c.listProjects(inNames, bson.D{ + {"product_name", 1}, + }) if err != nil { return nil, err } - err = cursor.All(context.TODO(), &resp) - if err != nil { - return nil, err + + var names []string + for _, r := range res { + names = append(names, r.Name) } - return resp, nil + return names, nil } -func (c *ProductColl) ListNames() ([]string, error) { - var res []struct { - ProductName string `bson:"product_name"` - } +func (c *ProductColl) ListProjectBriefs(inNames []string) ([]*ProjectInfo, error) { + return c.listProjects(inNames, bson.D{ + {"product_name", 1}, + {"project_name", 1}, + {"description", 1}, + {"update_time", 1}, + {"update_by", 1}, + {"onboarding_status", 1}, + {"public", 1}, + }) +} +func (c *ProductColl) listProjects(inNames []string, projection bson.D) ([]*ProjectInfo, error) { opts := options.Find() - projection := bson.D{ - {"product_name", 1}, + filter := bson.M{} + if len(inNames) > 0 { + filter["product_name"] = bson.M{"$in": inNames} } - opts.SetProjection(projection) - cursor, err := c.Collection.Find(context.TODO(), bson.M{}, opts) + if len(projection) > 0 { + opts.SetProjection(projection) + } + + cursor, err := c.Collection.Find(context.TODO(), filter, opts) if err != nil { return nil, err } + + var res []*ProjectInfo err = cursor.All(context.TODO(), &res) if err != nil { return nil, err } - var names []string - for _, r := range res { - names = append(names, r.ProductName) + return res, nil +} + +func (c *ProductColl) List() ([]*template.Product, error) { + var resp []*template.Product + + cursor, err := c.Collection.Find(context.TODO(), bson.M{}) + if err != nil { + return nil, err + } + err = cursor.All(context.TODO(), &resp) + if err != nil { + return nil, err } - return names, nil + return resp, nil } type ProductListOpt struct { @@ -182,6 +217,19 @@ func (c *ProductColl) Create(args *template.Product) error { return err } +func (c *ProductColl) UpdateServiceOrchestration(productName string, services [][]string, updateBy string) error { + + query := bson.M{"product_name": productName} + change := bson.M{"$set": bson.M{ + "services": services, + "update_time": time.Now().Unix(), + "update_by": updateBy, + }} + + _, err := c.UpdateOne(context.TODO(), query, change) + return err +} + // Update existing ProductTmpl func (c *ProductColl) Update(productName string, args *template.Product) error { // avoid panic issue @@ -198,17 +246,14 @@ func (c *ProductColl) Update(productName string, args *template.Product) error { "services": args.Services, "update_time": time.Now().Unix(), "update_by": args.UpdateBy, - "teams": args.Teams, "enabled": args.Enabled, "description": args.Description, - "visibility": args.Visibility, - "user_ids": args.UserIDs, - "team_id": args.TeamID, "timeout": args.Timeout, "shared_services": args.SharedServices, "image_searching_rules": args.ImageSearchingRules, "custom_tar_rule": args.CustomTarRule, "custom_image_rule": args.CustomImageRule, + "public": args.Public, }} _, err := c.UpdateOne(context.TODO(), query, change) @@ -221,24 +266,6 @@ type ProductArgs struct { UpdateBy string `json:"update_by"` } -// UpdateServiceOrder existing ProductTmpl -func (c *ProductColl) UpdateServiceOrder(args *ProductArgs) error { - // avoid panic issue - if args == nil { - return errors.New("nil product args") - } - - query := bson.M{"product_name": args.ProductName} - change := bson.M{"$set": bson.M{ - "services": args.Services, - "update_time": time.Now().Unix(), - "update_by": args.UpdateBy, - }} - - _, err := c.UpdateOne(context.TODO(), query, change) - return err -} - // AddService adds a service to services[0] if it is not there. func (c *ProductColl) AddService(productName, serviceName string) error { diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/webhook.go b/pkg/microservice/aslan/core/common/repository/mongodb/webhook.go index 39f153ba1955014c7f254501f7ee867b9e8913b3..2f68b259fbb20952f82c36597e75fc19bbfc2850 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/webhook.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/webhook.go @@ -119,6 +119,20 @@ func (c *WebHookColl) Delete(owner, repo, address string) error { return nil } +func (c *WebHookColl) List() ([]*models.WebHook, error) { + res := make([]*models.WebHook, 0) + cursor, err := c.Collection.Find(context.TODO(), bson.M{}) + if err != nil { + return nil, err + } + err = cursor.All(context.TODO(), &res) + if err != nil { + return nil, err + } + + return res, err +} + // Find find webhook func (c *WebHookColl) Find(owner, repo, address string) (*models.WebHook, error) { query := bson.M{"owner": owner, "repo": repo, "address": address} diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/workflow.go b/pkg/microservice/aslan/core/common/repository/mongodb/workflow.go index 4f482802bbac62412fbaddeb176a54d8e5ddc84e..edd7015c6489baf847c150c2a2e5dbb1c387796e 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/workflow.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/workflow.go @@ -172,3 +172,25 @@ func (c *WorkflowColl) ListWithScheduleEnabled() ([]*models.Workflow, error) { return resp, nil } + +func (c *WorkflowColl) ListWorkflowsByProjects(projects []string) ([]*models.Workflow, error) { + resp := make([]*models.Workflow, 0) + query := bson.M{} + if len(projects) != 0 { + query = bson.M{"product_tmpl_name": bson.M{ + "$in": projects, + }} + } + + cursor, err := c.Collection.Find(context.TODO(), query) + if err != nil { + return nil, err + } + + err = cursor.All(context.TODO(), &resp) + if err != nil { + return nil, err + } + + return resp, nil +} diff --git a/pkg/microservice/aslan/core/common/service/collie/client.go b/pkg/microservice/aslan/core/common/service/collie/client.go index a2b94c6a0ad6fc85cd226f9b9fd80b7fbb21d830..05c9beaff788e84546206096bafa2134ee111377 100644 --- a/pkg/microservice/aslan/core/common/service/collie/client.go +++ b/pkg/microservice/aslan/core/common/service/collie/client.go @@ -17,27 +17,22 @@ limitations under the License. package collie import ( - "github.com/koderover/zadig/pkg/setting" "github.com/koderover/zadig/pkg/tool/httpclient" ) type Client struct { *httpclient.Client - host string - token string + host string } -func New(host, token string) *Client { +func New(host string) *Client { c := httpclient.New( - httpclient.SetAuthScheme(setting.RootAPIKey), - httpclient.SetAuthToken(token), httpclient.SetHostURL(host), ) return &Client{ Client: c, host: host, - token: token, } } diff --git a/pkg/microservice/aslan/core/common/service/command/git_cmd.go b/pkg/microservice/aslan/core/common/service/command/git_cmd.go index d47f3f8cbbc32066e478d2e5f9a647b266508321..d28708bbc05960079146174fae6928db4747a969 100644 --- a/pkg/microservice/aslan/core/common/service/command/git_cmd.go +++ b/pkg/microservice/aslan/core/common/service/command/git_cmd.go @@ -30,7 +30,7 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/config" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/codehost" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" "github.com/koderover/zadig/pkg/tool/log" ) @@ -65,7 +65,7 @@ type Command struct { IgnoreError bool } -func RunGitCmds(codehostDetail *codehost.Detail, repoOwner, repoName, branchName, remoteName string) error { +func RunGitCmds(codehostDetail *systemconfig.CodeHost, repoOwner, repoName, branchName, remoteName string) error { var ( tokens []string repo *Repo @@ -73,11 +73,11 @@ func RunGitCmds(codehostDetail *codehost.Detail, repoOwner, repoName, branchName cmds = make([]*Command, 0) ) repo = &Repo{ - Source: codehostDetail.Source, + Source: codehostDetail.Type, Address: codehostDetail.Address, Name: repoName, Branch: branchName, - OauthToken: codehostDetail.OauthToken, + OauthToken: codehostDetail.AccessToken, RemoteName: remoteName, Owner: repoOwner, } diff --git a/pkg/microservice/aslan/core/common/service/config_payload.go b/pkg/microservice/aslan/core/common/service/config_payload.go index ec01b0c7d59038fe98c3e1c23302d4130da8adba..ac244fe381d5de048b400dfc6f43d2966894ff6e 100644 --- a/pkg/microservice/aslan/core/common/service/config_payload.go +++ b/pkg/microservice/aslan/core/common/service/config_payload.go @@ -21,12 +21,11 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/codehost" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" ) func GetConfigPayload(codeHostID int) *models.ConfigPayload { payload := &models.ConfigPayload{ - APIToken: config.PoetryAPIRootKey(), S3Storage: models.S3Config{ Ak: config.S3StorageAK(), Sk: config.S3StorageSK(), @@ -74,7 +73,7 @@ func GetConfigPayload(codeHostID int) *models.ConfigPayload { } if codeHostID > 0 { - ch, _ := codehost.GetCodeHostInfoByID(codeHostID) + ch, _ := systemconfig.New().GetCodeHost(codeHostID) if ch != nil && ch.Type == setting.SourceFromGithub { payload.Github.AccessToken = ch.AccessToken } diff --git a/pkg/microservice/aslan/core/common/service/delivery.go b/pkg/microservice/aslan/core/common/service/delivery.go index 91d40737f6f19b0e59b991f6750ae8c74f47ba08..74baaf6f73714206728de1e344bfee21f54e8751 100644 --- a/pkg/microservice/aslan/core/common/service/delivery.go +++ b/pkg/microservice/aslan/core/common/service/delivery.go @@ -36,7 +36,7 @@ import ( ) func DeleteDeliveryInfos(productName string, log *zap.SugaredLogger) error { - deliveryVersions, err := mongodb.NewDeliveryVersionColl().ListDeliveryVersions(productName, 1) + deliveryVersions, err := mongodb.NewDeliveryVersionColl().ListDeliveryVersions(productName) if err != nil { log.Errorf("delete DeleteDeliveryInfo error: %v", err) return e.ErrDeleteDeliveryVersion @@ -71,9 +71,8 @@ func DeleteDeliveryInfos(productName string, log *zap.SugaredLogger) error { return nil } -func AddDeliveryVersion(orgID, taskID int, productName, workflowName string, pipelineTask *taskmodels.Task, logger *zap.SugaredLogger) error { +func AddDeliveryVersion(taskID int, productName, workflowName string, pipelineTask *taskmodels.Task, logger *zap.SugaredLogger) error { deliveryVersionArgs := &mongodb.DeliveryVersionArgs{ - OrgID: orgID, ProductName: productName, WorkflowName: workflowName, TaskID: taskID, @@ -87,7 +86,6 @@ func AddDeliveryVersion(orgID, taskID int, productName, workflowName string, pip } deliveryVersion := new(commonmodels.DeliveryVersion) - deliveryVersion.OrgID = orgID deliveryVersion.WorkflowName = workflowName deliveryVersion.TaskID = taskID deliveryVersion.ProductName = productName diff --git a/pkg/microservice/aslan/core/common/service/fs/git.go b/pkg/microservice/aslan/core/common/service/fs/git.go index 12b5c9003288bdc06e54e452a43895d7a61861b8..4ab9082ae16c16a35ce6157c8fa5c92ec13e49ae 100644 --- a/pkg/microservice/aslan/core/common/service/fs/git.go +++ b/pkg/microservice/aslan/core/common/service/fs/git.go @@ -27,7 +27,7 @@ import ( githubservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/github" gitlabservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/gitlab" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/codehost" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" "github.com/koderover/zadig/pkg/tool/log" ) @@ -101,7 +101,7 @@ func GetPublicTreeGetter(repoLink string) (TreeGetter, error) { } func GetTreeGetter(codeHostID int) (TreeGetter, error) { - ch, err := codehost.GetCodeHostInfoByID(codeHostID) + ch, err := systemconfig.New().GetCodeHost(codeHostID) if err != nil { log.Errorf("Failed to get codeHost by id %d, err: %s", codeHostID, err) return nil, err diff --git a/pkg/microservice/aslan/core/common/service/gerrit/gerrit.go b/pkg/microservice/aslan/core/common/service/gerrit/gerrit.go index 5706817753bedf002233420d38b0cf159a57f013..516d4e17c28fb29ff0bcd0d2bf3305ab9445b8f3 100644 --- a/pkg/microservice/aslan/core/common/service/gerrit/gerrit.go +++ b/pkg/microservice/aslan/core/common/service/gerrit/gerrit.go @@ -26,7 +26,7 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/config" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" - "github.com/koderover/zadig/pkg/shared/codehost" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" "github.com/koderover/zadig/pkg/tool/gerrit" ) @@ -37,7 +37,7 @@ func DeleteGerritWebhook(workflow *models.Workflow, log *zap.SugaredLogger) erro continue } - detail, err := codehost.GetCodeHostInfoByID(workflowWebhook.MainRepo.CodehostID) + detail, err := systemconfig.New().GetCodeHost(workflowWebhook.MainRepo.CodehostID) if err != nil { log.Errorf("DeleteGerritWebhook GetCodehostDetail err:%v", err) continue diff --git a/pkg/microservice/aslan/core/common/service/git/hook.go b/pkg/microservice/aslan/core/common/service/git/hook.go index dcff7666cf3b146f73d2a70d1a7003741887aea8..08770cc51ad020970fc30268e35befc99efe739d 100644 --- a/pkg/microservice/aslan/core/common/service/git/hook.go +++ b/pkg/microservice/aslan/core/common/service/git/hook.go @@ -17,26 +17,14 @@ limitations under the License. package git import ( - "sync" + "crypto/sha256" + "encoding/hex" - "github.com/koderover/zadig/pkg/microservice/aslan/config" - "github.com/koderover/zadig/pkg/shared/poetry" - "github.com/koderover/zadig/pkg/tool/log" + "github.com/koderover/zadig/pkg/config" ) -var once sync.Once -var secret string - func GetHookSecret() string { - once.Do(func() { - poetryClient := poetry.New(config.PoetryAPIServer(), config.PoetryAPIRootKey()) - org, err := poetryClient.GetOrganization(poetry.DefaultOrganization) - if err != nil { - log.Errorf("failed to find default organization: %v", err) - secret = "--impossible-token--" - } - secret = org.Token - }) - - return secret + hash := sha256.Sum256([]byte(config.SecretKey())) + + return hex.EncodeToString(hash[:]) } diff --git a/pkg/microservice/aslan/core/common/service/github/webhook.go b/pkg/microservice/aslan/core/common/service/github/webhook.go index ebd172285ded81b45a63a43d50b5cd15bdadf038..645bf05d1e8277bc042366c69ab47dae4ca60eea 100644 --- a/pkg/microservice/aslan/core/common/service/github/webhook.go +++ b/pkg/microservice/aslan/core/common/service/github/webhook.go @@ -31,14 +31,30 @@ func (c *Client) CreateWebHook(owner, repo string) (string, error) { Secret: gitservice.GetHookSecret(), Events: []string{git.PushEvent, git.PullRequestEvent, git.BranchOrTagCreateEvent, git.CheckRunEvent}, }) + if err != nil { + return "", err + } - return strconv.Itoa(int(hook.GetID())), err + return strconv.Itoa(int(hook.GetID())), nil } func (c *Client) DeleteWebHook(owner, repo, hookID string) error { - hookIDInt, err := strconv.Atoi(hookID) + hookIDInt, err := strconv.ParseInt(hookID, 10, 64) + if err != nil { + return err + } + return c.DeleteHook(context.TODO(), owner, repo, hookIDInt) +} + +func (c *Client) RefreshWebHookSecret(secret, owner, repo, hookID string) error { + hookIDInt, err := strconv.ParseInt(hookID, 10, 64) if err != nil { return err } - return c.DeleteHook(context.TODO(), owner, repo, int64(hookIDInt)) + _, err = c.UpdateHook(context.TODO(), owner, repo, hookIDInt, &git.Hook{ + URL: config.WebHookURL(), + Secret: secret, + }) + + return err } diff --git a/pkg/microservice/aslan/core/common/service/gitlab/webhook.go b/pkg/microservice/aslan/core/common/service/gitlab/webhook.go index cf6f76736c2bd6e4fe48147206163e78fa78ecaf..f1a1e772e9cc11c00a26508ac9745c8505ecd18b 100644 --- a/pkg/microservice/aslan/core/common/service/gitlab/webhook.go +++ b/pkg/microservice/aslan/core/common/service/gitlab/webhook.go @@ -44,3 +44,16 @@ func (c *Client) DeleteWebHook(owner, repo, hookID string) error { } return c.DeleteProjectHook(owner, repo, hookIDInt) } + +func (c *Client) RefreshWebHookSecret(secret, owner, repo, hookID string) error { + hookIDInt, err := strconv.Atoi(hookID) + if err != nil { + return err + } + _, err = c.UpdateProjectHook(owner, repo, hookIDInt, &git.Hook{ + URL: config.WebHookURL(), + Secret: secret, + }) + + return err +} diff --git a/pkg/microservice/aslan/core/common/service/pipeline.go b/pkg/microservice/aslan/core/common/service/pipeline.go index 3fc47b6c11949229cc589f39f8e359c10ad3498e..dd7b9e1549af95530f9730980873bf35963d9dc0 100644 --- a/pkg/microservice/aslan/core/common/service/pipeline.go +++ b/pkg/microservice/aslan/core/common/service/pipeline.go @@ -111,7 +111,7 @@ func DeletePipeline(pipelineName, requestID string, isDeletingProductTmpl bool, return nil } -func GetPipelineInfo(userID int, pipelineName string, log *zap.SugaredLogger) (*commonmodels.Pipeline, error) { +func GetPipelineInfo(pipelineName string, log *zap.SugaredLogger) (*commonmodels.Pipeline, error) { resp, err := mongodb.NewPipelineColl().Find(&mongodb.PipelineFindOption{Name: pipelineName}) if err != nil { log.Error(err) diff --git a/pkg/microservice/aslan/core/common/service/product.go b/pkg/microservice/aslan/core/common/service/product.go index d7f2ef47c08d0b1e2e6b91f7afbfcecf005cdb7a..9986f3575f95d8ab55a029697fc8049b3592f718 100644 --- a/pkg/microservice/aslan/core/common/service/product.go +++ b/pkg/microservice/aslan/core/common/service/product.go @@ -27,7 +27,6 @@ import ( "k8s.io/apimachinery/pkg/util/sets" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/koderover/zadig/pkg/microservice/aslan/config" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" commonmodels "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" @@ -35,7 +34,6 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb/template" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/poetry" e "github.com/koderover/zadig/pkg/tool/errors" helmtool "github.com/koderover/zadig/pkg/tool/helmclient" "github.com/koderover/zadig/pkg/tool/kube/updater" @@ -73,8 +71,6 @@ func DeleteProduct(username, envName, productName, requestID string, log *zap.Su log.Infof("[%s] delete product %s", username, productInfo.Namespace) LogProductStats(username, setting.DeleteProductEvent, productName, requestID, eventStart, log) - poetryClient := poetry.New(config.PoetryAPIServer(), config.PoetryAPIRootKey()) - switch productInfo.Source { case setting.SourceFromHelm: err = mongodb.NewProductColl().Delete(envName, productName) @@ -82,11 +78,6 @@ func DeleteProduct(username, envName, productName, requestID string, log *zap.Su log.Errorf("Product.Delete error: %v", err) } - _, err = poetryClient.DeleteEnvRolePermission(productName, envName, log) - if err != nil { - log.Errorf("DeleteEnvRole error: %v", err) - } - go func() { var err error defer func() { @@ -134,11 +125,6 @@ func DeleteProduct(username, envName, productName, requestID string, log *zap.Su log.Errorf("Product.Delete error: %v", err) } - _, err = poetryClient.DeleteEnvRolePermission(productName, envName, log) - if err != nil { - log.Errorf("DeleteEnvRole error: %v", err) - } - // 删除workload数据 tempProduct, err := template.NewProductColl().Find(productName) if err != nil { @@ -240,11 +226,6 @@ func DeleteProduct(username, envName, productName, requestID string, log *zap.Su if err != nil { log.Errorf("Product.Delete error: %v", err) } - - _, err = poetryClient.DeleteEnvRolePermission(productName, envName, log) - if err != nil { - log.Errorf("DeleteEnvRole error: %v", err) - } }() } return nil diff --git a/pkg/microservice/aslan/core/common/service/scmnotify/client.go b/pkg/microservice/aslan/core/common/service/scmnotify/client.go index f7299ce33307489062d20c635d2ae0d9dd3ee5c7..39964c6b9edfe7d35acce48e97d2c8b79ed770d7 100644 --- a/pkg/microservice/aslan/core/common/service/scmnotify/client.go +++ b/pkg/microservice/aslan/core/common/service/scmnotify/client.go @@ -27,7 +27,7 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/config" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" - "github.com/koderover/zadig/pkg/shared/codehost" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" "github.com/koderover/zadig/pkg/tool/gerrit" gitlabtool "github.com/koderover/zadig/pkg/tool/git/gitlab" "github.com/koderover/zadig/pkg/tool/log" @@ -55,7 +55,7 @@ func (c *Client) Comment(notify *models.Notification) error { } } - codeHostDetail, err := codehost.GetCodeHostInfoByID(notify.CodehostID) + codeHostDetail, err := systemconfig.New().GetCodeHost(notify.CodehostID) if err != nil { return errors.Wrapf(err, "codehost %d not found to comment", notify.CodehostID) } diff --git a/pkg/microservice/aslan/core/common/service/service.go b/pkg/microservice/aslan/core/common/service/service.go index 31d13b2882d4a4b203e79b1073f523bc8034f0b0..7804093148c816dd1bf605301a3d5b26cb790631 100644 --- a/pkg/microservice/aslan/core/common/service/service.go +++ b/pkg/microservice/aslan/core/common/service/service.go @@ -37,8 +37,7 @@ import ( templaterepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb/template" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/webhook" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/codehost" - "github.com/koderover/zadig/pkg/shared/poetry" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/log" "github.com/koderover/zadig/pkg/util/converter" @@ -131,7 +130,7 @@ func ListServiceTemplate(productName string, log *zap.SugaredLogger) (*ServiceTm return nil, e.ErrListTemplate.AddDesc(err.Error()) } - details, err := codehost.ListCodehostDetial() + details, err := systemconfig.New().ListCodeHosts() if err != nil { log.Errorf("无法从原有数据中恢复加载信息, listCodehostDetail failed err: %+v", err) return nil, e.ErrListTemplate.AddDesc(err.Error()) @@ -162,8 +161,8 @@ func ListServiceTemplate(productName string, log *zap.SugaredLogger) (*ServiceTm return nil, err } - detail, err := codehost.GetCodeHostInfo( - &codehost.Option{CodeHostType: poetry.GitHubProvider, Address: address, Namespace: owner}) + detail, err := systemconfig.GetCodeHostInfo( + &systemconfig.Option{CodeHostType: systemconfig.GitHubProvider, Address: address, Namespace: owner}) if err != nil { log.Errorf("get github codeHostInfo failed, err:%v", err) return nil, err @@ -318,7 +317,7 @@ func GetServiceTemplate(serviceName, serviceType, productName, excludeStatus str if resp.Source == setting.SourceFromGitlab && resp.RepoName == "" { if gitlabAddress, err := GetGitlabAddress(resp.SrcPath); err == nil { - if details, err := codehost.ListCodehostDetial(); err == nil { + if details, err := systemconfig.New().ListCodeHosts(); err == nil { for _, detail := range details { if strings.Contains(detail.Address, gitlabAddress) { resp.GerritCodeHostID = detail.ID @@ -355,8 +354,8 @@ func GetServiceTemplate(serviceName, serviceType, productName, excludeStatus str return nil, err } - detail, err := codehost.GetCodeHostInfo( - &codehost.Option{CodeHostType: poetry.GitHubProvider, Address: address, Namespace: owner, CodeHostID: resp.CodehostID}) + detail, err := systemconfig.GetCodeHostInfo( + &systemconfig.Option{CodeHostType: systemconfig.GitHubProvider, Address: address, Namespace: owner}) if err != nil { log.Errorf("get github codeHostInfo failed, err:%v", err) return nil, err diff --git a/pkg/microservice/aslan/core/common/service/template_product.go b/pkg/microservice/aslan/core/common/service/template_product.go index 0d40911fcaf2290aaf126697d108b02b431fad81..5ae1cd62f77935ce923398cf53f9f2b6bd8d95cc 100644 --- a/pkg/microservice/aslan/core/common/service/template_product.go +++ b/pkg/microservice/aslan/core/common/service/template_product.go @@ -18,21 +18,20 @@ package service import ( "fmt" - "strings" "sync" "go.uber.org/zap" "k8s.io/apimachinery/pkg/util/sets" + configbase "github.com/koderover/zadig/pkg/config" "github.com/koderover/zadig/pkg/microservice/aslan/config" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models/template" commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" templaterepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb/template" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/collie" - "github.com/koderover/zadig/pkg/microservice/aslan/internal/cache" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/poetry" + configclient "github.com/koderover/zadig/pkg/shared/config" e "github.com/koderover/zadig/pkg/tool/errors" ) @@ -53,15 +52,11 @@ func GetProductTemplate(productName string, log *zap.SugaredLogger) (*template.P } totalFreeStyles := make([]*collie.CiPipelineResource, 0) - features, err := GetFeatures(log) - if err != nil { - log.Errorf("GetProductTemplate GetFeatures err : %v", err) - } - - if strings.Contains(features, string(config.FreestyleType)) { + cl := configclient.New(configbase.ConfigServiceAddress()) + if enable, err := cl.CheckFeature(setting.ModernWorkflowType); err == nil && enable { // CI场景onboarding流程处于第二步时,需要返回ci工作流id,用于前端跳转 collieAPIAddress := config.CollieAPIAddress() - cl := collie.New(collieAPIAddress, config.PoetryAPIRootKey()) + cl := collie.New(collieAPIAddress) if resp.ProductFeature != nil && resp.ProductFeature.DevelopHabit == "yaml" && resp.OnboardingStatus == setting.OnboardingStatusSecond && collieAPIAddress != "" { ciPipelines, err := cl.ListCIPipelines(productName, log) if err != nil { @@ -109,7 +104,7 @@ func GetProductTemplate(productName string, log *zap.SugaredLogger) (*template.P return resp, fmt.Errorf("Testing.List err : %v", err) } - totalEnvs, err := commonrepo.NewProductColl().List(&commonrepo.ProductListOptions{Name: productName, IsSort: true}) + totalEnvs, err := commonrepo.NewProductColl().List(&commonrepo.ProductListOptions{Name: productName, IsSortByUpdateTime: true}) if err != nil { return resp, fmt.Errorf("Product.List err : %v", err) } @@ -124,9 +119,9 @@ func GetProductTemplate(productName string, log *zap.SugaredLogger) (*template.P return resp, fmt.Errorf("Pipeline.List err : %v", err) } - if strings.Contains(features, string(config.FreestyleType)) { + if enable, err := cl.CheckFeature(setting.ModernWorkflowType); err == nil && enable { collieAPIAddress := config.CollieAPIAddress() - cl := collie.New(collieAPIAddress, config.PoetryAPIRootKey()) + cl := collie.New(collieAPIAddress) totalFreeStyles, err = cl.ListCIPipelines(productName, log) if err != nil { log.Errorf("GetProductTemplate freestyle.List err : %v", err) @@ -174,26 +169,6 @@ func GetProductTemplate(productName string, log *zap.SugaredLogger) (*template.P return resp, nil } -func GetFeatures(log *zap.SugaredLogger) (string, error) { - featuresByteKey := []byte("features") - featuresByteValue, err := cache.Get(featuresByteKey) - if err != nil { - poetryCtl := poetry.New(config.PoetryAPIServer(), config.PoetryAPIRootKey()) - fs, err := poetryCtl.ListFeatures() - if err != nil { - return "", err - } - cacheValue := strings.Join(fs, ",") - // 一天过期 - if err = cache.Set(featuresByteKey, []byte(cacheValue), 86400); err != nil { - log.Errorf("getFeatures set cache err:%v", err) - } - return cacheValue, nil - } - - return string(featuresByteValue), nil -} - func FillProductTemplateVars(productTemplates []*template.Product, log *zap.SugaredLogger) error { var ( wg sync.WaitGroup diff --git a/pkg/shared/poetry/token.go b/pkg/microservice/aslan/core/common/service/template_store.go similarity index 60% rename from pkg/shared/poetry/token.go rename to pkg/microservice/aslan/core/common/service/template_store.go index bf31b540fcf2c5ddc14f8f6f973ce81b22b33add..b97b14a90e50aa4338d3c7b300f08c800b75fd67 100644 --- a/pkg/shared/poetry/token.go +++ b/pkg/microservice/aslan/core/common/service/template_store.go @@ -14,23 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -package poetry +package service -import "github.com/koderover/zadig/pkg/tool/httpclient" +import "github.com/koderover/zadig/pkg/microservice/aslan/core/templatestore/repository/mongodb" -type signature struct { - Token string `json:"token"` - Username string `json:"username"` -} - -func (c *Client) SignatureCheck(username, token string) error { - url := "/directory/token/check" - - s := &signature{Username: username, Token: token} - _, err := c.Post(url, httpclient.SetBody(s)) +func GetDockerfileTemplateContent(id string) (string, error) { + dockerfileTemplate, err := mongodb.NewDockerfileTemplateColl().GetById(id) if err != nil { - return err + return "", err } - - return nil + return dockerfileTemplate.Content, nil } diff --git a/pkg/microservice/aslan/core/common/service/utils.go b/pkg/microservice/aslan/core/common/service/utils.go index 5270cc00ea7994e1385199f9e439d6d13b924290..a89404921c414c94e46c0af7df9129cfe0211adf 100644 --- a/pkg/microservice/aslan/core/common/service/utils.go +++ b/pkg/microservice/aslan/core/common/service/utils.go @@ -28,9 +28,7 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/notify" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/poetry" e "github.com/koderover/zadig/pkg/tool/errors" - "github.com/koderover/zadig/pkg/types/permission" ) func SendMessage(sender, title, content, requestID string, log *zap.SugaredLogger) { @@ -54,11 +52,6 @@ func SendMessage(sender, title, content, requestID string, log *zap.SugaredLogge func SendFailedTaskMessage(username, productName, name, requestID string, workflowType config.PipelineType, err error, log *zap.SugaredLogger) { title := "创建工作流任务失败" - perm := permission.WorkflowUpdateUUID - if workflowType == config.TestType { - title = "创建测试任务失败" - perm = permission.TestManageUUID - } errStr := err.Error() _, messageMap := e.ErrorMessage(err) @@ -74,13 +67,6 @@ func SendFailedTaskMessage(username, productName, name, requestID string, workfl SendMessage(username, title, content, requestID, log) return } - - // 如果是timer创建的任务,通知需要发送给该项目下有编辑工作流权限的用户 - poetryClient := poetry.New(config.PoetryAPIServer(), config.PoetryAPIRootKey()) - users, _ := poetryClient.ListProductPermissionUsers(productName, perm, log) - for _, user := range users { - SendMessage(user, title, content, requestID, log) - } } func SendErrorMessage(sender, title, requestID string, err error, log *zap.SugaredLogger) { diff --git a/pkg/microservice/aslan/core/common/service/workflow.go b/pkg/microservice/aslan/core/common/service/workflow.go index 4b76211999e1aa223a2bb345c2166dbe31b0c8f1..023d7c98d25fd1d5baf209c59f5bce00cff6bc10 100644 --- a/pkg/microservice/aslan/core/common/service/workflow.go +++ b/pkg/microservice/aslan/core/common/service/workflow.go @@ -30,7 +30,7 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/gerrit" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/webhook" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/codehost" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" e "github.com/koderover/zadig/pkg/tool/errors" ) @@ -112,7 +112,7 @@ func DeleteWorkflow(workflowName, requestID string, isDeletingProductTmpl bool, log.Errorf("PipelineTaskV2.DeleteByPipelineName error: %v", err) } - if deliveryVersions, err := mongodb.NewDeliveryVersionColl().Find(&mongodb.DeliveryVersionArgs{OrgID: 1, WorkflowName: workflowName}); err == nil { + if deliveryVersions, err := mongodb.NewDeliveryVersionColl().Find(&mongodb.DeliveryVersionArgs{WorkflowName: workflowName}); err == nil { for _, deliveryVersion := range deliveryVersions { if err := mongodb.NewDeliveryVersionColl().Delete(deliveryVersion.ID.Hex()); err != nil { log.Errorf("DeleteWorkflow.DeliveryVersion.Delete error: %v", err) @@ -167,7 +167,7 @@ func ProcessWebhook(updatedHooks, currentHooks interface{}, name string, logger wg.Add(1) go func(wh hookItem) { defer wg.Done() - ch, err := codehost.GetCodeHostInfoByID(wh.codeHostID) + ch, err := systemconfig.New().GetCodeHost(wh.codeHostID) if err != nil { logger.Errorf("Failed to get codeHost by id %d, err: %s", wh.codeHostID, err) errs = multierror.Append(errs, err) @@ -201,7 +201,7 @@ func ProcessWebhook(updatedHooks, currentHooks interface{}, name string, logger wg.Add(1) go func(wh hookItem) { defer wg.Done() - ch, err := codehost.GetCodeHostInfoByID(wh.codeHostID) + ch, err := systemconfig.New().GetCodeHost(wh.codeHostID) if err != nil { logger.Errorf("Failed to get codeHost by id %d, err: %s", wh.codeHostID, err) errs = multierror.Append(errs, err) diff --git a/pkg/microservice/aslan/core/cron/handler/router.go b/pkg/microservice/aslan/core/cron/handler/router.go index 9d06de008e7fe9c66cb1428ef4c9303fd2ab40f3..29bb3f483538eacb681f1ffafe1918a7365229d9 100644 --- a/pkg/microservice/aslan/core/cron/handler/router.go +++ b/pkg/microservice/aslan/core/cron/handler/router.go @@ -18,14 +18,11 @@ package handler import ( "github.com/gin-gonic/gin" - - gin2 "github.com/koderover/zadig/pkg/middleware/gin" ) type Router struct{} func (*Router) Inject(router *gin.RouterGroup) { - router.Use(gin2.Auth()) // --------------------------------------------------------------------------------------- // 定时任务管理接口 diff --git a/pkg/microservice/aslan/core/delivery/handler/policy.yaml b/pkg/microservice/aslan/core/delivery/handler/policy.yaml new file mode 100644 index 0000000000000000000000000000000000000000..fe2625dba201a343011cf460951e12e8e705c82c --- /dev/null +++ b/pkg/microservice/aslan/core/delivery/handler/policy.yaml @@ -0,0 +1,18 @@ +resource: Delivery +alias: "交付中心" +description: "" +rules: + - action: get_delivery + alias: "查看版本" + description: "" + rules: + - method: GET + endpoint: "/api/aslan/delivery/releases" + - method: GET + endpoint: "/api/directory/dc/releases" + - action: delete_delivery + alias: "删除版本" + description: "" + rules: + - method: DELETE + endpoint: "/api/aslan/delivery/releases/?*" \ No newline at end of file diff --git a/pkg/microservice/aslan/core/delivery/handler/policy_definitions.go b/pkg/microservice/aslan/core/delivery/handler/policy_definitions.go new file mode 100644 index 0000000000000000000000000000000000000000..a434ba1ddc8fb0fcf719d776fc0e1211fe8a5240 --- /dev/null +++ b/pkg/microservice/aslan/core/delivery/handler/policy_definitions.go @@ -0,0 +1,24 @@ +package handler + +import ( + _ "embed" + + "sigs.k8s.io/yaml" + + "github.com/koderover/zadig/pkg/shared/client/policy" + "github.com/koderover/zadig/pkg/tool/log" +) + +//go:embed policy.yaml +var policyDefinitions []byte + +func (*Router) Policies() *policy.Policy { + res := &policy.Policy{} + err := yaml.Unmarshal(policyDefinitions, res) + if err != nil { + // should not have happened here + log.DPanic(err) + } + + return res +} diff --git a/pkg/microservice/aslan/core/delivery/handler/product.go b/pkg/microservice/aslan/core/delivery/handler/product.go index 59eb70b2ce7a7e9ce50c8befd487d54514561f9a..43bf3bfda49ca583cefa3d9fc10989e096b6bc05 100644 --- a/pkg/microservice/aslan/core/delivery/handler/product.go +++ b/pkg/microservice/aslan/core/delivery/handler/product.go @@ -17,8 +17,6 @@ limitations under the License. package handler import ( - "strconv" - "github.com/gin-gonic/gin" deliveryservice "github.com/koderover/zadig/pkg/microservice/aslan/core/delivery/service" @@ -26,19 +24,6 @@ import ( e "github.com/koderover/zadig/pkg/tool/errors" ) -func ListDeliveryProduct(c *gin.Context) { - ctx := internalhandler.NewContext(c) - defer func() { internalhandler.JSONResponse(c, ctx) }() - //params validate - orgIDStr := c.Query("orgId") - orgID, err := strconv.Atoi(orgIDStr) - if err != nil { - ctx.Err = e.ErrInvalidParam.AddDesc("orgId can't be empty!") - return - } - ctx.Resp, ctx.Err = deliveryservice.FindDeliveryProduct(orgID, ctx.Logger) -} - func GetProductByDeliveryInfo(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() @@ -49,5 +34,5 @@ func GetProductByDeliveryInfo(c *gin.Context) { return } - ctx.Resp, ctx.Err = deliveryservice.GetProductByDeliveryInfo(ctx.Username, releaseID, ctx.Logger) + ctx.Resp, ctx.Err = deliveryservice.GetProductByDeliveryInfo(ctx.UserName, releaseID, ctx.Logger) } diff --git a/pkg/microservice/aslan/core/delivery/handler/router.go b/pkg/microservice/aslan/core/delivery/handler/router.go index cb6b92e50c8457bf0a804fa99ed0509fa2a0db1a..889b7e7aadceb0559bce205afdfd098631f8730b 100644 --- a/pkg/microservice/aslan/core/delivery/handler/router.go +++ b/pkg/microservice/aslan/core/delivery/handler/router.go @@ -20,13 +20,11 @@ import ( "github.com/gin-gonic/gin" gin2 "github.com/koderover/zadig/pkg/middleware/gin" - "github.com/koderover/zadig/pkg/types/permission" ) type Router struct{} func (*Router) Inject(router *gin.RouterGroup) { - router.Use(gin2.Auth()) deliveryArtifact := router.Group("artifacts") { @@ -39,7 +37,6 @@ func (*Router) Inject(router *gin.RouterGroup) { deliveryProduct := router.Group("products") { - deliveryProduct.GET("", ListDeliveryProduct) deliveryProduct.GET("/:releaseId", GetProductByDeliveryInfo) } @@ -47,7 +44,7 @@ func (*Router) Inject(router *gin.RouterGroup) { { deliveryRelease.GET("/:id", GetDeliveryVersion) deliveryRelease.GET("", ListDeliveryVersion) - deliveryRelease.DELETE("/:id", GetProductNameByDelivery, gin2.IsHavePermission([]string{permission.ReleaseDeleteUUID}, permission.ContextKeyType), gin2.UpdateOperationLogStatus, DeleteDeliveryVersion) + deliveryRelease.DELETE("/:id", GetProductNameByDelivery, gin2.UpdateOperationLogStatus, DeleteDeliveryVersion) } deliveryPackage := router.Group("packages") diff --git a/pkg/microservice/aslan/core/delivery/handler/version.go b/pkg/microservice/aslan/core/delivery/handler/version.go index 28e26ff0edc79922bc970434c88dcf742baeb899..44ea5e99814a70fbf4977dd05dd5840a9fc412b0 100644 --- a/pkg/microservice/aslan/core/delivery/handler/version.go +++ b/pkg/microservice/aslan/core/delivery/handler/version.go @@ -96,16 +96,10 @@ type DeliverySecurityStatsInfo struct { func ListDeliveryVersion(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - //params validate - orgIDStr := c.Query("orgId") - orgID, err := strconv.Atoi(orgIDStr) - if err != nil { - ctx.Err = e.ErrInvalidParam.AddDesc("orgId can't be empty!") - return - } taskIDStr := c.Query("taskId") var taskID = 0 + var err error if taskIDStr != "" { taskID, err = strconv.Atoi(taskIDStr) if err != nil { @@ -143,8 +137,7 @@ func ListDeliveryVersion(c *gin.Context) { serviceName := c.Query("serviceName") version := new(commonrepo.DeliveryVersionArgs) - version.OrgID = orgID - version.ProductName = c.Query("productName") + version.ProductName = c.Query("projectName") version.WorkflowName = c.Query("workflowName") version.TaskID = taskID version.PerPage = perPage @@ -286,16 +279,9 @@ type DeliveryFileInfo struct { func ListPackagesVersion(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - //params validate - orgIDStr := c.Query("orgId") - orgID, err := strconv.Atoi(orgIDStr) - if err != nil { - ctx.Err = e.ErrInvalidParam.AddDesc("orgId can't be empty!") - return - } + version := &commonrepo.DeliveryVersionArgs{ - OrgID: orgID, - ProductName: c.Query("productName"), + ProductName: c.Query("projectName"), } deliveryVersions, err := deliveryservice.FindDeliveryVersion(version, ctx.Logger) if err != nil { @@ -343,7 +329,7 @@ func ListPackagesVersion(c *gin.Context) { func DeleteDeliveryVersion(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - internalhandler.InsertOperationLog(c, ctx.Username, c.GetString("productName"), "删除", "版本交付", fmt.Sprintf("主键ID:%s", c.Param("id")), "", ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, c.GetString("productName"), "删除", "版本交付", fmt.Sprintf("主键ID:%s", c.Param("id")), "", ctx.Logger) //params validate ID := c.Param("id") @@ -382,13 +368,6 @@ func ListDeliveryServiceNames(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - productName := c.Query("productName") - orgIDStr := c.Query("orgId") - orgID, err := strconv.Atoi(orgIDStr) - if err != nil { - ctx.Err = e.ErrInvalidParam.AddDesc("orgId can't be empty!") - return - } - - ctx.Resp, ctx.Err = deliveryservice.ListDeliveryServiceNames(orgID, productName, ctx.Logger) + productName := c.Query("projectName") + ctx.Resp, ctx.Err = deliveryservice.ListDeliveryServiceNames(productName, ctx.Logger) } diff --git a/pkg/microservice/aslan/core/delivery/service/product.go b/pkg/microservice/aslan/core/delivery/service/product.go index 9b2fdf8b7f595a815da10db2f46403dafa9de5e0..ece5c4adc91735b3c1c2050de5c8b30b7387f7ac 100644 --- a/pkg/microservice/aslan/core/delivery/service/product.go +++ b/pkg/microservice/aslan/core/delivery/service/product.go @@ -24,16 +24,6 @@ import ( e "github.com/koderover/zadig/pkg/tool/errors" ) -func FindDeliveryProduct(orgID int, log *zap.SugaredLogger) ([]string, error) { - productNames, err := commonrepo.NewDeliveryVersionColl().FindProducts(orgID) - if err != nil { - log.Errorf("find FindDeliveryProduct error: %v", err) - return []string{}, e.ErrFindDeliveryProducts - } - - return productNames, err -} - func GetProductByDeliveryInfo(username, releaseID string, log *zap.SugaredLogger) (*commonmodels.Product, error) { version := new(commonrepo.DeliveryVersionArgs) version.ID = releaseID diff --git a/pkg/microservice/aslan/core/delivery/service/version.go b/pkg/microservice/aslan/core/delivery/service/version.go index d9498b649189ab945fcbc316d40fc3be4f9a49c5..1c013f689596ebff19d325bee86642b25335ab40 100644 --- a/pkg/microservice/aslan/core/delivery/service/version.go +++ b/pkg/microservice/aslan/core/delivery/service/version.go @@ -52,11 +52,10 @@ func DeleteDeliveryVersion(args *commonrepo.DeliveryVersionArgs, log *zap.Sugare return nil } -func ListDeliveryServiceNames(orgID int, productName string, log *zap.SugaredLogger) ([]string, error) { +func ListDeliveryServiceNames(productName string, log *zap.SugaredLogger) ([]string, error) { serviceNames := sets.String{} version := new(commonrepo.DeliveryVersionArgs) - version.OrgID = orgID version.ProductName = productName deliveryVersions, err := FindDeliveryVersion(version, log) if err != nil { diff --git a/pkg/microservice/aslan/core/environment/handler/configmap.go b/pkg/microservice/aslan/core/environment/handler/configmap.go index 644e74b5c5d6fda9e743af2014c31bd2e8477f66..bb75e30fa706a8d70c5b22a0778560056c991140 100644 --- a/pkg/microservice/aslan/core/environment/handler/configmap.go +++ b/pkg/microservice/aslan/core/environment/handler/configmap.go @@ -36,7 +36,7 @@ func ListConfigMaps(c *gin.Context) { args := &service.ListConfigMapArgs{ EnvName: c.Query("envName"), - ProductName: c.Query("productName"), + ProductName: c.Query("projectName"), ServiceName: c.Query("serviceName"), } @@ -55,7 +55,7 @@ func UpdateConfigMap(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("UpdateConfigMap json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, args.ProductName, "更新", "集成环境-服务-configMap", fmt.Sprintf("环境名称:%s,服务名称:%s", args.EnvName, args.ServiceName), string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, args.ProductName, "更新", "集成环境-服务-configMap", fmt.Sprintf("环境名称:%s,服务名称:%s", args.EnvName, args.ServiceName), string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) if err := c.BindJSON(args); err != nil { @@ -74,7 +74,7 @@ func UpdateConfigMap(c *gin.Context) { // return //} - ctx.Err = service.UpdateConfigMap(args.EnvName, args, ctx.User.Name, ctx.User.ID, ctx.Logger) + ctx.Err = service.UpdateConfigMap(args.EnvName, args, ctx.UserName, ctx.UserID, ctx.Logger) } func RollBackConfigMap(c *gin.Context) { @@ -89,7 +89,7 @@ func RollBackConfigMap(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("RollBackConfigMap json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, args.ProductName, "回滚", "集成环境-服务-configMap", fmt.Sprintf("环境名称:%s,服务名称:%s", args.EnvName, args.ServiceName), string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, args.ProductName, "回滚", "集成环境-服务-configMap", fmt.Sprintf("环境名称:%s,服务名称:%s", args.EnvName, args.ServiceName), string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) if err := c.BindJSON(args); err != nil { @@ -102,5 +102,5 @@ func RollBackConfigMap(c *gin.Context) { return } - ctx.Err = service.RollBackConfigMap(args.EnvName, args, ctx.User.Name, ctx.User.ID, ctx.Logger) + ctx.Err = service.RollBackConfigMap(args.EnvName, args, ctx.UserName, ctx.UserID, ctx.Logger) } diff --git a/pkg/microservice/aslan/core/environment/handler/environment.go b/pkg/microservice/aslan/core/environment/handler/environment.go index 99b331c5be2c1015a15f9948ead8875d3b6ed32e..7e8edcbac56f2d010f00d19c5dff14d19707c69f 100644 --- a/pkg/microservice/aslan/core/environment/handler/environment.go +++ b/pkg/microservice/aslan/core/environment/handler/environment.go @@ -52,27 +52,15 @@ type NamespaceResource struct { Ingresses []resource.Ingress `json:"ingresses"` } -// ListProducts list all product information -// Args: projectName, which is formerly known as productName, is the primary key of the project in our system func ListProducts(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - - if c.Query("projectName") != "" { - isProduction := c.Query("production") - var envFilter string - switch isProduction { - case "true": - envFilter = setting.ProdENV - case "false": - envFilter = setting.TestENV - default: - envFilter = isProduction - } - ctx.Resp, ctx.Err = service.ListProductsV2(c.Query("projectName"), envFilter, ctx.User.Name, ctx.User.ID, ctx.User.IsSuperUser, ctx.Logger) + projectName := c.Query("projectName") + if projectName == "" { + ctx.Err = e.ErrInvalidParam return } - ctx.Resp, ctx.Err = service.ListProducts(c.Query("productName"), c.Query("envType"), ctx.User.Name, ctx.User.ID, ctx.User.IsSuperUser, ctx.Logger) + ctx.Resp, ctx.Err = service.ListProducts(c.Query("projectName"), ctx.UserName, ctx.Logger) } // GetProductStatus List product status @@ -102,7 +90,7 @@ func AutoUpdateProduct(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("AutoUpdateProduct json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, c.Param("productName"), "自动更新", "集成环境", strings.Join(args.EnvNames, ","), string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, c.Param("productName"), "自动更新", "集成环境", strings.Join(args.EnvNames, ","), string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) if err := c.BindJSON(args); err != nil { @@ -112,7 +100,7 @@ func AutoUpdateProduct(c *gin.Context) { } force, _ := strconv.ParseBool(c.Query("force")) - ctx.Resp, ctx.Err = service.AutoUpdateProduct(args.EnvNames, c.Param("productName"), ctx.User.ID, ctx.User.IsSuperUser, ctx.RequestID, force, ctx.Logger) + ctx.Resp, ctx.Err = service.AutoUpdateProduct(args.EnvNames, c.Param("productName"), ctx.RequestID, force, ctx.Logger) } func CreateHelmProduct(c *gin.Context) { @@ -148,10 +136,10 @@ func CreateHelmProduct(c *gin.Context) { envNameList = append(envNameList, arg.EnvName) } - internalhandler.InsertOperationLog(c, ctx.Username, productName, "新增", "集成环境", strings.Join(envNameList, "-"), string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, productName, "新增", "集成环境", strings.Join(envNameList, "-"), string(data), ctx.Logger) ctx.Err = service.CreateHelmProduct( - productName, ctx.Username, ctx.RequestID, createArgs, ctx.Logger, + productName, ctx.UserName, ctx.RequestID, createArgs, ctx.Logger, ) } @@ -167,7 +155,7 @@ func CreateProduct(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("CreateProduct json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, args.ProductName, "新增", "集成环境", args.EnvName, string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, args.ProductName, "新增", "集成环境", args.EnvName, string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) if err := c.BindJSON(args); err != nil { @@ -180,9 +168,9 @@ func CreateProduct(c *gin.Context) { return } - args.UpdateBy = ctx.Username + args.UpdateBy = ctx.UserName ctx.Err = service.CreateProduct( - ctx.Username, ctx.RequestID, args, ctx.Logger, + ctx.UserName, ctx.RequestID, args, ctx.Logger, ) } @@ -203,7 +191,7 @@ func UpdateProduct(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) return } - internalhandler.InsertOperationLog(c, ctx.Username, productName, "更新", "集成环境", envName, string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, productName, "更新", "集成环境", envName, string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) if err := c.BindJSON(args); err != nil { @@ -213,7 +201,7 @@ func UpdateProduct(c *gin.Context) { force, _ := strconv.ParseBool(c.Query("force")) // update product asynchronously - ctx.Err = service.UpdateProductV2(envName, productName, ctx.Username, ctx.RequestID, force, args.Vars, ctx.Logger) + ctx.Err = service.UpdateProductV2(envName, productName, ctx.UserName, ctx.RequestID, force, args.Vars, ctx.Logger) if ctx.Err != nil { ctx.Logger.Errorf("failed to update product %s %s: %v", envName, productName, ctx.Err) } @@ -227,7 +215,7 @@ func UpdateProductRecycleDay(c *gin.Context) { productName := c.Param("productName") recycleDayStr := c.Query("recycleDay") - internalhandler.InsertOperationLog(c, ctx.Username, productName, "更新", "集成环境-环境回收", envName, "", ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, productName, "更新", "集成环境-环境回收", envName, "", ctx.Logger) var ( recycleDay int @@ -295,9 +283,10 @@ func UpdateHelmProductRenderset(c *gin.Context) { if err = json.Unmarshal(data, arg); err != nil { log.Errorf("UpdateHelmProductVariable json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, c.Param("productName"), "更新", "更新环境变量", "", string(data), ctx.Logger) - ctx.Err = service.UpdateHelmProductRenderset(productName, envName, ctx.Username, ctx.RequestID, arg, ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, c.Param("productName"), "更新", "更新环境变量", "", string(data), ctx.Logger) + + ctx.Err = service.UpdateHelmProductRenderset(productName, envName, ctx.UserName, ctx.RequestID, arg, ctx.Logger) if ctx.Err != nil { ctx.Logger.Errorf("failed to update product Variable %s %s: %v", envName, productName, ctx.Err) } @@ -322,10 +311,10 @@ func UpdateMultiHelmEnv(c *gin.Context) { } args.ProductName = c.Param("productName") - internalhandler.InsertOperationLog(c, ctx.Username, args.ProductName, "更新", "集成环境", strings.Join(args.EnvNames, ","), string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, args.ProductName, "更新", "集成环境", strings.Join(args.EnvNames, ","), string(data), ctx.Logger) ctx.Resp, ctx.Err = service.UpdateMultipleHelmEnv( - ctx.Username, ctx.RequestID, ctx.User.ID, ctx.User.IsSuperUser, args, ctx.Logger, + ctx.RequestID, args, ctx.Logger, ) } @@ -336,7 +325,7 @@ func GetProduct(c *gin.Context) { envName := c.Query("envName") productName := c.Param("productName") - ctx.Resp, ctx.Err = service.GetProduct(ctx.Username, envName, productName, ctx.Logger) + ctx.Resp, ctx.Err = service.GetProduct(ctx.UserName, envName, productName, ctx.Logger) } func GetProductInfo(c *gin.Context) { @@ -346,7 +335,7 @@ func GetProductInfo(c *gin.Context) { envName := c.Query("envName") productName := c.Param("productName") - ctx.Resp, ctx.Err = service.GetProductInfo(ctx.Username, envName, productName, ctx.Logger) + ctx.Resp, ctx.Err = service.GetProductInfo(ctx.UserName, envName, productName, ctx.Logger) } func GetProductIngress(c *gin.Context) { @@ -354,7 +343,7 @@ func GetProductIngress(c *gin.Context) { defer func() { internalhandler.JSONResponse(c, ctx) }() productName := c.Param("productName") - ctx.Resp, ctx.Err = service.GetProductIngress(ctx.Username, productName, ctx.Logger) + ctx.Resp, ctx.Err = service.GetProductIngress(ctx.UserName, productName, ctx.Logger) } func ListRenderCharts(c *gin.Context) { @@ -387,7 +376,7 @@ func GetEstimatedRenderCharts(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - productName := c.Query("productName") + productName := c.Query("projectName") if productName == "" { ctx.Err = e.ErrInvalidParam.AddDesc("productName can't be empty!") return @@ -410,8 +399,8 @@ func DeleteProduct(c *gin.Context) { defer func() { internalhandler.JSONResponse(c, ctx) }() envName := c.Query("envName") - internalhandler.InsertOperationLog(c, ctx.Username, c.Param("productName"), "删除", "集成环境", envName, "", ctx.Logger) - ctx.Err = commonservice.DeleteProduct(ctx.Username, envName, c.Param("productName"), ctx.RequestID, ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, c.Param("productName"), "删除", "集成环境", envName, "", ctx.Logger) + ctx.Err = commonservice.DeleteProduct(ctx.UserName, envName, c.Param("productName"), ctx.RequestID, ctx.Logger) } func EnvShare(c *gin.Context) { @@ -427,7 +416,7 @@ func EnvShare(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("CreateProduct json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, productName, "更新", "集成环境-环境授权", args.EnvName, string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, productName, "更新", "集成环境-环境授权", args.EnvName, string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) if productName == "" { @@ -445,7 +434,7 @@ func EnvShare(c *gin.Context) { return } - ctx.Err = service.UpdateProductPublic(productName, args, ctx.Logger) + //ctx.Err = service.UpdateProductPublic(productName, args, ctx.Logger) } func ListGroups(c *gin.Context) { diff --git a/pkg/microservice/aslan/core/environment/handler/export.go b/pkg/microservice/aslan/core/environment/handler/export.go index 6f0a9917c552a901f0950c1700613a83a4d7900b..7419254fc49bb34bbea37652e65c7f56514d710f 100644 --- a/pkg/microservice/aslan/core/environment/handler/export.go +++ b/pkg/microservice/aslan/core/environment/handler/export.go @@ -29,7 +29,7 @@ func ExportYaml(c *gin.Context) { serviceName := c.Query("serviceName") envName := c.Query("envName") - productName := c.Query("productName") + productName := c.Query("projectName") ctx.Resp = service.ExportYaml(envName, productName, serviceName, ctx.Logger) } diff --git a/pkg/microservice/aslan/core/environment/handler/image.go b/pkg/microservice/aslan/core/environment/handler/image.go index 48bbcd6c6c5f3660e61c79f6b1c0d6fc36ce8dc0..45315376c1972ce37d088d36c91a363750038812 100644 --- a/pkg/microservice/aslan/core/environment/handler/image.go +++ b/pkg/microservice/aslan/core/environment/handler/image.go @@ -49,7 +49,7 @@ func UpdateStatefulSetContainerImage(c *gin.Context) { } internalhandler.InsertOperationLog( - c, ctx.Username, args.ProductName, + c, ctx.UserName, args.ProductName, "更新", "集成环境-服务镜像", fmt.Sprintf("环境名称:%s,服务名称:%s,StatefulSet:%s", args.EnvName, args.ServiceName, args.Name), string(data), ctx.Logger) @@ -80,7 +80,7 @@ func UpdateDeploymentContainerImage(c *gin.Context) { } internalhandler.InsertOperationLog( - c, ctx.Username, args.ProductName, + c, ctx.UserName, args.ProductName, "更新", "集成环境-服务镜像", fmt.Sprintf("环境名称:%s,服务名称:%s,Deployment:%s", args.EnvName, args.ServiceName, args.Name), string(data), ctx.Logger) diff --git a/pkg/microservice/aslan/core/environment/handler/kube.go b/pkg/microservice/aslan/core/environment/handler/kube.go index c35ea7bbfda5b88d4f52f83cca0a564c1471c86a..1e4c0c48172dd8957012062b7a3aada448b714ce 100644 --- a/pkg/microservice/aslan/core/environment/handler/kube.go +++ b/pkg/microservice/aslan/core/environment/handler/kube.go @@ -38,7 +38,7 @@ func ListKubeEvents(c *gin.Context) { defer func() { internalhandler.JSONResponse(c, ctx) }() envName := c.Query("envName") - productName := c.Query("productName") + productName := c.Query("projectName") name := c.Query("name") rtype := c.Query("type") @@ -81,9 +81,9 @@ func DeletePod(c *gin.Context) { podName := c.Param("podName") envName := c.Query("envName") - productName := c.Query("productName") + productName := c.Query("projectName") - internalhandler.InsertOperationLog(c, ctx.Username, c.Query("productName"), "重启", "集成环境-服务实例", fmt.Sprintf("环境名称:%s,pod名称:%s", c.Query("envName"), c.Param("podName")), "", ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, c.Query("projectName"), "重启", "集成环境-服务实例", fmt.Sprintf("环境名称:%s,pod名称:%s", c.Query("envName"), c.Param("podName")), "", ctx.Logger) ctx.Err = service.DeletePod(envName, productName, podName, ctx.Logger) } @@ -92,7 +92,7 @@ func ListPodEvents(c *gin.Context) { defer func() { internalhandler.JSONResponse(c, ctx) }() envName := c.Query("envName") - productName := c.Query("productName") + productName := c.Query("projectName") podName := c.Param("podName") ctx.Resp, ctx.Err = service.ListPodEvents(envName, productName, podName, ctx.Logger) diff --git a/pkg/microservice/aslan/core/environment/handler/policy.yaml b/pkg/microservice/aslan/core/environment/handler/policy.yaml new file mode 100644 index 0000000000000000000000000000000000000000..12e3cde0e8fc6e871b64de1731153e7a87a89073 --- /dev/null +++ b/pkg/microservice/aslan/core/environment/handler/policy.yaml @@ -0,0 +1,100 @@ +resource: Environment +alias: "集成环境" +description: "" +rules: + - action: get_environment + alias: "查看集成环境" + description: "" + rules: + - method: GET + endpoint: "/api/aslan/environment/environments" + - method: GET + endpoint: "/api/aslan/environment/environments/?*" + - method: GET + endpoint: "/api/aslan/environment/revision/products" + - method: GET + endpoint: "/api/aslan/environment/environments/?*/groups" + - method: GET + endpoint: "/api/aslan/environment/environments/?*/services/?*" + - method: GET + endpoint: "/api/aslan/environment/kube/workloads" + - method: GET + endpoint: "/api/aslan/service/workloads" + - method: GET + endpoint: "/api/aslan/environment/export/service" + - method: GET + endpoint: "/api/aslan/environment/configmaps" + - method: GET + endpoint: "/api/aslan/environment/kube/pods/?*/events" + - method: GET + endpoint: "/api/aslan/environment/kube/events" + - method: GET + endpoint: "/api/aslan/logs/sse/pods/?*/containers/?*" + - method: GET + endpoint: "/api/aslan/project/products/?*/services" + - action: create_environment + alias: "新建集成环境" + description: "" + rules: + - method: POST + endpoint: "/api/aslan/environment/environments" + - method: POST + endpoint: "/api/aslan/environment/environments/?*/helm" + - method: POST + endpoint: "/api/aslan/service/workloads" + - method: GET + endpoint: "/api/aslan/project/products/?*/services" + - method: GET + endpoint: "/api/aslan/delivery/releases" + - action: config_environment + alias: "配置集成环境" + description: "" + rules: + - method: PUT + endpoint: "/api/aslan/environment/environments/?*/autoUpdate" + - method: POST + endpoint: "/api/aslan/environment/environments/?*" + - method: PUT + endpoint: "/api/aslan/environment/environments/?*/envRecycle" + - method: PUT + endpoint: "/api/aslan/environment/environments/?*/renderchart" + - method: PUT + endpoint: "/api/aslan/environment/environments/?*/renderset" + - method: PUT + endpoint: "/api/aslan/environment/environments/?*/multiHelmEnv" + - method: PUT + endpoint: "/api/aslan/service/workloads" + - method: GET + endpoint: "/api/aslan/project/products/?*/services" + - action: manage_environment + alias: "管理服务实例" + description: "" + rules: + - method: POST + endpoint: "/api/aslan/environment/image/deployment" + - method: POST + endpoint: "/api/aslan/environment/image/statefulset" + - method: DELETE + endpoint: "/api/aslan/environment/kube/pods/?*" + - method: POST + endpoint: "/api/aslan/environment/environments/?*/services/?*/restart" + - method: PUT + endpoint: "/api/aslan/environment/configmaps" + - method: POST + endpoint: "/api/aslan/environment/configmaps" + - method: PUT + endpoint: "/api/aslan/environment/environments/?*/services/?*/?*" + - method: POST + endpoint: "/api/aslan/environment/environments/?*/services/?*/restartNew" + - method: POST + endpoint: "/api/aslan/environment/environments/?*/services/?*/scale/?*" + - method: POST + endpoint: "/api/aslan/environment/environments/?*/services/?*/scaleNew/?*" + - method: GET + endpoint: "/api/podexec/?*/?*/?*/?*/podExec" + - action: delete_environment + alias: "删除集成环境" + description: "" + rules: + - method: DELETE + endpoint: "/api/aslan/environment/environments/?*" \ No newline at end of file diff --git a/pkg/microservice/aslan/core/environment/handler/policy_definitions.go b/pkg/microservice/aslan/core/environment/handler/policy_definitions.go new file mode 100644 index 0000000000000000000000000000000000000000..a434ba1ddc8fb0fcf719d776fc0e1211fe8a5240 --- /dev/null +++ b/pkg/microservice/aslan/core/environment/handler/policy_definitions.go @@ -0,0 +1,24 @@ +package handler + +import ( + _ "embed" + + "sigs.k8s.io/yaml" + + "github.com/koderover/zadig/pkg/shared/client/policy" + "github.com/koderover/zadig/pkg/tool/log" +) + +//go:embed policy.yaml +var policyDefinitions []byte + +func (*Router) Policies() *policy.Policy { + res := &policy.Policy{} + err := yaml.Unmarshal(policyDefinitions, res) + if err != nil { + // should not have happened here + log.DPanic(err) + } + + return res +} diff --git a/pkg/microservice/aslan/core/environment/handler/renderset.go b/pkg/microservice/aslan/core/environment/handler/renderset.go index 534188c5b8178196569bb1924565acf59dd91e21..50aff5726bdf2d632fb1ba27180e63d2ad0bcf60 100644 --- a/pkg/microservice/aslan/core/environment/handler/renderset.go +++ b/pkg/microservice/aslan/core/environment/handler/renderset.go @@ -29,7 +29,7 @@ func GetServiceRenderCharts(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - if c.Query("productName") == "" { + if c.Query("projectName") == "" { ctx.Err = e.ErrInvalidParam.AddDesc("productName can not be null!") return } @@ -39,14 +39,14 @@ func GetServiceRenderCharts(c *gin.Context) { return } - ctx.Resp, ctx.Err = service.GetRenderCharts(c.Query("productName"), c.Query("envName"), c.Query("serviceName"), ctx.Logger) + ctx.Resp, ctx.Err = service.GetRenderCharts(c.Query("projectName"), c.Query("envName"), c.Query("serviceName"), ctx.Logger) } func GetProductDefaultValues(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - if c.Query("productName") == "" { + if c.Query("projectName") == "" { ctx.Err = e.ErrInvalidParam.AddDesc("productName can not be null!") return } @@ -56,7 +56,7 @@ func GetProductDefaultValues(c *gin.Context) { return } - ctx.Resp, ctx.Err = service.GetDefaultValues(c.Query("productName"), c.Query("envName"), ctx.Logger) + ctx.Resp, ctx.Err = service.GetDefaultValues(c.Query("projectName"), c.Query("envName"), ctx.Logger) } func GetYamlContent(c *gin.Context) { diff --git a/pkg/microservice/aslan/core/environment/handler/revision.go b/pkg/microservice/aslan/core/environment/handler/revision.go index 77ed70d34aa6ab5e1212bb4ec7b74ae8324c34bf..fa35d689823b5095c62f873de6201c98b9e5f64e 100644 --- a/pkg/microservice/aslan/core/environment/handler/revision.go +++ b/pkg/microservice/aslan/core/environment/handler/revision.go @@ -32,5 +32,5 @@ func ListProductsRevision(c *gin.Context) { ctx.Resp, ctx.Err = service.ListProductsRevisionByFacility(c.Query("basicFacility"), ctx.Logger) return } - ctx.Resp, ctx.Err = service.ListProductsRevision(c.Query("productName"), c.Query("envName"), ctx.User.ID, ctx.User.IsSuperUser, ctx.Logger) + ctx.Resp, ctx.Err = service.ListProductsRevision(c.Query("projectName"), c.Query("envName"), ctx.Logger) } diff --git a/pkg/microservice/aslan/core/environment/handler/router.go b/pkg/microservice/aslan/core/environment/handler/router.go index 770b2f4ee9e8562c3664189d0f4d282bfde8a607..bc13c84cad8543d210ad585cc0ed432cf8149433 100644 --- a/pkg/microservice/aslan/core/environment/handler/router.go +++ b/pkg/microservice/aslan/core/environment/handler/router.go @@ -20,22 +20,19 @@ import ( "github.com/gin-gonic/gin" gin2 "github.com/koderover/zadig/pkg/middleware/gin" - "github.com/koderover/zadig/pkg/types/permission" ) type Router struct{} func (*Router) Inject(router *gin.RouterGroup) { - router.Use(gin2.Auth()) - // --------------------------------------------------------------------------------------- // Kube配置管理接口 ConfigMap // --------------------------------------------------------------------------------------- configmaps := router.Group("configmaps") { configmaps.GET("", ListConfigMaps) - configmaps.PUT("", gin2.StoreProductName, gin2.IsHavePermission([]string{permission.TestEnvManageUUID, permission.ProdEnvManageUUID}, permission.ContextKeyType), gin2.UpdateOperationLogStatus, UpdateConfigMap) - configmaps.POST("", gin2.StoreProductName, gin2.IsHavePermission([]string{permission.TestEnvManageUUID, permission.ProdEnvManageUUID}, permission.ContextKeyType), gin2.UpdateOperationLogStatus, RollBackConfigMap) + configmaps.PUT("", gin2.UpdateOperationLogStatus, UpdateConfigMap) + configmaps.POST("", gin2.UpdateOperationLogStatus, RollBackConfigMap) } // --------------------------------------------------------------------------------------- @@ -60,7 +57,7 @@ func (*Router) Inject(router *gin.RouterGroup) { // --------------------------------------------------------------------------------------- export := router.Group("export") { - export.GET("/service", gin2.IsHavePermission([]string{permission.TestEnvManageUUID, permission.ProdEnvManageUUID}, permission.QueryType), ExportYaml) + export.GET("/service", ExportYaml) // export.GET("/pipelines/:name", ExportBuildYaml) } @@ -69,8 +66,8 @@ func (*Router) Inject(router *gin.RouterGroup) { // --------------------------------------------------------------------------------------- image := router.Group("image") { - image.POST("/deployment", gin2.StoreProductName, gin2.IsHavePermission([]string{permission.TestEnvManageUUID, permission.ProdEnvManageUUID, permission.TestUpdateEnvUUID}, permission.ContextKeyType), gin2.UpdateOperationLogStatus, UpdateDeploymentContainerImage) - image.POST("/statefulset", gin2.StoreProductName, gin2.IsHavePermission([]string{permission.TestEnvManageUUID, permission.ProdEnvManageUUID, permission.TestUpdateEnvUUID}, permission.ContextKeyType), gin2.UpdateOperationLogStatus, UpdateStatefulSetContainerImage) + image.POST("/deployment", gin2.UpdateOperationLogStatus, UpdateDeploymentContainerImage) + image.POST("/statefulset", gin2.UpdateOperationLogStatus, UpdateStatefulSetContainerImage) } // 查询环境创建时的服务和变量信息 @@ -86,7 +83,7 @@ func (*Router) Inject(router *gin.RouterGroup) { kube.GET("/events", ListKubeEvents) kube.POST("/pods", ListServicePods) - kube.DELETE("/pods/:podName", gin2.IsHavePermission([]string{permission.TestEnvManageUUID, permission.ProdEnvManageUUID, permission.TestUpdateEnvUUID}, permission.QueryType), gin2.UpdateOperationLogStatus, DeletePod) + kube.DELETE("/pods/:podName", gin2.UpdateOperationLogStatus, DeletePod) kube.GET("/pods/:podName/events", ListPodEvents) kube.GET("/workloads", ListWorkloads) } @@ -98,38 +95,38 @@ func (*Router) Inject(router *gin.RouterGroup) { { environments.GET("", ListProducts) environments.GET("/:productName/status", GetProductStatus) - environments.POST("/:productName/auto", gin2.IsHavePermission([]string{permission.TestEnvCreateUUID}, permission.ParamType), AutoCreateProduct) + environments.POST("/:productName/auto", AutoCreateProduct) - environments.PUT("/:productName/autoUpdate", gin2.IsHavePermission([]string{permission.TestEnvManageUUID, permission.ProdEnvManageUUID}, permission.ParamType), gin2.UpdateOperationLogStatus, AutoUpdateProduct) - environments.POST("", gin2.StoreProductName, gin2.IsHavePermission([]string{permission.TestEnvCreateUUID, permission.ProdEnvCreateUUID}, permission.ContextKeyType), gin2.UpdateOperationLogStatus, CreateProduct) + environments.PUT("/:productName/autoUpdate", gin2.UpdateOperationLogStatus, AutoUpdateProduct) + environments.POST("", gin2.UpdateOperationLogStatus, CreateProduct) environments.POST("/:productName/helm", gin2.UpdateOperationLogStatus, CreateHelmProduct) environments.PUT("/:productName/multiHelmEnv", gin2.UpdateOperationLogStatus, UpdateMultiHelmEnv) - environments.POST("/:productName", gin2.IsHavePermission([]string{permission.TestEnvManageUUID, permission.ProdEnvManageUUID}, permission.ParamType), gin2.UpdateOperationLogStatus, UpdateProduct) - environments.PUT("/:productName/envRecycle", gin2.IsHavePermission([]string{permission.TestEnvManageUUID}, permission.ParamType), gin2.UpdateOperationLogStatus, UpdateProductRecycleDay) + environments.POST("/:productName", gin2.UpdateOperationLogStatus, UpdateProduct) + environments.PUT("/:productName/envRecycle", gin2.UpdateOperationLogStatus, UpdateProductRecycleDay) environments.POST("/:productName/estimated-values", EstimatedValues) environments.PUT("/:productName/renderset", gin2.UpdateOperationLogStatus, UpdateHelmProductRenderset) environments.GET("/:productName/helmChartVersions", GetHelmChartVersions) - environments.PUT("/:productName", gin2.IsHavePermission([]string{permission.TestEnvShareUUID}, permission.ParamType), gin2.UpdateOperationLogStatus, EnvShare) + //environments.PUT("/:productName", gin2.UpdateOperationLogStatus, EnvShare) environments.GET("/:productName", GetProduct) environments.GET("/:productName/productInfo", GetProductInfo) environments.GET("/:productName/ingressInfo", GetProductIngress) environments.GET("/:productName/helmRenderCharts", ListRenderCharts) - environments.DELETE("/:productName", gin2.IsHavePermission([]string{permission.TestEnvDeleteUUID, permission.ProdEnvDeleteUUID}, permission.ParamType), gin2.UpdateOperationLogStatus, DeleteProduct) + environments.DELETE("/:productName", gin2.UpdateOperationLogStatus, DeleteProduct) environments.GET("/:productName/groups", ListGroups) environments.GET("/:productName/workloads", ListWorkloadsInEnv) environments.GET("/:productName/services/:serviceName", GetService) - environments.PUT("/:productName/services/:serviceName/:serviceType", gin2.IsHavePermission([]string{permission.TestEnvManageUUID, permission.ProdEnvManageUUID}, permission.ParamType), gin2.UpdateOperationLogStatus, UpdateService) - environments.POST("/:productName/services/:serviceName/restart", gin2.IsHavePermission([]string{permission.TestEnvManageUUID, permission.ProdEnvManageUUID}, permission.ParamType), gin2.UpdateOperationLogStatus, RestartService) - environments.POST("/:productName/services/:serviceName/restartNew", gin2.IsHavePermission([]string{permission.TestEnvManageUUID, permission.ProdEnvManageUUID, permission.TestUpdateEnvUUID}, permission.ParamType), gin2.UpdateOperationLogStatus, RestartNewService) - environments.POST("/:productName/services/:serviceName/scale/:number", gin2.IsHavePermission([]string{permission.TestEnvManageUUID, permission.ProdEnvManageUUID}, permission.ParamType), gin2.UpdateOperationLogStatus, ScaleService) - environments.POST("/:productName/services/:serviceName/scaleNew/:number", gin2.IsHavePermission([]string{permission.TestEnvManageUUID, permission.ProdEnvManageUUID}, permission.ParamType), gin2.UpdateOperationLogStatus, ScaleNewService) + environments.PUT("/:productName/services/:serviceName/:serviceType", gin2.UpdateOperationLogStatus, UpdateService) + environments.POST("/:productName/services/:serviceName/restart", gin2.UpdateOperationLogStatus, RestartService) + environments.POST("/:productName/services/:serviceName/restartNew", gin2.UpdateOperationLogStatus, RestartNewService) + environments.POST("/:productName/services/:serviceName/scale/:number", gin2.UpdateOperationLogStatus, ScaleService) + environments.POST("/:productName/services/:serviceName/scaleNew/:number", gin2.UpdateOperationLogStatus, ScaleNewService) environments.GET("/:productName/services/:serviceName/containers/:container/namespaces/:namespace", GetServiceContainer) environments.GET("/estimated-renderchart", GetEstimatedRenderCharts) diff --git a/pkg/microservice/aslan/core/environment/handler/service.go b/pkg/microservice/aslan/core/environment/handler/service.go index 6c5cffd871897aa10868c4387a22f18a0c78a11d..3405c7c05702add9b0d88b42e323faca81a44915 100644 --- a/pkg/microservice/aslan/core/environment/handler/service.go +++ b/pkg/microservice/aslan/core/environment/handler/service.go @@ -49,14 +49,14 @@ func RestartService(c *gin.Context) { ServiceName: c.Param("serviceName"), } - internalhandler.InsertOperationLog(c, ctx.Username, c.Param("productName"), "重启", "集成环境-服务", fmt.Sprintf("环境名称:%s,服务名称:%s", c.Query("envName"), c.Param("serviceName")), "", ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, c.Param("productName"), "重启", "集成环境-服务", fmt.Sprintf("环境名称:%s,服务名称:%s", c.Query("envName"), c.Param("serviceName")), "", ctx.Logger) ctx.Err = service.RestartService(args.EnvName, args, ctx.Logger) } func UpdateService(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - internalhandler.InsertOperationLog(c, ctx.Username, c.Param("productName"), "更新", "集成环境-单服务", fmt.Sprintf("环境名称:%s,服务名称:%s", c.Query("envName"), c.Param("serviceName")), "", ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, c.Param("productName"), "更新", "集成环境-单服务", fmt.Sprintf("环境名称:%s,服务名称:%s", c.Query("envName"), c.Param("serviceName")), "", ctx.Logger) svcRev := new(service.SvcRevision) if err := c.BindJSON(svcRev); err != nil { @@ -70,7 +70,7 @@ func UpdateService(c *gin.Context) { ServiceName: c.Param("serviceName"), ServiceType: c.Param("serviceType"), ServiceRev: svcRev, - UpdateBy: ctx.Username, + UpdateBy: ctx.UserName, } ctx.Err = service.UpdateService(args, ctx.Logger) @@ -89,7 +89,7 @@ func RestartNewService(c *gin.Context) { } internalhandler.InsertOperationLog( - c, ctx.Username, + c, ctx.UserName, c.Param("productName"), "重启", "集成环境-服务", @@ -116,7 +116,7 @@ func ScaleNewService(c *gin.Context) { name := c.Query("name") internalhandler.InsertOperationLog( - c, ctx.Username, + c, ctx.UserName, c.Param("productName"), "伸缩", "集成环境-服务", @@ -142,7 +142,7 @@ func ScaleNewService(c *gin.Context) { func ScaleService(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - internalhandler.InsertOperationLog(c, ctx.Username, c.Param("productName"), "伸缩", "集成环境-服务", fmt.Sprintf("环境名称:%s,服务名称:%s", c.Query("envName"), c.Param("serviceName")), "", ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, c.Param("productName"), "伸缩", "集成环境-服务", fmt.Sprintf("环境名称:%s,服务名称:%s", c.Query("envName"), c.Param("serviceName")), "", ctx.Logger) number, err := strconv.Atoi(c.Param("number")) if err != nil { diff --git a/pkg/microservice/aslan/core/environment/service/configmap.go b/pkg/microservice/aslan/core/environment/service/configmap.go index 045d23381c90d0b1cedd7dca2223279ad446b8af..bbb634c570cb998ecd42a6c60dc3b708e5c956cf 100644 --- a/pkg/microservice/aslan/core/environment/service/configmap.go +++ b/pkg/microservice/aslan/core/environment/service/configmap.go @@ -19,7 +19,6 @@ package service import ( "fmt" "sort" - "strconv" "strings" "time" @@ -146,7 +145,7 @@ func ListConfigMaps(args *ListConfigMapArgs, log *zap.SugaredLogger) ([]*configM return res, nil } -func UpdateConfigMap(envName string, args *UpdateConfigMapArgs, userName string, userID int, log *zap.SugaredLogger) error { +func UpdateConfigMap(envName string, args *UpdateConfigMapArgs, userName, userID string, log *zap.SugaredLogger) error { product, err := commonrepo.NewProductColl().Find(&commonrepo.ProductFindOptions{ Name: args.ProductName, EnvName: args.EnvName, @@ -191,7 +190,7 @@ func UpdateConfigMap(envName string, args *UpdateConfigMapArgs, userName string, cfg.Data = args.Data // 记录修改configmap的用户 cfg.Labels[setting.UpdateBy] = kube.MakeSafeLabelValue(userName) - cfg.Labels[setting.UpdateByID] = fmt.Sprintf("%d", userID) + cfg.Labels[setting.UpdateByID] = userID cfg.Labels[setting.UpdateTime] = time.Now().Format("20060102150405") cfg.Labels[setting.DirtyLabel] = setting.LabelValueTrue @@ -200,7 +199,7 @@ func UpdateConfigMap(envName string, args *UpdateConfigMapArgs, userName string, as = make(map[string]string) } as[setting.ModifiedByAnnotation] = userName - as[setting.EditorIDAnnotation] = strconv.Itoa(userID) + as[setting.EditorIDAnnotation] = userID as[setting.LastUpdateTimeAnnotation] = util.FormatTime(time.Now()) cfg.SetAnnotations(as) @@ -223,7 +222,7 @@ func UpdateConfigMap(envName string, args *UpdateConfigMapArgs, userName string, return nil } -func RollBackConfigMap(envName string, args *RollBackConfigMapArgs, userName string, userID int, log *zap.SugaredLogger) error { +func RollBackConfigMap(envName string, args *RollBackConfigMapArgs, userName, userID string, log *zap.SugaredLogger) error { product, err := commonrepo.NewProductColl().Find(&commonrepo.ProductFindOptions{ Name: args.ProductName, EnvName: args.EnvName, @@ -260,7 +259,7 @@ func RollBackConfigMap(envName string, args *RollBackConfigMapArgs, userName str destinSrc.Data = srcCfg.Data destinSrc.Labels[setting.UpdateBy] = kube.MakeSafeLabelValue(userName) - destinSrc.Labels[setting.UpdateByID] = fmt.Sprintf("%d", userID) + destinSrc.Labels[setting.UpdateByID] = userID destinSrc.Labels[setting.UpdateTime] = time.Now().Format("20060102150405") // 回滚时显示回滚版本的时间 if updateTime, ok := srcCfg.Labels[setting.UpdateTime]; ok { diff --git a/pkg/microservice/aslan/core/environment/service/environment.go b/pkg/microservice/aslan/core/environment/service/environment.go index 08c33d7bec265c9facd947a1587b238c02dcc5cf..e8f7c584d596a3c5b1a91dcd4e722e66b9641e5c 100644 --- a/pkg/microservice/aslan/core/environment/service/environment.go +++ b/pkg/microservice/aslan/core/environment/service/environment.go @@ -22,7 +22,6 @@ import ( "fmt" "path/filepath" "regexp" - "sort" "strings" "sync" "time" @@ -56,14 +55,12 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/setting" "github.com/koderover/zadig/pkg/shared/kube/wrapper" - "github.com/koderover/zadig/pkg/shared/poetry" e "github.com/koderover/zadig/pkg/tool/errors" helmtool "github.com/koderover/zadig/pkg/tool/helmclient" "github.com/koderover/zadig/pkg/tool/kube/getter" "github.com/koderover/zadig/pkg/tool/kube/serializer" "github.com/koderover/zadig/pkg/tool/kube/updater" "github.com/koderover/zadig/pkg/tool/log" - "github.com/koderover/zadig/pkg/types/permission" "github.com/koderover/zadig/pkg/util" "github.com/koderover/zadig/pkg/util/converter" "github.com/koderover/zadig/pkg/util/fs" @@ -152,38 +149,13 @@ type RawYamlResp struct { type intervalExecutorHandler func(data *commonmodels.Service, log *zap.SugaredLogger) error -func UpdateProductPublic(productName string, args *ProductParams, log *zap.SugaredLogger) error { - err := commonrepo.NewProductColl().UpdateIsPublic(args.EnvName, productName, args.IsPublic) - if err != nil { - log.Errorf("UpdateProductPublic error: %v", err) - return fmt.Errorf("UpdateProductPublic error: %v", err) - } - - poetryCtl := poetry.New(config.PoetryAPIServer(), config.PoetryAPIRootKey()) - if !args.IsPublic { //把公开设置成不公开 - _, err := poetryCtl.AddEnvRolePermission(productName, args.EnvName, args.PermissionUUIDs, args.RoleID, log) - if err != nil { - log.Errorf("UpdateProductPublic AddEnvRole error: %v", err) - return fmt.Errorf("UpdateProductPublic AddEnvRole error: %v", err) - } - return nil - } - //把不公开设成公开 删除原来环境绑定的角色 - _, err = poetryCtl.DeleteEnvRolePermission(productName, args.EnvName, log) - if err != nil { - log.Errorf("UpdateProductPublic DeleteEnvRole error: %v", err) - return fmt.Errorf("UpdateProductPublic DeleteEnvRole error: %v", err) - } - - return nil -} - func GetProductStatus(productName string, log *zap.SugaredLogger) ([]*EnvStatus, error) { products, err := commonrepo.NewProductColl().List(&commonrepo.ProductListOptions{Name: productName}) if err != nil { log.Errorf("Collection.Product.List List product error: %v", err) return nil, e.ErrListProducts.AddDesc(err.Error()) } + envStatusSlice := make([]*EnvStatus, 0) for _, publicProduct := range products { if publicProduct.ProductName != productName { @@ -201,128 +173,11 @@ func GetProductStatus(productName string, log *zap.SugaredLogger) ([]*EnvStatus, return envStatusSlice, err } -func ListProducts(productNameParam, envType string, userName string, userID int, superUser bool, log *zap.SugaredLogger) ([]*ProductResp, error) { - var ( - err error - testResp []*ProductResp - prodResp []*ProductResp - products = make([]*commonmodels.Product, 0) - productNameMap map[string][]int64 - productNamespaces = sets.NewString() - ) - resp := make([]*ProductResp, 0) - - poetryCtl := poetry.New(config.PoetryAPIServer(), config.PoetryAPIRootKey()) - - // 获取所有产品 - if superUser { - products, err = commonrepo.NewProductColl().List(&commonrepo.ProductListOptions{Name: productNameParam}) - if err != nil { - log.Errorf("[%s] Collections.Product.List error: %v", userName, err) - return resp, e.ErrListEnvs.AddDesc(err.Error()) - } - } else { - //项目下所有公开环境 - publicProducts, err := commonrepo.NewProductColl().List(&commonrepo.ProductListOptions{IsPublic: true}) - if err != nil { - log.Errorf("Collection.Product.List List product error: %v", err) - return resp, e.ErrListProducts.AddDesc(err.Error()) - } - for _, publicProduct := range publicProducts { - if productNameParam == "" { - products = append(products, publicProduct) - productNamespaces.Insert(publicProduct.Namespace) - } else if publicProduct.ProductName == productNameParam { - products = append(products, publicProduct) - productNamespaces.Insert(publicProduct.Namespace) - } - } - - productNameMap, err = poetryCtl.GetUserProject(userID, log) - if err != nil { - log.Errorf("Collection.Product.List GetUserProject error: %v", err) - return resp, e.ErrListProducts.AddDesc(err.Error()) - } - for productName, roleIDs := range productNameMap { - //用户关联角色所关联的环境 - for _, roleID := range roleIDs { - if roleID == setting.RoleOwnerID { - tmpProducts, err := commonrepo.NewProductColl().List(&commonrepo.ProductListOptions{Name: productName}) - if err != nil { - log.Errorf("Collection.Product.List Find product error: %v", err) - return resp, e.ErrListProducts.AddDesc(err.Error()) - } - for _, product := range tmpProducts { - if productNameParam == "" { - if !productNamespaces.Has(product.Namespace) { - products = append(products, product) - } - } else if product.ProductName == productNameParam { - if !productNamespaces.Has(product.Namespace) { - products = append(products, product) - } - } - } - } else { - productMap := make(map[string]int) - // 先列出环境-用户授权 - userEnvPermissionList, err := poetryCtl.GetUserEnvPermission(userID, log) - if err != nil { - log.Errorf("failed to get user env permission, err: %v", err) - return resp, err - } - for _, userEnvPermission := range userEnvPermissionList { - product, err := commonrepo.NewProductColl().Find(&commonrepo.ProductFindOptions{Name: productName, EnvName: userEnvPermission.EnvName}) - if err != nil { - log.Errorf("Collection.Product.List Find product error: %v", err) - continue - } - if productNameParam == "" { - if !productNamespaces.Has(product.Namespace) && userEnvPermission.PermissionUUID == permission.TestEnvListUUID { - products = append(products, product) - productNamespaces = productNamespaces.Insert(product.Namespace) - productMap[product.EnvName] = 1 - } - } else if product.ProductName == productNameParam { - if !productNamespaces.Has(product.Namespace) && userEnvPermission.PermissionUUID == permission.TestEnvManageUUID { - products = append(products, product) - productNamespaces = productNamespaces.Insert(product.Namespace) - productMap[product.EnvName] = 1 - } - } - } - // 再获取环境-角色授权 - roleEnvPermissions, err := poetryCtl.ListEnvRolePermission(productName, "", roleID, log) - if err != nil { - log.Errorf("Collection.Product.List ListRoleEnvs error: %v", err) - return resp, e.ErrListProducts.AddDesc(err.Error()) - } - for _, roleEnvPermission := range roleEnvPermissions { - product, err := commonrepo.NewProductColl().Find(&commonrepo.ProductFindOptions{Name: productName, EnvName: roleEnvPermission.EnvName}) - if err != nil { - log.Errorf("Collection.Product.List Find product error: %v", err) - continue - } - if productNameParam == "" { - if !productNamespaces.Has(product.Namespace) && roleEnvPermission.PermissionUUID == permission.TestEnvListUUID { - products = append(products, product) - productNamespaces.Insert(product.Namespace) - } - } else if product.ProductName == productNameParam { - if !productNamespaces.Has(product.Namespace) && roleEnvPermission.PermissionUUID == permission.TestEnvManageUUID { - products = append(products, product) - productNamespaces.Insert(product.Namespace) - } - } - } - } - } - } - } - - err = FillProductVars(products, log) +func ListProducts(productNameParam string, userName string, log *zap.SugaredLogger) (resp []*ProductResp, err error) { + products, err := commonrepo.NewProductColl().List(&commonrepo.ProductListOptions{Name: productNameParam, IsSortByProductName: true}) if err != nil { - return resp, err + log.Errorf("[%s] Collections.Product.List error: %v", userName, err) + return resp, e.ErrListEnvs.AddDesc(err.Error()) } for _, prod := range products { @@ -340,212 +195,19 @@ func ListProducts(productNameParam, envType string, userName string, userID int, Render: prod.Render, Source: prod.Source, } - - if prod.ClusterID != "" { - cluster, _ := commonrepo.NewK8SClusterColl().Get(prod.ClusterID) + if product.ClusterID != "" { + cluster, _ := commonrepo.NewK8SClusterColl().Get(product.ClusterID) if cluster != nil && cluster.Production { product.IsProd = true - operatorPerm := poetryCtl.HasOperatePermission(prod.ProductName, permission.ProdEnvManageUUID, userID, superUser, log) - viewPerm := poetryCtl.HasOperatePermission(prod.ProductName, permission.ProdEnvListUUID, userID, superUser, log) - if envType == "" && (operatorPerm || viewPerm) { - prodResp = append(prodResp, product) - } else if envType == setting.ProdENV { - prodResp = append(prodResp, product) - } - } else if cluster != nil && !cluster.Production { - product.IsProd = false - testResp = append(testResp, product) - } - } else { - product.IsProd = false - testResp = append(testResp, product) - } - } - switch envType { - case setting.ProdENV: - resp = append(resp, prodResp...) - case setting.TestENV: - resp = append(resp, testResp...) - default: - resp = append(resp, prodResp...) - resp = append(resp, testResp...) - } - - sort.SliceStable(resp, func(i, j int) bool { return resp[i].ProductName < resp[j].ProductName }) - - return resp, nil -} - -type ListProductsRespV2 struct { - ClusterName string `json:"clusterName"` - Production bool `json:"production"` - Name string `json:"name"` - ProjectName string `json:"projectName"` - Source string `json:"source"` -} - -// Args: projectName, which is formerly known as productName, is the primary key of the project in our system -func ListProductsV2(projectName, envFilter string, userName string, userID int, superUser bool, log *zap.SugaredLogger) ([]*ListProductsRespV2, error) { - var ( - err error - testResp []*ListProductsRespV2 - prodResp []*ListProductsRespV2 - products = make([]*commonmodels.Product, 0) - productNameMap map[string][]int64 - productNamespaces = sets.NewString() - ) - ret := make([]*ListProductsRespV2, 0) - - poetryCtl := poetry.New(config.PoetryAPIServer(), config.PoetryAPIRootKey()) - - // 获取所有产品 - if superUser { - products, err = commonrepo.NewProductColl().List(&commonrepo.ProductListOptions{Name: projectName}) - if err != nil { - log.Errorf("[%s] Collections.Product.List error: %v", userName, err) - return ret, e.ErrListEnvs.AddDesc(err.Error()) - } - } else { - //项目下所有公开环境 - publicProducts, err := commonrepo.NewProductColl().List(&commonrepo.ProductListOptions{IsPublic: true}) - if err != nil { - log.Errorf("Collection.Product.List List product error: %v", err) - return ret, e.ErrListProducts.AddDesc(err.Error()) - } - for _, publicProduct := range publicProducts { - if projectName == "" { - products = append(products, publicProduct) - productNamespaces.Insert(publicProduct.Namespace) - } else if publicProduct.ProductName == projectName { - products = append(products, publicProduct) - productNamespaces.Insert(publicProduct.Namespace) } } - - productNameMap, err = poetryCtl.GetUserProject(userID, log) + err = FillProductVars(products, log) if err != nil { - log.Errorf("Collection.Product.List GetUserProject error: %v", err) - return ret, e.ErrListProducts.AddDesc(err.Error()) - } - for productName, roleIDs := range productNameMap { - //用户关联角色所关联的环境 - for _, roleID := range roleIDs { - if roleID == setting.RoleOwnerID { - tmpProducts, err := commonrepo.NewProductColl().List(&commonrepo.ProductListOptions{Name: productName}) - if err != nil { - log.Errorf("Collection.Product.List Find product error: %v", err) - return ret, e.ErrListProducts.AddDesc(err.Error()) - } - for _, product := range tmpProducts { - if projectName == "" { - if !productNamespaces.Has(product.Namespace) { - products = append(products, product) - } - } else if product.ProductName == projectName { - if !productNamespaces.Has(product.Namespace) { - products = append(products, product) - } - } - } - } else { - productMap := make(map[string]int) - // 先列出环境-用户授权 - userEnvPermissionList, err := poetryCtl.GetUserEnvPermission(userID, log) - if err != nil { - log.Errorf("failed to get user env permission, err: %v", err) - return ret, err - } - for _, userEnvPermission := range userEnvPermissionList { - product, err := commonrepo.NewProductColl().Find(&commonrepo.ProductFindOptions{Name: productName, EnvName: userEnvPermission.EnvName}) - if err != nil { - log.Errorf("Collection.Product.List Find product error: %v", err) - continue - } - if projectName == "" { - if !productNamespaces.Has(product.Namespace) && userEnvPermission.PermissionUUID == permission.TestEnvListUUID { - products = append(products, product) - productNamespaces = productNamespaces.Insert(product.Namespace) - productMap[product.EnvName] = 1 - } - } else if product.ProductName == projectName { - if !productNamespaces.Has(product.Namespace) && userEnvPermission.PermissionUUID == permission.TestEnvManageUUID { - products = append(products, product) - productNamespaces = productNamespaces.Insert(product.Namespace) - productMap[product.EnvName] = 1 - } - } - } - // 再获取环境-角色授权 - roleEnvPermissions, err := poetryCtl.ListEnvRolePermission(productName, "", roleID, log) - if err != nil { - log.Errorf("Collection.Product.List ListRoleEnvs error: %v", err) - return ret, e.ErrListProducts.AddDesc(err.Error()) - } - for _, roleEnvPermission := range roleEnvPermissions { - product, err := commonrepo.NewProductColl().Find(&commonrepo.ProductFindOptions{Name: productName, EnvName: roleEnvPermission.EnvName}) - if err != nil { - log.Errorf("Collection.Product.List Find product error: %v", err) - continue - } - if projectName == "" { - if !productNamespaces.Has(product.Namespace) && roleEnvPermission.PermissionUUID == permission.TestEnvListUUID { - products = append(products, product) - productNamespaces.Insert(product.Namespace) - } - } else if product.ProductName == projectName { - if !productNamespaces.Has(product.Namespace) && roleEnvPermission.PermissionUUID == permission.TestEnvManageUUID { - products = append(products, product) - productNamespaces.Insert(product.Namespace) - } - } - } - } - } - } - } - - for _, product := range products { - item := &ListProductsRespV2{ - Name: product.EnvName, - ProjectName: product.ProductName, - Source: product.Source, - } - if product.ClusterID != "" { - cluster, _ := commonrepo.NewK8SClusterColl().Get(product.ClusterID) - if cluster != nil && cluster.Production { - item.Production = true - item.ClusterName = cluster.Name - operatorPerm := poetryCtl.HasOperatePermission(product.ProductName, permission.ProdEnvManageUUID, userID, superUser, log) - viewPerm := poetryCtl.HasOperatePermission(product.ProductName, permission.ProdEnvListUUID, userID, superUser, log) - if envFilter == "" && (operatorPerm || viewPerm) { - prodResp = append(prodResp, item) - } else if envFilter == setting.ProdENV { - prodResp = append(prodResp, item) - } - } else if cluster != nil && !cluster.Production { - item.Production = false - item.ClusterName = cluster.Name - testResp = append(testResp, item) - } - } else { - item.Production = false - testResp = append(testResp, item) + return resp, err } + resp = append(resp, product) } - - switch envFilter { - case setting.ProdENV: - ret = append(ret, prodResp...) - case setting.TestENV: - ret = append(ret, testResp...) - default: - ret = append(ret, prodResp...) - ret = append(ret, testResp...) - } - - sort.SliceStable(ret, func(i, j int) bool { return ret[i].ProjectName < ret[j].ProjectName }) - - return ret, nil + return resp, nil } func FillProductVars(products []*commonmodels.Product, log *zap.SugaredLogger) error { @@ -599,7 +261,7 @@ func AutoCreateProduct(productName, envType, requestID string, log *zap.SugaredL var mutexAutoUpdate sync.RWMutex -func AutoUpdateProduct(envNames []string, productName string, userID int, superUser bool, requestID string, force bool, log *zap.SugaredLogger) ([]*EnvStatus, error) { +func AutoUpdateProduct(envNames []string, productName, requestID string, force bool, log *zap.SugaredLogger) ([]*EnvStatus, error) { mutexAutoUpdate.Lock() defer func() { mutexAutoUpdate.Unlock() @@ -636,7 +298,7 @@ func AutoUpdateProduct(envNames []string, productName string, userID int, superU } } - productsRevison, err := ListProductsRevision(productName, "", userID, superUser, log) + productsRevison, err := ListProductsRevision(productName, "", log) if err != nil { log.Errorf("AutoUpdateProduct ListProductsRevision err:%v", err) return envStatuses, err @@ -1413,7 +1075,7 @@ func updateHelmProductVariable(productResp *commonmodels.Product, renderset *com var mutexUpdateMultiHelm sync.RWMutex -func UpdateMultipleHelmEnv(userName, requestID string, userID int, superUser bool, args *UpdateMultiHelmProductArg, log *zap.SugaredLogger) ([]*EnvStatus, error) { +func UpdateMultipleHelmEnv(requestID string, args *UpdateMultiHelmProductArg, log *zap.SugaredLogger) ([]*EnvStatus, error) { mutexUpdateMultiHelm.Lock() defer func() { mutexUpdateMultiHelm.Unlock() @@ -1422,7 +1084,7 @@ func UpdateMultipleHelmEnv(userName, requestID string, userID int, superUser boo envNames, productName := args.EnvNames, args.ProductName envStatuses := make([]*EnvStatus, 0) - productsRevision, err := ListProductsRevision(productName, "", userID, superUser, log) + productsRevision, err := ListProductsRevision(productName, "", log) if err != nil { log.Errorf("UpdateMultiHelmProduct ListProductsRevision err:%v", err) return envStatuses, err @@ -1777,149 +1439,6 @@ func getProjectType(productName string) string { return projectType } -// createGroup create or update services in service group -//func createGroup(envName, productName, username string, group []*commonmodels.ProductService, renderSet *commonmodels.RenderSet, kubeClient client.Client, log *zap.SugaredLogger) error { -// log.Infof("[Namespace:%s][Product:%s] createGroup", envName, productName) -// updatableServiceNameList := make([]string, 0) -// -// // 异步创建无依赖的服务 -// errList := &multierror.Error{ -// ErrorFormat: func(es []error) string { -// points := make([]string, len(es)) -// for i, err := range es { -// points[i] = fmt.Sprintf("%v", err) -// } -// -// return strings.Join(points, "\n") -// }, -// } -// -// opt := &commonrepo.ProductFindOptions{Name: productName, EnvName: envName} -// prod, err := commonrepo.NewProductColl().Find(opt) -// if err != nil { -// errList = multierror.Append(errList, err) -// } -// -// var wg sync.WaitGroup -// var lock sync.Mutex -// var resources []*unstructured.Unstructured -// -// for i := range group { -// if group[i].Type == setting.K8SDeployType { -// // 只有在service有Pod的时候,才需要等待pod running或者等待pod succeed -// // 比如在group中,如果service下仅有configmap/service/ingress这些yaml的时候,不需要waitServicesRunning -// wg.Add(1) -// updatableServiceNameList = append(updatableServiceNameList, group[i].ServiceName) -// go func(svc *commonmodels.ProductService) { -// defer wg.Done() -// items, err := upsertService(false, prod, svc, nil, renderSet, kubeClient, log) -// if err != nil { -// lock.Lock() -// switch e := err.(type) { -// case *multierror.Error: -// errList = multierror.Append(errList, e.Errors...) -// default: -// errList = multierror.Append(errList, e) -// } -// lock.Unlock() -// } -// -// // concurrent array append -// lock.Lock() -// resources = append(resources, items...) -// lock.Unlock() -// }(group[i]) -// } else if group[i].Type == setting.PMDeployType { -// //更新非k8s服务 -// if len(group[i].EnvConfigs) > 0 { -// serviceTempl, err := commonservice.GetServiceTemplate(group[i].ServiceName, setting.PMDeployType, productName, setting.ProductStatusDeleting, group[i].Revision, log) -// if err != nil { -// errList = multierror.Append(errList, err) -// } -// if serviceTempl != nil { -// oldEnvConfigs := serviceTempl.EnvConfigs -// for _, currentEnvConfig := range group[i].EnvConfigs { -// envConfig := &commonmodels.EnvConfig{ -// EnvName: currentEnvConfig.EnvName, -// HostIDs: currentEnvConfig.HostIDs, -// } -// oldEnvConfigs = append(oldEnvConfigs, envConfig) -// } -// -// args := &commonservice.ServiceTmplBuildObject{ -// ServiceTmplObject: &commonservice.ServiceTmplObject{ -// ProductName: serviceTempl.ProductName, -// ServiceName: serviceTempl.ServiceName, -// Visibility: serviceTempl.Visibility, -// Revision: serviceTempl.Revision, -// Type: serviceTempl.Type, -// Username: username, -// HealthChecks: serviceTempl.HealthChecks, -// EnvConfigs: oldEnvConfigs, -// EnvStatuses: []*commonmodels.EnvStatus{}, -// From: "createEnv", -// }, -// Build: &commonmodels.Build{Name: serviceTempl.BuildName}, -// } -// -// if err := commonservice.UpdatePmServiceTemplate(username, args, log); err != nil { -// errList = multierror.Append(errList, err) -// } -// } -// } -// var latestRevision int64 = group[i].Revision -// // 获取最新版本的服务 -// if latestServiceTempl, _ := commonservice.GetServiceTemplate(group[i].ServiceName, setting.PMDeployType, productName, setting.ProductStatusDeleting, 0, log); latestServiceTempl != nil { -// latestRevision = latestServiceTempl.Revision -// } -// // 更新环境 -// if latestRevision > group[i].Revision { -// // 更新产品服务 -// for _, serviceGroup := range prod.Services { -// for j, service := range serviceGroup { -// if service.ServiceName == group[i].ServiceName && service.Type == setting.PMDeployType { -// serviceGroup[j].Revision = latestRevision -// } -// } -// } -// if err := commonrepo.NewProductColl().Update(prod); err != nil { -// log.Errorf("[%s][%s] Product.Update error: %v", envName, productName, err) -// errList = multierror.Append(errList, err) -// } -// } -// if _, err = commonservice.CreateServiceTask(&commonmodels.ServiceTaskArgs{ -// ProductName: productName, -// ServiceName: group[i].ServiceName, -// Revision: latestRevision, -// EnvNames: []string{envName}, -// ServiceTaskCreator: username, -// }, log); err != nil { -// errList = multierror.Append(errList, err) -// } -// } -// } -// -// wg.Wait() -// -// // 如果创建依赖服务组有返回错误, 停止等待 -// if err := errList.ErrorOrNil(); err != nil { -// return err -// } -// -// if err := waitResourceRunning(kubeClient, prod.Namespace, resources, config.ServiceStartTimeout(), log); err != nil { -// log.Errorf( -// "service group %s/%+v doesn't start in %d seconds: %v", -// prod.Namespace, -// updatableServiceNameList, config.ServiceStartTimeout(), err) -// -// err = e.ErrUpdateEnv.AddErr( -// errors.Errorf(e.StartPodTimeout+"\n %s", "["+strings.Join(updatableServiceNameList, "], [")+"]")) -// return err -// } -// -// return nil -//} - // upsertService 创建或者更新服务, 更新服务之前先创建服务需要的配置 func upsertService(isUpdate bool, env *commonmodels.Product, service *commonmodels.ProductService, prevSvc *commonmodels.ProductService, @@ -2693,6 +2212,7 @@ func installProductHelmCharts(user, envName, requestID string, args *commonmodel errList = multierror.Append(errList, serviceGroupErr...) } } + err = errList.ErrorOrNil() } diff --git a/pkg/microservice/aslan/core/environment/service/product.go b/pkg/microservice/aslan/core/environment/service/product.go index 52909896ee3cd78bfc85d88daf7c265ef493d9b1..c91818eab4fe26a0d0c35bd3bd7cb378bba495d1 100644 --- a/pkg/microservice/aslan/core/environment/service/product.go +++ b/pkg/microservice/aslan/core/environment/service/product.go @@ -31,7 +31,6 @@ import ( commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/poetry" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/log" ) @@ -61,25 +60,19 @@ func CleanProductCronJob(requestID string, log *zap.SugaredLogger) { } if time.Now().Unix()-product.UpdateTime > int64(60*60*24*product.RecycleDay) { - title := "系统清理产品信息" - content := fmt.Sprintf("环境 [%s] 已经连续%d天没有使用, 系统已自动删除该环境, 如有需要请重新创建。", product.EnvName, product.RecycleDay) + //title := "系统清理产品信息" + //content := fmt.Sprintf("环境 [%s] 已经连续%d天没有使用, 系统已自动删除该环境, 如有需要请重新创建。", product.EnvName, product.RecycleDay) if err := commonservice.DeleteProduct("robot", product.EnvName, product.ProductName, requestID, log); err != nil { log.Errorf("[%s][P:%s] delete product error: %v", product.EnvName, product.ProductName, err) // 如果有错误,重试删除 if err := commonservice.DeleteProduct("robot", product.EnvName, product.ProductName, requestID, log); err != nil { - content = fmt.Sprintf("系统自动清理环境 [%s] 失败,请手动删除环境。", product.ProductName) + //content = fmt.Sprintf("系统自动清理环境 [%s] 失败,请手动删除环境。", product.ProductName) log.Errorf("[%s][P:%s] retry delete product error: %v", product.EnvName, product.ProductName, err) } } - poetryClient := poetry.New(config.PoetryAPIServer(), config.PoetryAPIRootKey()) - users, _ := poetryClient.ListProductPermissionUsers("", "", log) - for _, user := range users { - commonservice.SendMessage(user, title, content, requestID, log) - } - log.Warnf("[%s] product %s deleted", product.EnvName, product.ProductName) } } @@ -108,11 +101,9 @@ func GetInitProduct(productTmplName string, log *zap.SugaredLogger) (*commonmode //返回中的ProductName即产品模板的名称 ret.ProductName = prodTmpl.ProductName ret.Revision = prodTmpl.Revision - ret.Enabled = prodTmpl.Enabled ret.Services = [][]*commonmodels.ProductService{} ret.UpdateBy = prodTmpl.UpdateBy ret.CreateTime = prodTmpl.CreateTime - ret.Visibility = prodTmpl.Visibility ret.Render = &commonmodels.RenderInfo{Name: "", Description: ""} ret.Vars = prodTmpl.Vars ret.ChartInfos = prodTmpl.ChartInfos diff --git a/pkg/microservice/aslan/core/environment/service/revision.go b/pkg/microservice/aslan/core/environment/service/revision.go index e17cc768e8c1713ab80ca13eaa64717b2c2b13f6..ffa22b27be0ab71f92a6148fc56b6a6ad7a55493 100644 --- a/pkg/microservice/aslan/core/environment/service/revision.go +++ b/pkg/microservice/aslan/core/environment/service/revision.go @@ -20,82 +20,17 @@ import ( "fmt" "go.uber.org/zap" - "k8s.io/apimachinery/pkg/util/sets" - "github.com/koderover/zadig/pkg/microservice/aslan/config" commonmodels "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" templaterepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb/template" commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/poetry" e "github.com/koderover/zadig/pkg/tool/errors" ) -func ListProductsRevision(productName, envName string, userID int, superUser bool, log *zap.SugaredLogger) ([]*ProductRevision, error) { - var ( - err error - prodRevs = make([]*ProductRevision, 0) - products = make([]*commonmodels.Product, 0) - productNameMap map[string][]int64 - productNamespaces = sets.NewString() - ) - if superUser { - products, err = commonrepo.NewProductColl().List(&commonrepo.ProductListOptions{ExcludeStatus: setting.ProductStatusDeleting, Name: productName, EnvName: envName}) - if err != nil { - log.Errorf("Collection.Product.List error: %v", err) - return prodRevs, e.ErrListProducts.AddDesc(err.Error()) - } - } else { - //项目下所有公开环境 - publicProducts, err := commonrepo.NewProductColl().List(&commonrepo.ProductListOptions{IsPublic: true, ExcludeStatus: setting.ProductStatusDeleting, Name: productName, EnvName: envName}) - if err != nil { - log.Errorf("Collection.Product.List List product error: %v", err) - return prodRevs, e.ErrListProducts.AddDesc(err.Error()) - } - for _, publicProduct := range publicProducts { - products = append(products, publicProduct) - productNamespaces.Insert(publicProduct.Namespace) - } - - poetryCtl := poetry.New(config.PoetryAPIServer(), config.PoetryAPIRootKey()) - productNameMap, err = poetryCtl.GetUserProject(userID, log) - if err != nil { - log.Errorf("Collection.Product.List GetUserProject error: %v", err) - return prodRevs, e.ErrListProducts.AddDesc(err.Error()) - } - for productName, roleIDs := range productNameMap { - //用户关联角色所关联的环境 - for _, roleID := range roleIDs { - if roleID == setting.RoleOwnerID { - tmpProducts, err := commonrepo.NewProductColl().List(&commonrepo.ProductListOptions{ExcludeStatus: setting.ProductStatusDeleting, Name: productName, EnvName: envName}) - if err != nil { - log.Errorf("Collection.Product.List Find product error: %v", err) - return prodRevs, e.ErrListProducts.AddDesc(err.Error()) - } - for _, product := range tmpProducts { - if !productNamespaces.Has(product.Namespace) { - products = append(products, product) - } - } - } else { - roleEnvs, err := poetryCtl.ListRoleEnvs(productName, envName, roleID, log) - if err != nil { - log.Errorf("Collection.Product.List ListRoleEnvs error: %v", err) - return prodRevs, e.ErrListProducts.AddDesc(err.Error()) - } - for _, roleEnv := range roleEnvs { - product, err := commonrepo.NewProductColl().Find(&commonrepo.ProductFindOptions{Name: productName, EnvName: roleEnv.EnvName}) - if err != nil { - log.Errorf("Collection.Product.List Find product error: %v", err) - return prodRevs, e.ErrListProducts.AddDesc(err.Error()) - } - products = append(products, product) - } - } - } - } - } +func ListProductsRevision(productName, envName string, log *zap.SugaredLogger) (prodRevs []*ProductRevision, err error) { + products, err := commonrepo.NewProductColl().List(&commonrepo.ProductListOptions{Name: productName, IsSortByProductName: true, EnvName: envName}) // 获取所有服务模板最新模板信息 allServiceTmpls, err := commonrepo.NewServiceColl().ListAllRevisions() diff --git a/pkg/microservice/aslan/core/log/handler/log.go b/pkg/microservice/aslan/core/log/handler/log.go index 6627420d3102d0e3780fe5c3ec8fb55aede90c12..648d858801878cbb25133fac866bbc013e55af30 100644 --- a/pkg/microservice/aslan/core/log/handler/log.go +++ b/pkg/microservice/aslan/core/log/handler/log.go @@ -94,7 +94,7 @@ func GetContainerLogs(c *gin.Context) { podName := c.Param("name") containerName := c.Query("container") envName := c.Query("envName") - productName := c.Query("productName") + productName := c.Query("projectName") tailLines, err := strconv.ParseInt(c.Query("tailLines"), 10, 64) if err != nil { diff --git a/pkg/microservice/aslan/core/log/handler/router.go b/pkg/microservice/aslan/core/log/handler/router.go index 03bda972111b6c2fda3edd04901c7f3dc59340e2..2fcfcb088de8944ca2366febd8e385c0586a72ef 100644 --- a/pkg/microservice/aslan/core/log/handler/router.go +++ b/pkg/microservice/aslan/core/log/handler/router.go @@ -18,15 +18,11 @@ package handler import ( "github.com/gin-gonic/gin" - - gin2 "github.com/koderover/zadig/pkg/middleware/gin" ) type Router struct{} func (*Router) Inject(router *gin.RouterGroup) { - router.Use(gin2.Auth()) - { router.GET("/pods/:name", GetContainerLogs) } diff --git a/pkg/microservice/aslan/core/log/handler/sse.go b/pkg/microservice/aslan/core/log/handler/sse.go index 7293d4360b64d8b3088212e5c908770e536f759c..2ac7c83265fd819463129f13f617064a5489bdcc 100644 --- a/pkg/microservice/aslan/core/log/handler/sse.go +++ b/pkg/microservice/aslan/core/log/handler/sse.go @@ -39,7 +39,7 @@ func GetContainerLogsSSE(c *gin.Context) { } envName := c.Query("envName") - productName := c.Query("productName") + productName := c.Query("projectName") internalhandler.Stream(c, func(ctx context.Context, streamChan chan interface{}) { logservice.ContainerLogStream(ctx, streamChan, envName, productName, c.Param("podName"), c.Param("containerName"), true, tails, logger) @@ -102,7 +102,7 @@ func GetWorkflowBuildJobContainerLogsSSE(c *gin.Context) { ServiceName: c.Param("serviceName"), PipelineType: string(config.WorkflowType), EnvName: c.Query("envName"), - ProductName: c.Query("productName"), + ProductName: c.Query("projectName"), } internalhandler.Stream(c, func(ctx1 context.Context, streamChan chan interface{}) { diff --git a/pkg/microservice/aslan/core/log/service/log.go b/pkg/microservice/aslan/core/log/service/log.go index c4e9ce00f99c34283d6df2d7e185445f5d564992..73778bc93e38d09dcffdf5fc2e967a42732d6791 100644 --- a/pkg/microservice/aslan/core/log/service/log.go +++ b/pkg/microservice/aslan/core/log/service/log.go @@ -72,6 +72,7 @@ func GetWorkflowTestJobContainerLogs(pipelineName, serviceName, pipelineType str func getContainerLogFromS3(pipelineName, filenamePrefix string, taskID int64, log *zap.SugaredLogger) (string, error) { fileName := strings.Replace(strings.ToLower(filenamePrefix), "_", "-", -1) + fileName += ".log" tempFile, _ := util.GenerateTmpFile() defer func() { _ = os.Remove(tempFile) @@ -97,16 +98,11 @@ func getContainerLogFromS3(pipelineName, filenamePrefix string, taskID int64, lo log.Errorf("Failed to create s3 client, the error is: %+v", err) return "", err } - objectPrefix := storage.GetObjectPath(fileName) - fileList, err := client.ListFiles(storage.Bucket, objectPrefix, false) - if err != nil { - log.Errorf("GetContainerLogFromS3 ListFiles err:%v", err) - return "", err - } - if len(fileList) == 0 { - return "", nil - } - err = client.Download(storage.Bucket, fileList[0], tempFile) + fullPath := storage.GetObjectPath(fileName) + err = client.DownloadWithOption(storage.Bucket, fullPath, tempFile, &s3tool.DownloadOption{ + IgnoreNotExistError: true, + RetryNum: 3, + }) if err != nil { log.Errorf("GetContainerLogFromS3 Download err:%v", err) return "", err diff --git a/pkg/microservice/aslan/core/multicluster/handler/clusters.go b/pkg/microservice/aslan/core/multicluster/handler/clusters.go index c421e307e5722f9b917a8975e0259b8d9d94dccc..d84ea096d0eeacb119be14f0db185532fc64dedd 100644 --- a/pkg/microservice/aslan/core/multicluster/handler/clusters.go +++ b/pkg/microservice/aslan/core/multicluster/handler/clusters.go @@ -60,7 +60,7 @@ func CreateCluster(c *gin.Context) { } args.CreatedAt = time.Now().Unix() - args.CreatedBy = ctx.Username + args.CreatedBy = ctx.UserName ctx.Resp, ctx.Err = service.CreateCluster(args, ctx.Logger) } @@ -87,21 +87,21 @@ func DeleteCluster(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - ctx.Err = service.DeleteCluster(ctx.Username, c.Param("id"), ctx.Logger) + ctx.Err = service.DeleteCluster(ctx.UserName, c.Param("id"), ctx.Logger) } func DisconnectCluster(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - ctx.Err = service.DisconnectCluster(ctx.Username, c.Param("id"), ctx.Logger) + ctx.Err = service.DisconnectCluster(ctx.UserName, c.Param("id"), ctx.Logger) } func ReconnectCluster(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - ctx.Err = service.ReconnectCluster(ctx.Username, c.Param("id"), ctx.Logger) + ctx.Err = service.ReconnectCluster(ctx.UserName, c.Param("id"), ctx.Logger) } func ClusterConnectFromAgent(c *gin.Context) { diff --git a/pkg/microservice/aslan/core/multicluster/handler/router.go b/pkg/microservice/aslan/core/multicluster/handler/router.go index fc4ba73703931f12b785a57fa759de0cad7601e1..7d03a0a4e530efa3955e693723412be26a09ed78 100644 --- a/pkg/microservice/aslan/core/multicluster/handler/router.go +++ b/pkg/microservice/aslan/core/multicluster/handler/router.go @@ -18,8 +18,6 @@ package handler import ( "github.com/gin-gonic/gin" - - gin2 "github.com/koderover/zadig/pkg/middleware/gin" ) type Router struct{} @@ -31,17 +29,15 @@ func (*Router) Inject(router *gin.RouterGroup) { Agent.GET("/:id/agent.yaml", GetClusterYaml("/api/hub")) } - router.Use(gin2.Auth()) - Cluster := router.Group("clusters") { Cluster.GET("", ListClusters) Cluster.GET("/:id", GetCluster) - Cluster.POST("", gin2.RequireSuperAdminAuth, CreateCluster) - Cluster.PUT("/:id", gin2.RequireSuperAdminAuth, UpdateCluster) - Cluster.DELETE("/:id", gin2.RequireSuperAdminAuth, DeleteCluster) - Cluster.PUT("/:id/disconnect", gin2.RequireSuperAdminAuth, DisconnectCluster) - Cluster.PUT("/:id/reconnect", gin2.RequireSuperAdminAuth, ReconnectCluster) + Cluster.POST("", CreateCluster) + Cluster.PUT("/:id", UpdateCluster) + Cluster.DELETE("/:id", DeleteCluster) + Cluster.PUT("/:id/disconnect", DisconnectCluster) + Cluster.PUT("/:id/reconnect", ReconnectCluster) } } diff --git a/pkg/microservice/aslan/core/project/handler/policy.yaml b/pkg/microservice/aslan/core/project/handler/policy.yaml new file mode 100644 index 0000000000000000000000000000000000000000..2ceecbcc76c59292d8640b8b5f15a05e1f8d7ac8 --- /dev/null +++ b/pkg/microservice/aslan/core/project/handler/policy.yaml @@ -0,0 +1,106 @@ +resource: Service +alias: "项目配置" +description: "" +rules: + - action: get_service + alias: "查看服务" + description: "" + rules: + - method: GET + endpoint: "/api/aslan/service/services" + - method: GET + endpoint: "/api/aslan/service/services/?*/k8s" + - method: GET + endpoint: "/api/aslan/project/products/?*/services" + - method: GET + endpoint: "/api/aslan/service/services/?*" + - method: GET + endpoint: "/api/aslan/project/products/?*/searching-rules" + - method: GET + endpoint: "/api/aslan/service/helm/?*/?*/filePath" + - method: GET + endpoint: "/api/aslan/service/helm/?*/?*/fileContent" + - method: GET + endpoint: "/api/aslan/service/helm/?*/?*/serviceModule" + - action: edit_service + alias: "编辑服务" + description: "" + rules: + - method: POST + endpoint: "/api/aslan/service/helm/?*" + - method: PUT + endpoint: "/api/aslan/service/services" + - method: PUT + endpoint: "/api/aslan/service/pm/?*" + - method: PUT + endpoint: "/api/aslan/project/products/?*" + - method: PATCH + endpoint: "/api/aslan/project/products/?*" + - method: PUT + endpoint: "/api/aslan/project/products/?*/searching-rules" + - method: POST + endpoint: "/api/aslan/service/template/reload" + - action: create_service + alias: "新建服务" + description: "" + rules: + - method: POST + endpoint: "/api/aslan/service/pm/?*" + - method: POST + endpoint: "/api/aslan/service/services" + - method: GET + endpoint: "/api/aslan/service/loader/preload/?*/?*" + - method: POST + endpoint: "/api/aslan/service/loader/load/?*/?*" + - method: POST + endpoint: "/api/aslan/service/helm/services" + - method: GET + endpoint: "/api/aslan/template/yaml" + - method: GET + endpoint: "/api/aslan/template/yaml/?*" + - method: POST + endpoint: "/api/aslan/service/template/load" + - method: GET + endpoint: "/api/aslan/template/charts/?*/variables" + - method: POST + endpoint: "/api/aslan/service/helm/services/bulk" + - action: delete_service + alias: "删除服务" + description: "" + rules: + - method: DELETE + endpoint: "/api/aslan/service/services/?*/?*" + - method: DELETE + endpoint: "/api/aslan/service/services/?*/pm" + - action: get_build + alias: "查看构建配置" + description: "" + rules: + - method: GET + endpoint: "/api/aslan/build/build" + - method: GET + endpoint: "/api/aslan/build/build/?*" + - method: GET + endpoint: "/api/aslan/build/targets" + - action: create_build + alias: "新建构建配置" + description: "" + rules: + - method: POST + endpoint: "/api/aslan/build/build" + - action: edit_build + alias: "编辑构建配置" + description: "" + rules: + - method: PUT + endpoint: "/api/aslan/build/build" + - method: POST + endpoint: "/api/aslan/build/targets" + - method: POST + endpoint: "/api/aslan/build/build/targets" + - action: delete_build + alias: "删除构建配置" + description: "" + rules: + - method: DELETE + endpoint: "/api/aslan/build/build" \ No newline at end of file diff --git a/pkg/microservice/aslan/core/project/handler/policy_definitions.go b/pkg/microservice/aslan/core/project/handler/policy_definitions.go new file mode 100644 index 0000000000000000000000000000000000000000..a434ba1ddc8fb0fcf719d776fc0e1211fe8a5240 --- /dev/null +++ b/pkg/microservice/aslan/core/project/handler/policy_definitions.go @@ -0,0 +1,24 @@ +package handler + +import ( + _ "embed" + + "sigs.k8s.io/yaml" + + "github.com/koderover/zadig/pkg/shared/client/policy" + "github.com/koderover/zadig/pkg/tool/log" +) + +//go:embed policy.yaml +var policyDefinitions []byte + +func (*Router) Policies() *policy.Policy { + res := &policy.Policy{} + err := yaml.Unmarshal(policyDefinitions, res) + if err != nil { + // should not have happened here + log.DPanic(err) + } + + return res +} diff --git a/pkg/microservice/aslan/core/project/handler/product.go b/pkg/microservice/aslan/core/project/handler/product.go index a84cc30ddce561edb368b163184d7168b7bf6bea..0729c3e2b618cecb47c9331079d6b71dba665e85 100644 --- a/pkg/microservice/aslan/core/project/handler/product.go +++ b/pkg/microservice/aslan/core/project/handler/product.go @@ -47,19 +47,6 @@ func GetProductTemplateServices(c *gin.Context) { ctx.Resp, ctx.Err = projectservice.GetProductTemplateServices(productTemplatName, ctx.Logger) } -//ListProductTemplate 产品分页信息 -func ListProductTemplate(c *gin.Context) { - ctx := internalhandler.NewContext(c) - defer func() { internalhandler.JSONResponse(c, ctx) }() - - productType := c.DefaultQuery("productType", "normal") - if productType != "openSource" { - ctx.Resp, ctx.Err = projectservice.ListProductTemplate(ctx.User.ID, ctx.User.IsSuperUser, ctx.Logger) - return - } - ctx.Resp, ctx.Err = projectservice.ListOpenSourceProduct(ctx.Logger) -} - func CreateProductTemplate(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() @@ -72,14 +59,14 @@ func CreateProductTemplate(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("CreateProductTemplate json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, args.ProductName, "新增", "项目管理-项目", args.ProductName, string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, args.ProductName, "新增", "项目管理-项目", args.ProductName, string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) if err := c.BindJSON(args); err != nil { ctx.Err = e.ErrInvalidParam.AddDesc("invalid ProductTmpl json args") return } - args.UpdateBy = ctx.Username + args.UpdateBy = ctx.UserName ctx.Err = projectservice.CreateProductTemplate(args, ctx.Logger) } @@ -96,7 +83,7 @@ func UpdateProductTemplate(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("UpdateProductTemplate json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, args.ProductName, "更新", "项目管理-项目环境模板或变量", args.ProductName, string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, args.ProductName, "更新", "项目管理-项目环境模板或变量", args.ProductName, string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) if err := c.BindJSON(args); err != nil { @@ -104,7 +91,7 @@ func UpdateProductTemplate(c *gin.Context) { return } - args.UpdateBy = ctx.Username + args.UpdateBy = ctx.UserName ctx.Err = projectservice.UpdateProductTemplate(c.Param("name"), args, ctx.Logger) } @@ -122,19 +109,6 @@ type updateServiceOrderArgs struct { Services [][]string `json:"services"` } -func UpdateServiceOrchestration(c *gin.Context) { - ctx := internalhandler.NewContext(c) - defer func() { internalhandler.JSONResponse(c, ctx) }() - - args := new(updateServiceOrderArgs) - if err := c.ShouldBindJSON(args); err != nil { - ctx.Err = e.ErrInvalidParam.AddDesc("invalid updateServiceOrder args") - return - } - - ctx.Err = projectservice.UpdateServiceOrchestration(ctx.User.Name, c.Param("name"), args.Services, ctx.Logger) -} - func UpdateProject(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() @@ -147,15 +121,15 @@ func UpdateProject(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("UpdateProject json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, args.ProductName, "更新", "项目管理-项目", args.ProductName, string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, args.ProductName, "更新", "项目管理-项目", args.ProductName, string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) if err := c.BindJSON(args); err != nil { ctx.Err = e.ErrInvalidParam.AddDesc("invalid ProductTmpl json args") return } - args.UpdateBy = ctx.Username - productName := c.Query("productName") + args.UpdateBy = ctx.UserName + productName := c.Query("projectName") if productName == "" { ctx.Err = e.ErrInvalidParam.AddDesc("productName can't be empty") return @@ -163,19 +137,43 @@ func UpdateProject(c *gin.Context) { ctx.Err = projectservice.UpdateProject(productName, args, ctx.Logger) } +type UpdateOrchestrationServiceReq struct { + Services [][]string `json:"services"` +} + +func UpdateServiceOrchestration(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + projectName := c.Param("name") + if projectName == "" { + ctx.Err = e.ErrInvalidParam + return + } + internalhandler.InsertOperationLog(c, ctx.UserName, projectName, "更新", "项目管理-项目服务编排", projectName, "", ctx.Logger) + + args := new(UpdateOrchestrationServiceReq) + if err := c.BindJSON(args); err != nil { + ctx.Err = e.ErrInvalidParam.AddDesc("invalid UpdateOrchestrationServiceReq json args") + return + } + + ctx.Err = projectservice.UpdateServiceOrchestration(projectName, args.Services, ctx.UserName, ctx.Logger) +} + func DeleteProductTemplate(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - internalhandler.InsertOperationLog(c, ctx.Username, c.Param("name"), "删除", "项目管理-项目", c.Param("name"), "", ctx.Logger) - ctx.Err = projectservice.DeleteProductTemplate(ctx.Username, c.Param("name"), ctx.RequestID, ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, c.Param("name"), "删除", "项目管理-项目", c.Param("name"), "", ctx.Logger) + ctx.Err = projectservice.DeleteProductTemplate(ctx.UserName, c.Param("name"), ctx.RequestID, ctx.Logger) } func ListTemplatesHierachy(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - ctx.Resp, ctx.Err = projectservice.ListTemplatesHierachy(ctx.User.Name, ctx.User.ID, ctx.User.IsSuperUser, ctx.Logger) + ctx.Resp, ctx.Err = projectservice.ListTemplatesHierachy(ctx.UserName, ctx.Logger) } func ForkProduct(c *gin.Context) { @@ -188,14 +186,14 @@ func ForkProduct(c *gin.Context) { return } args.ProductName = c.Param("productName") - ctx.Err = projectservice.ForkProduct(ctx.User.ID, ctx.Username, ctx.RequestID, args, ctx.Logger) + ctx.Err = projectservice.ForkProduct(ctx.UserName, ctx.UserID, ctx.RequestID, args, ctx.Logger) } func UnForkProduct(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - ctx.Err = projectservice.UnForkProduct(ctx.User.ID, ctx.Username, c.Param("productName"), c.Query("workflowName"), c.Query("envName"), ctx.RequestID, ctx.Logger) + ctx.Err = projectservice.UnForkProduct(ctx.UserID, ctx.UserName, c.Param("productName"), c.Query("workflowName"), c.Query("envName"), ctx.RequestID, ctx.Logger) } func GetCustomMatchRules(c *gin.Context) { @@ -219,7 +217,7 @@ func CreateOrUpdateMatchRules(c *gin.Context) { return } - internalhandler.InsertOperationLog(c, ctx.Username, c.Param("name"), "更新", "工程管理-项目", c.Param("name"), "", ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, c.Param("name"), "更新", "工程管理-项目", c.Param("name"), "", ctx.Logger) args := new(projectservice.CustomParseDataArgs) data, err := c.GetRawData() @@ -234,5 +232,5 @@ func CreateOrUpdateMatchRules(c *gin.Context) { return } - ctx.Err = projectservice.UpdateCustomMatchRules(c.Param("name"), ctx.Username, args.Rules) + ctx.Err = projectservice.UpdateCustomMatchRules(c.Param("name"), ctx.UserName, args.Rules) } diff --git a/pkg/microservice/aslan/core/project/handler/project.go b/pkg/microservice/aslan/core/project/handler/project.go index 32bb3949e9978a42e4dc59296479f5c33b705a2e..c2747c35d7a849ffdce97c49ea9e04272fd82814 100644 --- a/pkg/microservice/aslan/core/project/handler/project.go +++ b/pkg/microservice/aslan/core/project/handler/project.go @@ -25,8 +25,10 @@ import ( ) type projectListArgs struct { - IgnoreNoEnvs bool `json:"ignoreNoEnvs" form:"ignoreNoEnvs"` - Verbosity string `json:"verbosity" form:"verbosity"` + IgnoreNoEnvs bool `json:"ignoreNoEnvs" form:"ignoreNoEnvs"` + IgnoreNoVersions bool `json:"ignoreNoVersions" form:"ignoreNoVersions"` + Verbosity string `json:"verbosity" form:"verbosity"` + Names []string `json:"names" form:"names"` } func ListProjects(c *gin.Context) { @@ -39,8 +41,19 @@ func ListProjects(c *gin.Context) { return } + productType := c.DefaultQuery("productType", "normal") + if productType == "openSource" { + ctx.Resp, ctx.Err = projectservice.ListOpenSourceProduct(ctx.Logger) + return + } + ctx.Resp, ctx.Err = projectservice.ListProjects( - &projectservice.ProjectListOptions{IgnoreNoEnvs: args.IgnoreNoEnvs, Verbosity: projectservice.QueryVerbosity(args.Verbosity)}, + &projectservice.ProjectListOptions{ + IgnoreNoEnvs: args.IgnoreNoEnvs, + IgnoreNoVersions: args.IgnoreNoVersions, + Verbosity: projectservice.QueryVerbosity(args.Verbosity), + Names: args.Names, + }, ctx.Logger, ) } diff --git a/pkg/microservice/aslan/core/project/handler/render.go b/pkg/microservice/aslan/core/project/handler/render.go index 86f259fd96deff534d4258460d2a76a41d985ab8..0061ae33955e627aa73d137b182532d7223cf78b 100644 --- a/pkg/microservice/aslan/core/project/handler/render.go +++ b/pkg/microservice/aslan/core/project/handler/render.go @@ -60,31 +60,6 @@ func GetRenderSetInfo(c *gin.Context) { ctx.Resp, ctx.Err = service.GetRenderSetInfo(c.Param("name"), revision) } -//func ValidateRenderSet(c *gin.Context) { -// ctx := internalhandler.NewContext(c) -// defer func() { internalhandler.JSONResponse(c, ctx) }() -// _, ctx.Err = projectservice.ValidateRenderSet(c.Param("productName"), c.Param("renderName"), "", ctx.Logger) -//} -// -//func RelateRender(c *gin.Context) { -// ctx := internalhandler.NewContext(c) -// defer func() { internalhandler.JSONResponse(c, ctx) }() -// ctx.Err = projectservice.RelateRender(c.Param("productName"), c.Param("renderName"), ctx.Logger) -//} -// -//func CreateRenderSet(c *gin.Context) { -// ctx := internalhandler.NewContext(c) -// defer func() { internalhandler.JSONResponse(c, ctx) }() -// -// args := new(models.RenderSet) -// ctx.Err = c.BindJSON(args) -// if ctx.Err != nil { -// return -// } -// args.UpdateBy = ctx.Username -// ctx.Err = projectservice.CreateRenderSet(args, ctx.Logger) -//} - func UpdateRenderSet(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() @@ -94,6 +69,6 @@ func UpdateRenderSet(c *gin.Context) { if ctx.Err != nil { return } - args.UpdateBy = ctx.Username + args.UpdateBy = ctx.UserName ctx.Err = service.UpdateRenderSet(args, ctx.Logger) } diff --git a/pkg/microservice/aslan/core/project/handler/router.go b/pkg/microservice/aslan/core/project/handler/router.go index 1d5c8ea713ef7a46294ddc72cc34a6768b6704ba..d8a5c4d17e79aa4a080f2bec6a60716fcad9cb36 100644 --- a/pkg/microservice/aslan/core/project/handler/router.go +++ b/pkg/microservice/aslan/core/project/handler/router.go @@ -20,14 +20,11 @@ import ( "github.com/gin-gonic/gin" gin2 "github.com/koderover/zadig/pkg/middleware/gin" - "github.com/koderover/zadig/pkg/types/permission" ) type Router struct{} func (*Router) Inject(router *gin.RouterGroup) { - router.Use(gin2.Auth()) - // 查看自定义变量是否被引用 render := router.Group("renders") { @@ -42,15 +39,14 @@ func (*Router) Inject(router *gin.RouterGroup) { { product.GET("/:name", GetProductTemplate) product.GET("/:name/services", GetProductTemplateServices) - product.GET("", ListProductTemplate) product.GET("/:name/searching-rules", GetCustomMatchRules) - product.PUT("/:name/searching-rules", gin2.StoreProductName, gin2.IsHavePermission([]string{permission.ServiceTemplateEditUUID}, permission.ContextKeyType), gin2.UpdateOperationLogStatus, CreateOrUpdateMatchRules) - product.POST("", gin2.StoreProductName, gin2.IsHavePermission([]string{permission.SuperUserUUID}, permission.ContextKeyType), gin2.UpdateOperationLogStatus, CreateProductTemplate) - product.PUT("/:name", gin2.IsHavePermission([]string{permission.ServiceTemplateEditUUID}, permission.ParamType), gin2.UpdateOperationLogStatus, UpdateProductTemplate) - product.PUT("/:name/:status", gin2.IsHavePermission([]string{permission.ServiceTemplateEditUUID}, permission.ParamType), gin2.UpdateOperationLogStatus, UpdateProductTmplStatus) + product.PUT("/:name/searching-rules", gin2.UpdateOperationLogStatus, CreateOrUpdateMatchRules) + product.POST("", gin2.UpdateOperationLogStatus, CreateProductTemplate) + product.PUT("/:name", gin2.UpdateOperationLogStatus, UpdateProductTemplate) + product.PUT("/:name/:status", gin2.UpdateOperationLogStatus, UpdateProductTmplStatus) product.PATCH("/:name", gin2.UpdateOperationLogStatus, UpdateServiceOrchestration) - product.PUT("", gin2.StoreProductName, gin2.IsHavePermission([]string{permission.SuperUserUUID}, permission.ContextKeyType), gin2.UpdateOperationLogStatus, UpdateProject) - product.DELETE("/:name", gin2.IsHavePermission([]string{permission.SuperUserUUID}, permission.ParamType), gin2.UpdateOperationLogStatus, DeleteProductTemplate) + product.PUT("", gin2.UpdateOperationLogStatus, UpdateProject) + product.DELETE("/:name", gin2.UpdateOperationLogStatus, DeleteProductTemplate) } openSource := router.Group("opensource") diff --git a/pkg/microservice/aslan/core/project/service/product.go b/pkg/microservice/aslan/core/project/service/product.go index 5e00738ec6845ac56f9f5086f45f13b7be32ef9d..29010f333a3d85d0bcb46df62c09e1aaf80520b4 100644 --- a/pkg/microservice/aslan/core/project/service/product.go +++ b/pkg/microservice/aslan/core/project/service/product.go @@ -22,7 +22,6 @@ import ( "regexp" "strconv" "strings" - "sync" "github.com/hashicorp/go-multierror" "github.com/pkg/errors" @@ -30,6 +29,7 @@ import ( "k8s.io/apimachinery/pkg/util/sets" "sigs.k8s.io/yaml" + configbase "github.com/koderover/zadig/pkg/config" "github.com/koderover/zadig/pkg/microservice/aslan/config" commonmodels "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models/template" @@ -40,10 +40,10 @@ import ( environmentservice "github.com/koderover/zadig/pkg/microservice/aslan/core/environment/service" workflowservice "github.com/koderover/zadig/pkg/microservice/aslan/core/workflow/service/workflow" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/poetry" + "github.com/koderover/zadig/pkg/shared/client/policy" + configclient "github.com/koderover/zadig/pkg/shared/config" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/log" - "github.com/koderover/zadig/pkg/types/permission" ) type CustomParseDataArgs struct { @@ -76,208 +76,6 @@ func GetProductTemplateServices(productName string, log *zap.SugaredLogger) (*te return resp, nil } -// ListProductTemplate 列出产品模板分页 -func ListProductTemplate(userID int, superUser bool, log *zap.SugaredLogger) ([]*template.Product, error) { - var ( - err error - errorList = &multierror.Error{} - resp = make([]*template.Product, 0) - tmpls = make([]*template.Product, 0) - productTmpls = make([]*template.Product, 0) - productNameMap = make(map[string][]int64) - productMap = make(map[string]*template.Product) - wg sync.WaitGroup - mu sync.Mutex - maxRoutineNum = 20 // 协程池最大协程数量 - ch = make(chan int, maxRoutineNum) // 控制协程数量 - ) - - poetryCtl := poetry.New(config.PoetryAPIServer(), config.PoetryAPIRootKey()) - - tmpls, err = templaterepo.NewProductColl().List() - if err != nil { - log.Errorf("ProfuctTmpl.List error: %v", err) - return resp, e.ErrListProducts.AddDesc(err.Error()) - } - - for _, product := range tmpls { - if superUser { - product.Role = setting.RoleAdmin - product.PermissionUUIDs = []string{} - product.ShowProject = true - continue - } - productMap[product.ProductName] = product - } - - if !superUser { - productNameMap, err = poetryCtl.GetUserProject(userID, log) - if err != nil { - log.Errorf("ProfuctTmpl.List GetUserProject error: %v", err) - return resp, e.ErrListProducts.AddDesc(err.Error()) - } - - // 优先处理客户有明确关联关系的项目 - for productName, roleIDs := range productNameMap { - wg.Add(1) - ch <- 1 - // 临时复制range获取的数据,避免重复操作最后一条数据 - tmpProductName := productName - tmpRoleIDs := roleIDs - - go func(tmpProductName string, tmpRoleIDs []int64) { - defer func() { - <-ch - wg.Done() - }() - - roleID := tmpRoleIDs[0] - product, err := templaterepo.NewProductColl().Find(tmpProductName) - if err != nil { - errorList = multierror.Append(errorList, err) - log.Errorf("ProfuctTmpl.List error: %v", err) - return - } - uuids, err := poetryCtl.GetUserPermissionUUIDs(roleID, tmpProductName, log) - if err != nil { - errorList = multierror.Append(errorList, err) - log.Errorf("ProfuctTmpl.List GetUserPermissionUUIDs error: %v", err) - return - } - if roleID == setting.RoleOwnerID { - product.Role = setting.RoleOwner - product.PermissionUUIDs = []string{} - } else { - product.Role = setting.RoleUser - product.PermissionUUIDs = uuids - } - product.ShowProject = true - mu.Lock() - productTmpls = append(productTmpls, product) - delete(productMap, tmpProductName) - mu.Unlock() - }(tmpProductName, tmpRoleIDs) - } - - wg.Wait() - if errorList.ErrorOrNil() != nil { - return resp, errorList - } - - // 增加项目里面设置过all-users的权限处理 - for _, product := range productMap { - wg.Add(1) - ch <- 1 - // 临时复制range获取的数据,避免重复操作最后一条数据 - tmpProduct := product - - go func(tmpProduct *template.Product) { - defer func() { - <-ch - wg.Done() - }() - - productRole, _ := poetryCtl.ListRoles(tmpProduct.ProductName, log) - if productRole != nil { - uuids, err := poetryCtl.GetUserPermissionUUIDs(productRole.ID, tmpProduct.ProductName, log) - if err != nil { - errorList = multierror.Append(errorList, err) - log.Errorf("ProfuctTmpl.List GetUserPermissionUUIDs error: %v", err) - return - } - - tmpProduct.Role = setting.RoleUser - tmpProduct.PermissionUUIDs = uuids - tmpProduct.ShowProject = true - mu.Lock() - productTmpls = append(productTmpls, tmpProduct) - delete(productMap, tmpProduct.ProductName) - mu.Unlock() - } - }(tmpProduct) - } - wg.Wait() - if errorList.ErrorOrNil() != nil { - return resp, errorList - } - - // 最后处理剩余的项目 - for _, product := range productMap { - wg.Add(1) - ch <- 1 - // 临时复制range获取的数据,避免重复操作最后一条数据 - tmpProduct := product - - go func(tmpProduct *template.Product) { - defer func() { - <-ch - wg.Done() - }() - - var uuids []string - uuids, err = poetryCtl.GetUserPermissionUUIDs(setting.RoleUserID, "", log) - if err != nil { - errorList = multierror.Append(errorList, err) - log.Errorf("ProfuctTmpl.List GetUserPermissionUUIDs error: %v", err) - return - } - tmpProduct.Role = setting.RoleUser - tmpProduct.PermissionUUIDs = uuids - tmpProduct.ShowProject = false - mu.Lock() - productTmpls = append(productTmpls, tmpProduct) - mu.Unlock() - }(tmpProduct) - } - wg.Wait() - if errorList.ErrorOrNil() != nil { - return resp, errorList - } - // 先清空tmpls中的管理员角色数据后,再插入普通用户角色的数据 - tmpls = make([]*template.Product, 0) - tmpls = append(tmpls, productTmpls...) - } - - err = FillProductTemplateVars(tmpls, log) - if err != nil { - return resp, err - } - - for _, tmpl := range tmpls { - wg.Add(1) - ch <- 1 - - go func(tmpTmpl *template.Product) { - defer func() { - <-ch - wg.Done() - }() - - tmpTmpl.TotalServiceNum, err = commonrepo.NewServiceColl().Count(tmpTmpl.ProductName) - if err != nil { - errorList = multierror.Append(errorList, err) - return - } - - tmpTmpl.TotalEnvNum, err = commonrepo.NewProductColl().Count(tmpTmpl.ProductName) - if err != nil { - errorList = multierror.Append(errorList, err) - return - } - - mu.Lock() - resp = append(resp, tmpTmpl) - mu.Unlock() - }(tmpl) - } - wg.Wait() - if errorList.ErrorOrNil() != nil { - return resp, errorList - } - - return resp, nil -} - func ListOpenSourceProduct(log *zap.SugaredLogger) ([]*template.Product, error) { opt := &templaterepo.ProductListOpt{ IsOpensource: "true", @@ -331,6 +129,14 @@ func CreateProductTemplate(args *template.Product, log *zap.SugaredLogger) (err return } +func UpdateServiceOrchestration(name string, services [][]string, updateBy string, log *zap.SugaredLogger) (err error) { + if err = templaterepo.NewProductColl().UpdateServiceOrchestration(name, services, updateBy); err != nil { + log.Errorf("UpdateChoreographyService error: %v", err) + return e.ErrUpdateProduct.AddErr(err) + } + return nil +} + // UpdateProductTemplate 更新产品模板 func UpdateProductTemplate(name string, args *template.Product, log *zap.SugaredLogger) (err error) { kvs := args.Vars @@ -401,31 +207,12 @@ func UpdateProductTmplStatus(productName, onboardingStatus string, log *zap.Suga return nil } -func UpdateServiceOrchestration(username, name string, services [][]string, log *zap.SugaredLogger) error { - if err := templaterepo.NewProductColl().UpdateServiceOrder(&templaterepo.ProductArgs{ - ProductName: name, - Services: services, - UpdateBy: username, - }); err != nil { - log.Errorf("failed to update service order,err:%s", err) - return e.ErrUpdateProduct.AddDesc("failed to update service order") - } - return nil -} - // UpdateProject 更新项目 func UpdateProject(name string, args *template.Product, log *zap.SugaredLogger) (err error) { err = validateRule(args.CustomImageRule, args.CustomTarRule) if err != nil { return e.ErrInvalidParam.AddDesc(err.Error()) } - poetryCtl := poetry.New(config.PoetryAPIServer(), config.PoetryAPIRootKey()) - //创建团建和项目之间的关系 - _, err = poetryCtl.AddProductTeam(args.ProductName, args.TeamID, args.UserIDs, log) - if err != nil { - log.Errorf("Project.Create AddProductTeam error: %v", err) - return e.ErrUpdateProduct.AddDesc(err.Error()) - } err = templaterepo.NewProductColl().Update(name, args) if err != nil { @@ -526,14 +313,6 @@ func DeleteProductTemplate(userName, productName, requestID string, log *zap.Sug } } - poetryCtl := poetry.New(config.PoetryAPIServer(), config.PoetryAPIRootKey()) - - //删除项目团队信息 - if err = poetryCtl.DeleteProductTeam(productName, log); err != nil { - log.Errorf("productTeam.Delete error: %v", err) - return e.ErrDeleteProduct - } - envs, _ := commonrepo.NewProductColl().List(&commonrepo.ProductListOptions{Name: productName}) for _, env := range envs { if err = commonrepo.NewProductColl().UpdateStatus(env.EnvName, productName, setting.ProductStatusDeleting); err != nil { @@ -563,12 +342,9 @@ func DeleteProductTemplate(userName, productName, requestID string, log *zap.Sug } //删除自由编排工作流 - features, err := commonservice.GetFeatures(log) - if err != nil { - log.Errorf("DeleteProductTemplate productName %s getFeatures err: %v", productName, err) - } - if strings.Contains(features, string(config.FreestyleType)) { - collieClient := collie.New(config.CollieAPIAddress(), config.PoetryAPIRootKey()) + cl := configclient.New(configbase.ConfigServiceAddress()) + if enable, err := cl.CheckFeature(setting.ModernWorkflowType); err == nil && enable { + collieClient := collie.New(config.CollieAPIAddress()) if err = collieClient.DeleteCIPipelines(productName, log); err != nil { log.Errorf("DeleteProductTemplate Delete productName %s freestyle pipeline err: %v", productName, err) } @@ -626,24 +402,7 @@ func DeleteProductTemplate(userName, productName, requestID string, log *zap.Sug return nil } -func ForkProduct(userID int, username, requestID string, args *template.ForkProject, log *zap.SugaredLogger) error { - poetryClient := poetry.New(config.PoetryAPIServer(), config.PoetryAPIRootKey()) - // first check if the product have contributor role, if not, create one - if !poetryClient.ContributorRoleExist(args.ProductName, log) { - err := poetryClient.CreateContributorRole(args.ProductName, log) - if err != nil { - log.Errorf("Cannot create contributor role for product: %s, the error is: %v", args.ProductName, err) - return e.ErrForkProduct.AddDesc(err.Error()) - } - } - - // Give contributor role to this user - // first look for roleID - roleID := poetryClient.GetContributorRoleID(args.ProductName, log) - if roleID < 0 { - log.Errorf("Failed to get contributor Role ID from poetry client") - return e.ErrForkProduct.AddDesc("Failed to get contributor Role ID from poetry client") - } +func ForkProduct(username, uid, requestID string, args *template.ForkProject, log *zap.SugaredLogger) error { prodTmpl, err := templaterepo.NewProductColl().Find(args.ProductName) if err != nil { @@ -716,24 +475,6 @@ func ForkProduct(userID int, username, requestID string, args *template.ForkProj return e.ErrForkProduct.AddDesc(errMsg) } - userList, _ := poetryClient.ListPermissionUsers(args.ProductName, roleID, poetry.ProjectType, log) - newUserList := append(userList, userID) - err = poetryClient.UpdateUserRole(roleID, poetry.ProjectType, args.ProductName, newUserList, log) - if err != nil { - log.Errorf("Failed to update user role, the error is: %v", err) - return e.ErrForkProduct.AddDesc(fmt.Sprintf("Failed to update user role, the error is: %v", err)) - } - - err = poetryClient.CreateUserEnvPermission(&poetry.UserEnvPermission{ - UserID: userID, - ProductName: args.ProductName, - EnvName: args.EnvName, - PermissionUUIDs: []string{permission.TestEnvListUUID, permission.TestEnvManageUUID}, - }) - if err != nil { - return e.ErrForkProduct.AddDesc(fmt.Sprintf("Failed to create env permission for user: %s", username)) - } - workflowPreset, err := workflowservice.PreSetWorkflow(args.ProductName, log) if err != nil { errMsg := fmt.Sprintf("Failed to get workflow preset info, the error is: %+v", err) @@ -774,18 +515,21 @@ func ForkProduct(userID int, username, requestID string, args *template.ForkProj CreateBy: username, UpdateBy: username, } + err = policy.NewDefault().CreateOrUpdateRoleBinding(args.ProductName, &policy.RoleBinding{ + Name: fmt.Sprintf(setting.RoleBindingNameFmt, args.ProductName, uid, args.ProductName), + UID: uid, + Role: string(setting.Contributor), + Public: true, + }) + if err != nil { + log.Error("rolebinding error") + return e.ErrForkProduct + } return workflowservice.CreateWorkflow(workflowArgs, log) } -func UnForkProduct(userID int, username, productName, workflowName, envName, requestID string, log *zap.SugaredLogger) error { - poetryClient := poetry.New(config.PoetryAPIServer(), config.PoetryAPIRootKey()) - if userEnvPermissions, _ := poetryClient.ListUserEnvPermission(productName, userID, log); len(userEnvPermissions) > 0 { - if err := poetryClient.DeleteUserEnvPermission(productName, username, userID, log); err != nil { - return e.ErrUnForkProduct.AddDesc(fmt.Sprintf("Failed to delete env permission for userID: %d, env: %s, productName: %s, the error is: %+v", userID, username, productName, err)) - } - } - +func UnForkProduct(userID string, username, productName, workflowName, envName, requestID string, log *zap.SugaredLogger) error { if _, err := workflowservice.FindWorkflow(workflowName, log); err == nil { err = commonservice.DeleteWorkflow(workflowName, requestID, false, log) if err != nil { @@ -794,14 +538,12 @@ func UnForkProduct(userID int, username, productName, workflowName, envName, req } } - if roleID := poetryClient.GetContributorRoleID(productName, log); roleID > 0 { - err := poetryClient.DeleteUserRole(roleID, poetry.ProjectType, userID, productName, log) - if err != nil { - log.Errorf("Failed to Delete user from role candidate, the error is: %v", err) - return e.ErrUnForkProduct.AddDesc(err.Error()) - } + policyClient := policy.New() + err := policyClient.DeleteRoleBinding(fmt.Sprintf(setting.RoleBindingNameFmt, userID, setting.Contributor, productName), productName) + if err != nil { + log.Error("rolebinding delete error") + return e.ErrForkProduct } - if err := commonservice.DeleteProduct(username, envName, productName, requestID, log); err != nil { _, messageMap := e.ErrorMessage(err) if description, ok := messageMap["description"]; ok { @@ -925,33 +667,17 @@ type ContainerInfo struct { Label string `bson:"label" json:"label"` } -func ListTemplatesHierachy(userName string, userID int, superUser bool, log *zap.SugaredLogger) ([]*ProductInfo, error) { +func ListTemplatesHierachy(userName string, log *zap.SugaredLogger) ([]*ProductInfo, error) { var ( err error resp = make([]*ProductInfo, 0) productTmpls = make([]*template.Product, 0) ) - if superUser { - productTmpls, err = templaterepo.NewProductColl().List() - if err != nil { - log.Errorf("[%s] ProductTmpl.List error: %v", userName, err) - return nil, e.ErrListProducts.AddDesc(err.Error()) - } - } else { - productNameMap, err := poetry.New(config.PoetryAPIServer(), config.PoetryAPIRootKey()).GetUserProject(userID, log) - if err != nil { - log.Errorf("ProfuctTmpl.List GetUserProject error: %v", err) - return resp, e.ErrListProducts.AddDesc(err.Error()) - } - for productName := range productNameMap { - product, err := templaterepo.NewProductColl().Find(productName) - if err != nil { - log.Errorf("ProfuctTmpl.List error: %v", err) - return resp, e.ErrListProducts.AddDesc(err.Error()) - } - productTmpls = append(productTmpls, product) - } + productTmpls, err = templaterepo.NewProductColl().List() + if err != nil { + log.Errorf("[%s] ProductTmpl.List error: %v", userName, err) + return nil, e.ErrListProducts.AddDesc(err.Error()) } for _, productTmpl := range productTmpls { diff --git a/pkg/microservice/aslan/core/project/service/project.go b/pkg/microservice/aslan/core/project/service/project.go index 7da39d9545237a7b6c3c4d3c36eb7db5e0df6bf4..4c9e1fb92efc8a573b1f5ed04dc30bf9629c8ca6 100644 --- a/pkg/microservice/aslan/core/project/service/project.go +++ b/pkg/microservice/aslan/core/project/service/project.go @@ -17,8 +17,6 @@ limitations under the License. package service import ( - "fmt" - "go.uber.org/zap" "k8s.io/apimachinery/pkg/util/sets" @@ -35,12 +33,20 @@ const ( ) type ProjectListOptions struct { - IgnoreNoEnvs bool - Verbosity QueryVerbosity + IgnoreNoEnvs bool + IgnoreNoVersions bool + Verbosity QueryVerbosity + Names []string } type ProjectDetailedRepresentation struct { *ProjectBriefRepresentation + Alias string `json:"alias"` + Desc string `json:"desc"` + UpdatedAt int64 `json:"updatedAt"` + UpdatedBy string `json:"updatedBy"` + Onboard bool `json:"onboard"` + Public bool `json:"public"` } type ProjectBriefRepresentation struct { @@ -55,7 +61,7 @@ type ProjectMinimalRepresentation struct { func ListProjects(opts *ProjectListOptions, logger *zap.SugaredLogger) (interface{}, error) { switch opts.Verbosity { case VerbosityDetailed: - return nil, fmt.Errorf("not Implemented") + return listDetailedProjectInfos(opts, logger) case VerbosityBrief: return listBriefProjectInfos(opts, logger) case VerbosityMinimal: @@ -65,47 +71,89 @@ func ListProjects(opts *ProjectListOptions, logger *zap.SugaredLogger) (interfac } } +func listDetailedProjectInfos(opts *ProjectListOptions, logger *zap.SugaredLogger) ([]*ProjectDetailedRepresentation, error) { + var res []*ProjectDetailedRepresentation + + nameSet, nameMap, err := getProjects(opts) + if err != nil { + logger.Errorf("Failed to list projects, err: %s", err) + return nil, err + } + + nameWithEnvSet, nameWithEnvMap, err := getProjectsWithEnvs(opts) + if err != nil { + logger.Errorf("Failed to list projects, err: %s", err) + return nil, err + } + + desiredSet := nameSet + if opts.IgnoreNoEnvs { + desiredSet = nameSet.Intersection(nameWithEnvSet) + } + + for name := range desiredSet { + info := nameMap[name] + res = append(res, &ProjectDetailedRepresentation{ + ProjectBriefRepresentation: &ProjectBriefRepresentation{ + ProjectMinimalRepresentation: &ProjectMinimalRepresentation{Name: name}, + Envs: nameWithEnvMap[name], + }, + Alias: info.Alias, + Desc: info.Desc, + UpdatedAt: info.UpdatedAt, + UpdatedBy: info.UpdatedBy, + Onboard: info.OnboardStatus != 0, + Public: info.Public, + }) + } + + return res, nil +} + func listBriefProjectInfos(opts *ProjectListOptions, logger *zap.SugaredLogger) ([]*ProjectBriefRepresentation, error) { var res []*ProjectBriefRepresentation - names, err := templaterepo.NewProductColl().ListNames() + nameSet, _, err := getProjects(opts) if err != nil { - logger.Errorf("Failed to list project names, err: %s", err) + logger.Errorf("Failed to list projects, err: %s", err) return nil, err } - nameWithEnvs, err := mongodb.NewProductColl().ListProjects() + nameWithEnvSet, nameWithEnvMap, err := getProjectsWithEnvs(opts) if err != nil { logger.Errorf("Failed to list projects, err: %s", err) return nil, err } - nameSet := sets.NewString() - for _, name := range names { - nameSet.Insert(name) + desiredSet := nameSet + if opts.IgnoreNoEnvs { + desiredSet = nameSet.Intersection(nameWithEnvSet) } - nameWithEnvsSet := sets.NewString() - for _, nameWithEnv := range nameWithEnvs { - // nameWithEnvs may contain projects which are already deleted. - if !nameSet.Has(nameWithEnv.ProjectName) { - continue - } + for name := range desiredSet { res = append(res, &ProjectBriefRepresentation{ - ProjectMinimalRepresentation: &ProjectMinimalRepresentation{Name: nameWithEnv.ProjectName}, - Envs: nameWithEnv.Envs, + ProjectMinimalRepresentation: &ProjectMinimalRepresentation{Name: name}, + Envs: nameWithEnvMap[name], }) - nameWithEnvsSet.Insert(nameWithEnv.ProjectName) } - if !opts.IgnoreNoEnvs { - for _, name := range names { - if !nameWithEnvsSet.Has(name) { - res = append(res, &ProjectBriefRepresentation{ - ProjectMinimalRepresentation: &ProjectMinimalRepresentation{Name: name}, - }) - } + return res, nil +} + +func listMinimalProjectInfoForDelivery(_ *ProjectListOptions, nameSet sets.String, logger *zap.SugaredLogger) ([]*ProjectMinimalRepresentation, error) { + var res []*ProjectMinimalRepresentation + namesWithDelivery, err := mongodb.NewDeliveryVersionColl().FindProducts() + if err != nil { + logger.Errorf("Failed to list projects by delivery, err: %s", err) + return nil, err + } + + for _, name := range namesWithDelivery { + // namesWithDelivery may contain projects which are already deleted. + if !nameSet.Has(name) { + continue } + res = append(res, &ProjectMinimalRepresentation{Name: name}) } return res, nil @@ -113,13 +161,17 @@ func listBriefProjectInfos(opts *ProjectListOptions, logger *zap.SugaredLogger) func listMinimalProjectInfos(opts *ProjectListOptions, logger *zap.SugaredLogger) ([]*ProjectMinimalRepresentation, error) { var res []*ProjectMinimalRepresentation - - names, err := templaterepo.NewProductColl().ListNames() + names, err := templaterepo.NewProductColl().ListNames(opts.Names) if err != nil { logger.Errorf("Failed to list project names, err: %s", err) return nil, err } + nameSet := sets.NewString(names...) + if opts.IgnoreNoVersions { + return listMinimalProjectInfoForDelivery(opts, nameSet, logger) + } + if !opts.IgnoreNoEnvs { for _, name := range names { res = append(res, &ProjectMinimalRepresentation{Name: name}) @@ -128,24 +180,51 @@ func listMinimalProjectInfos(opts *ProjectListOptions, logger *zap.SugaredLogger return res, nil } - nameSet := sets.NewString() - for _, name := range names { - nameSet.Insert(name) - } - - nameWithEnvs, err := mongodb.NewProductColl().ListProjects() + nameWithEnvSet, _, err := getProjectsWithEnvs(opts) if err != nil { logger.Errorf("Failed to list projects, err: %s", err) return nil, err } - for _, nameWithEnv := range nameWithEnvs { + for name := range nameWithEnvSet { // nameWithEnvs may contain projects which are already deleted. - if !nameSet.Has(nameWithEnv.ProjectName) { + if !nameSet.Has(name) { continue } - res = append(res, &ProjectMinimalRepresentation{Name: nameWithEnv.ProjectName}) + res = append(res, &ProjectMinimalRepresentation{Name: name}) } return res, nil } + +func getProjectsWithEnvs(opts *ProjectListOptions) (sets.String, map[string][]string, error) { + nameWithEnvs, err := mongodb.NewProductColl().ListProjectsInNames(opts.Names) + if err != nil { + return nil, nil, err + } + + nameSet := sets.NewString() + nameMap := make(map[string][]string) + for _, nameWithEnv := range nameWithEnvs { + nameSet.Insert(nameWithEnv.ProjectName) + nameMap[nameWithEnv.ProjectName] = nameWithEnv.Envs + } + + return nameSet, nameMap, nil +} + +func getProjects(opts *ProjectListOptions) (sets.String, map[string]*templaterepo.ProjectInfo, error) { + res, err := templaterepo.NewProductColl().ListProjectBriefs(opts.Names) + if err != nil { + return nil, nil, err + } + + nameSet := sets.NewString() + nameMap := make(map[string]*templaterepo.ProjectInfo) + for _, r := range res { + nameSet.Insert(r.Name) + nameMap[r.Name] = r + } + + return nameSet, nameMap, nil +} diff --git a/pkg/microservice/aslan/core/service.go b/pkg/microservice/aslan/core/service.go index eeccff7dc1d44be8e893e9caab27b1f10af08e2c..35d9c1f1aeb26446f6c65d5406aaf77b85926c67 100644 --- a/pkg/microservice/aslan/core/service.go +++ b/pkg/microservice/aslan/core/service.go @@ -30,12 +30,18 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb/template" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/nsq" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/webhook" + deliveryhandler "github.com/koderover/zadig/pkg/microservice/aslan/core/delivery/handler" + environmenthandler "github.com/koderover/zadig/pkg/microservice/aslan/core/environment/handler" environmentservice "github.com/koderover/zadig/pkg/microservice/aslan/core/environment/service" + projecthandler "github.com/koderover/zadig/pkg/microservice/aslan/core/project/handler" systemrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/system/repository/mongodb" systemservice "github.com/koderover/zadig/pkg/microservice/aslan/core/system/service" templaterepo "github.com/koderover/zadig/pkg/microservice/aslan/core/templatestore/repository/mongodb" + workflowhandler "github.com/koderover/zadig/pkg/microservice/aslan/core/workflow/handler" workflowservice "github.com/koderover/zadig/pkg/microservice/aslan/core/workflow/service/workflow" + testinghandler "github.com/koderover/zadig/pkg/microservice/aslan/core/workflow/testing/handler" "github.com/koderover/zadig/pkg/setting" + "github.com/koderover/zadig/pkg/shared/client/policy" "github.com/koderover/zadig/pkg/tool/log" mongotool "github.com/koderover/zadig/pkg/tool/mongo" ) @@ -44,6 +50,10 @@ const ( webhookController = iota ) +type policyGetter interface { + Policies() *policy.Policy +} + type Controller interface { Run(workers int, stopCh <-chan struct{}) } @@ -68,6 +78,24 @@ func StartControllers(stopCh <-chan struct{}) { wg.Wait() } +func registerPolicies() { + policyClient := policy.New() + + for _, r := range []policyGetter{ + new(workflowhandler.Router), + new(environmenthandler.Router), + new(projecthandler.Router), + new(testinghandler.Router), + new(deliveryhandler.Router), + } { + err := policyClient.CreateOrUpdatePolicy(r.Policies()) + if err != nil { + // should not have happened here + log.DPanic(err) + } + } +} + func Start(ctx context.Context) { log.Init(&log.Config{ Level: commonconfig.LogLevel(), @@ -88,6 +116,8 @@ func Start(ctx context.Context) { environmentservice.ResetProductsStatus() + registerPolicies() + go StartControllers(ctx.Done()) } @@ -170,6 +200,10 @@ func initDatabase() { commonrepo.NewWorkflowStatColl(), commonrepo.NewWorkLoadsStatColl(), commonrepo.NewServicesInExternalEnvColl(), + commonrepo.NewExternalLinkColl(), + + templaterepo.NewChartColl(), + templaterepo.NewDockerfileTemplateColl(), templaterepo.NewChartColl(), templaterepo.NewDockerfileTemplateColl(), diff --git a/pkg/microservice/aslan/core/service/handler/helm.go b/pkg/microservice/aslan/core/service/handler/helm.go index 13393399343e3756ad3f98d1bacbb0015612db9b..0573b0989f9aab1bdee972c218cba3452efe9c30 100644 --- a/pkg/microservice/aslan/core/service/handler/helm.go +++ b/pkg/microservice/aslan/core/service/handler/helm.go @@ -64,9 +64,9 @@ func CreateOrUpdateHelmService(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("invalid HelmService json args") return } - args.CreatedBy = ctx.Username + args.CreatedBy = ctx.UserName - ctx.Resp, ctx.Err = svcservice.CreateOrUpdateHelmService(c.Query("productName"), args, ctx.Logger) + ctx.Resp, ctx.Err = svcservice.CreateOrUpdateHelmService(c.Query("projectName"), args, ctx.Logger) } func CreateOrUpdateBulkHelmServices(c *gin.Context) { @@ -78,9 +78,9 @@ func CreateOrUpdateBulkHelmServices(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("invalid HelmService json args") return } - args.CreatedBy = ctx.Username + args.CreatedBy = ctx.UserName - ctx.Resp, ctx.Err = svcservice.CreateOrUpdateBulkHelmService(c.Query("productName"), args, ctx.Logger) + ctx.Resp, ctx.Err = svcservice.CreateOrUpdateBulkHelmService(c.Query("projectName"), args, ctx.Logger) } func UpdateHelmService(c *gin.Context) { @@ -92,7 +92,7 @@ func UpdateHelmService(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("invalid HelmServiceArgs json args") return } - args.CreateBy = ctx.Username + args.CreateBy = ctx.UserName args.ProductName = c.Param("productName") ctx.Err = svcservice.UpdateHelmService(args, ctx.Logger) diff --git a/pkg/microservice/aslan/core/service/handler/loader.go b/pkg/microservice/aslan/core/service/handler/loader.go index 7a9e6406adf962c4a468b83ac34cac628b5ccb6b..00b5675f7a3a1c6c38b178e9359ea4a9164e821a 100644 --- a/pkg/microservice/aslan/core/service/handler/loader.go +++ b/pkg/microservice/aslan/core/service/handler/loader.go @@ -85,7 +85,7 @@ func LoadServiceTemplate(c *gin.Context) { remoteName := c.Query("remoteName") repoOwner := c.Query("repoOwner") - ctx.Err = svcservice.LoadServiceFromCodeHost(ctx.Username, codehostID, repoOwner, repoName, repoUUID, branchName, remoteName, args, ctx.Logger) + ctx.Err = svcservice.LoadServiceFromCodeHost(ctx.UserName, codehostID, repoOwner, repoName, repoUUID, branchName, remoteName, args, ctx.Logger) } // ValidateServiceUpdate ... diff --git a/pkg/microservice/aslan/core/service/handler/router.go b/pkg/microservice/aslan/core/service/handler/router.go index 16ada899657047d8703574a3102880e834534718..e83c94033b300095bd5f3925afd992429c6c47f8 100644 --- a/pkg/microservice/aslan/core/service/handler/router.go +++ b/pkg/microservice/aslan/core/service/handler/router.go @@ -18,15 +18,13 @@ package handler import ( "github.com/gin-gonic/gin" + gin2 "github.com/koderover/zadig/pkg/middleware/gin" - "github.com/koderover/zadig/pkg/types/permission" ) type Router struct{} func (*Router) Inject(router *gin.RouterGroup) { - router.Use(gin2.Auth()) - harbor := router.Group("harbor") { harbor.GET("/project", ListHarborProjects) @@ -41,9 +39,9 @@ func (*Router) Inject(router *gin.RouterGroup) { helm.GET("/:productName/:serviceName/serviceModule", GetHelmServiceModule) helm.GET("/:productName/:serviceName/filePath", GetFilePath) helm.GET("/:productName/:serviceName/fileContent", GetFileContent) - helm.POST("/services", gin2.IsHavePermission([]string{permission.ServiceTemplateManageUUID}, permission.ParamType), CreateOrUpdateHelmService) - helm.POST("/services/bulk", gin2.IsHavePermission([]string{permission.ServiceTemplateManageUUID}, permission.ParamType), CreateOrUpdateBulkHelmServices) - helm.PUT("/:productName", gin2.IsHavePermission([]string{permission.ServiceTemplateManageUUID}, permission.ParamType), UpdateHelmService) + helm.POST("/services", CreateOrUpdateHelmService) + helm.POST("/services/bulk", CreateOrUpdateBulkHelmServices) + helm.PUT("/:productName", UpdateHelmService) } k8s := router.Group("services") @@ -51,10 +49,10 @@ func (*Router) Inject(router *gin.RouterGroup) { k8s.GET("", ListServiceTemplate) k8s.GET("/:name/:type", GetServiceTemplate) k8s.GET("/:name", GetServiceTemplateOption) - k8s.POST("", GetServiceTemplateProductName, gin2.IsHavePermission([]string{permission.ServiceTemplateManageUUID}, permission.ContextKeyType), gin2.UpdateOperationLogStatus, CreateServiceTemplate) - k8s.PUT("", GetServiceTemplateObjectProductName, gin2.IsHavePermission([]string{permission.ServiceTemplateManageUUID}, permission.ContextKeyType), gin2.UpdateOperationLogStatus, UpdateServiceTemplate) + k8s.POST("", GetServiceTemplateProductName, gin2.UpdateOperationLogStatus, CreateServiceTemplate) + k8s.PUT("", GetServiceTemplateObjectProductName, gin2.UpdateOperationLogStatus, UpdateServiceTemplate) k8s.PUT("/yaml/validator", YamlValidator) - k8s.DELETE("/:name/:type", gin2.IsHavePermission([]string{permission.ServiceTemplateDeleteUUID}, permission.QueryType), gin2.UpdateOperationLogStatus, DeleteServiceTemplate) + k8s.DELETE("/:name/:type", gin2.UpdateOperationLogStatus, DeleteServiceTemplate) k8s.GET("/:name/:type/ports", ListServicePort) } @@ -79,8 +77,8 @@ func (*Router) Inject(router *gin.RouterGroup) { pm := router.Group("pm") { - pm.POST("/:productName", gin2.IsHavePermission([]string{permission.ServiceTemplateManageUUID}, permission.ParamType), gin2.UpdateOperationLogStatus, CreatePMService) - pm.PUT("/:productName", gin2.IsHavePermission([]string{permission.ServiceTemplateManageUUID}, permission.ParamType), gin2.UpdateOperationLogStatus, UpdatePmServiceTemplate) + pm.POST("/:productName", gin2.UpdateOperationLogStatus, CreatePMService) + pm.PUT("/:productName", gin2.UpdateOperationLogStatus, UpdatePmServiceTemplate) } template := router.Group("template") diff --git a/pkg/microservice/aslan/core/service/handler/service.go b/pkg/microservice/aslan/core/service/handler/service.go index 683f74aa938fac90ebf21ac4af662ad82ba45b1f..cf7475516bd2874a32ef8a36fa1e5fa1fa1703c0 100644 --- a/pkg/microservice/aslan/core/service/handler/service.go +++ b/pkg/microservice/aslan/core/service/handler/service.go @@ -39,13 +39,13 @@ func ListServiceTemplate(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - ctx.Resp, ctx.Err = commonservice.ListServiceTemplate(c.Query("productName"), ctx.Logger) + ctx.Resp, ctx.Err = commonservice.ListServiceTemplate(c.Query("projectName"), ctx.Logger) } func ListWorkloadTemplate(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - ctx.Resp, ctx.Err = commonservice.ListWorkloadTemplate(c.Query("productName"), c.Query("env"), ctx.Logger) + ctx.Resp, ctx.Err = commonservice.ListWorkloadTemplate(c.Query("projectName"), c.Query("env"), ctx.Logger) } func GetServiceTemplate(c *gin.Context) { @@ -56,7 +56,7 @@ func GetServiceTemplate(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("invalid revision number") return } - ctx.Resp, ctx.Err = commonservice.GetServiceTemplate(c.Param("name"), c.Param("type"), c.Query("productName"), setting.ProductStatusDeleting, revision, ctx.Logger) + ctx.Resp, ctx.Err = commonservice.GetServiceTemplate(c.Param("name"), c.Param("type"), c.Query("projectName"), setting.ProductStatusDeleting, revision, ctx.Logger) } func GetServiceTemplateOption(c *gin.Context) { @@ -67,7 +67,7 @@ func GetServiceTemplateOption(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("invalid revision number") return } - ctx.Resp, ctx.Err = svcservice.GetServiceTemplateOption(c.Param("name"), c.Query("productName"), revision, ctx.Logger) + ctx.Resp, ctx.Err = svcservice.GetServiceTemplateOption(c.Param("name"), c.Query("projectName"), revision, ctx.Logger) } func CreateServiceTemplate(c *gin.Context) { @@ -82,16 +82,16 @@ func CreateServiceTemplate(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("CreateServiceTemplate json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, args.ProductName, "新增", "项目管理-服务", fmt.Sprintf("服务名称:%s,版本号:%d", args.ServiceName, args.Revision), string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, args.ProductName, "新增", "项目管理-服务", fmt.Sprintf("服务名称:%s,版本号:%d", args.ServiceName, args.Revision), string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) if err := c.BindJSON(args); err != nil { ctx.Err = e.ErrInvalidParam.AddDesc("invalid ServiceTmpl json args") return } - args.CreateBy = ctx.Username + args.CreateBy = ctx.UserName - ctx.Resp, ctx.Err = svcservice.CreateServiceTemplate(ctx.Username, args, ctx.Logger) + ctx.Resp, ctx.Err = svcservice.CreateServiceTemplate(ctx.UserName, args, ctx.Logger) } func UpdateServiceTemplate(c *gin.Context) { @@ -107,10 +107,10 @@ func UpdateServiceTemplate(c *gin.Context) { log.Errorf("UpdateServiceTemplate json.Unmarshal err : %v", err) } if args.Username != "system" { - internalhandler.InsertOperationLog(c, ctx.Username, args.ProductName, "更新", "项目管理-服务", fmt.Sprintf("服务名称:%s,版本号:%d", args.ServiceName, args.Revision), "", ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, args.ProductName, "更新", "项目管理-服务", fmt.Sprintf("服务名称:%s,版本号:%d", args.ServiceName, args.Revision), "", ctx.Logger) } c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) - args.Username = ctx.Username + args.Username = ctx.UserName ctx.Err = svcservice.UpdateServiceTemplate(args) } @@ -139,9 +139,9 @@ func DeleteServiceTemplate(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - internalhandler.InsertOperationLog(c, ctx.Username, c.Query("productName"), "删除", "项目管理-服务", c.Param("name"), "", ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, c.Query("projectName"), "删除", "项目管理-服务", c.Param("name"), "", ctx.Logger) - ctx.Err = svcservice.DeleteServiceTemplate(c.Param("name"), c.Param("type"), c.Query("productName"), c.DefaultQuery("isEnvTemplate", "true"), c.DefaultQuery("visibility", "public"), ctx.Logger) + ctx.Err = svcservice.DeleteServiceTemplate(c.Param("name"), c.Param("type"), c.Query("projectName"), c.DefaultQuery("isEnvTemplate", "true"), c.DefaultQuery("visibility", "public"), ctx.Logger) } func ListServicePort(c *gin.Context) { @@ -152,7 +152,7 @@ func ListServicePort(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("invalid revision number") return } - ctx.Resp, ctx.Err = svcservice.ListServicePort(c.Param("name"), c.Param("type"), c.Query("productName"), setting.ProductStatusDeleting, revision, ctx.Logger) + ctx.Resp, ctx.Err = svcservice.ListServicePort(c.Param("name"), c.Param("type"), c.Query("projectName"), setting.ProductStatusDeleting, revision, ctx.Logger) } type K8sWorkloadsArgs struct { @@ -172,13 +172,13 @@ func UpdateWorkloads(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("invalid UpdateWorkloadsArgs") return } - product := c.Query("productName") + product := c.Query("projectName") env := c.Query("env") if product == "" || env == "" { ctx.Err = e.ErrInvalidParam return } - ctx.Err = service.UpdateWorkloads(c, ctx.RequestID, ctx.Username, product, env, *args, ctx.Logger) + ctx.Err = service.UpdateWorkloads(c, ctx.RequestID, ctx.UserName, product, env, *args, ctx.Logger) } func CreateK8sWorkloads(c *gin.Context) { @@ -190,14 +190,14 @@ func CreateK8sWorkloads(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("invalid K8sWorkloadsArgs args") return } - ctx.Err = svcservice.CreateK8sWorkLoads(c, ctx.RequestID, ctx.Username, args.ProductName, args.WorkLoads, args.ClusterID, args.Namespace, args.EnvName, ctx.Logger) + ctx.Err = svcservice.CreateK8sWorkLoads(c, ctx.RequestID, ctx.UserName, args.ProductName, args.WorkLoads, args.ClusterID, args.Namespace, args.EnvName, ctx.Logger) } func ListAvailablePublicServices(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - ctx.Resp, ctx.Err = svcservice.ListAvailablePublicServices(c.Query("productName"), ctx.Logger) + ctx.Resp, ctx.Err = svcservice.ListAvailablePublicServices(c.Query("projectName"), ctx.Logger) } func GetServiceTemplateProductName(c *gin.Context) { @@ -243,7 +243,7 @@ func CreatePMService(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("CreatePMService json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, c.Param("productName"), "新增", "项目管理-物理机部署服务", fmt.Sprintf("服务名称:%s,版本号:%d", args.ServiceTmplObject.ServiceName, args.ServiceTmplObject.Revision), string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, c.Param("productName"), "新增", "项目管理-物理机部署服务", fmt.Sprintf("服务名称:%s,版本号:%d", args.ServiceTmplObject.ServiceName, args.ServiceTmplObject.Revision), string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) if err := c.BindJSON(args); err != nil { @@ -280,7 +280,7 @@ func CreatePMService(c *gin.Context) { } } - ctx.Err = svcservice.CreatePMService(ctx.Username, args, ctx.Logger) + ctx.Err = svcservice.CreatePMService(ctx.UserName, args, ctx.Logger) } func UpdatePmServiceTemplate(c *gin.Context) { @@ -295,7 +295,7 @@ func UpdatePmServiceTemplate(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("UpdatePmServiceTemplate json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, c.Param("productName"), "更新", "项目管理-主机服务", fmt.Sprintf("服务名称:%s,版本号:%d", args.ServiceTmplObject.ServiceName, args.ServiceTmplObject.Revision), "", ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, c.Param("productName"), "更新", "项目管理-主机服务", fmt.Sprintf("服务名称:%s,版本号:%d", args.ServiceTmplObject.ServiceName, args.ServiceTmplObject.Revision), "", ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) for _, heathCheck := range args.ServiceTmplObject.HealthChecks { @@ -322,5 +322,5 @@ func UpdatePmServiceTemplate(c *gin.Context) { } } } - ctx.Err = commonservice.UpdatePmServiceTemplate(ctx.Username, args, ctx.Logger) + ctx.Err = commonservice.UpdatePmServiceTemplate(ctx.UserName, args, ctx.Logger) } diff --git a/pkg/microservice/aslan/core/service/handler/yaml_template.go b/pkg/microservice/aslan/core/service/handler/yaml_template.go index 310fd1c3add2db008757c9ed776562619bb63e78..99fd797ccc7f93dc62344a8bd6673357b611fc78 100644 --- a/pkg/microservice/aslan/core/service/handler/yaml_template.go +++ b/pkg/microservice/aslan/core/service/handler/yaml_template.go @@ -25,7 +25,7 @@ func LoadServiceFromYamlTemplate(c *gin.Context) { return } - ctx.Err = svcservice.LoadServiceFromYamlTemplate(ctx.Username, req.ProjectName, req.ServiceName, req.TemplateID, req.Variables, ctx.Logger) + ctx.Err = svcservice.LoadServiceFromYamlTemplate(ctx.UserName, req.ProjectName, req.ServiceName, req.TemplateID, req.Variables, ctx.Logger) } func ReloadServiceFromYamlTemplate(c *gin.Context) { @@ -38,5 +38,5 @@ func ReloadServiceFromYamlTemplate(c *gin.Context) { return } - ctx.Err = svcservice.ReloadServiceFromYamlTemplate(ctx.Username, req.ProjectName, req.ServiceName, req.Variables, ctx.Logger) + ctx.Err = svcservice.ReloadServiceFromYamlTemplate(ctx.UserName, req.ProjectName, req.ServiceName, req.Variables, ctx.Logger) } diff --git a/pkg/microservice/aslan/core/service/service/helm.go b/pkg/microservice/aslan/core/service/service/helm.go index 50aa6e6905951f58d60df91972fb0f58c97e2ec6..662fe9cb89376589a4798b9cceb2af3d9cb912b1 100644 --- a/pkg/microservice/aslan/core/service/service/helm.go +++ b/pkg/microservice/aslan/core/service/service/helm.go @@ -46,8 +46,7 @@ import ( templatestore "github.com/koderover/zadig/pkg/microservice/aslan/core/templatestore/repository/models" "github.com/koderover/zadig/pkg/microservice/aslan/core/templatestore/repository/mongodb" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/codehost" - "github.com/koderover/zadig/pkg/shared/poetry" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/log" "github.com/koderover/zadig/pkg/types" @@ -346,11 +345,11 @@ func CreateOrUpdateHelmServiceFromChartTemplate(projectName string, args *HelmSe }, nil } -func getCodehostType(repoArgs *CreateFromRepo, repoLink string) (string, *poetry.CodeHost, error) { +func getCodehostType(repoArgs *CreateFromRepo, repoLink string) (string, *systemconfig.CodeHost, error) { if repoLink != "" { return setting.SourceFromPublicRepo, nil, nil } - ch, err := codehost.GetCodeHostInfoByID(repoArgs.CodehostID) + ch, err := systemconfig.New().GetCodeHost(repoArgs.CodehostID) if err != nil { log.Errorf("Failed to get codeHost by id %d, err: %s", repoArgs.CodehostID, err.Error()) return "", ch, err @@ -375,8 +374,6 @@ func CreateOrUpdateHelmServiceFromGitRepo(projectName string, args *HelmServiceC } repoLink = publicArgs.RepoLink - } else { - } response := &BulkHelmServiceCreationResponse{} diff --git a/pkg/microservice/aslan/core/service/service/loader.go b/pkg/microservice/aslan/core/service/service/loader.go index 4c9434afe08db4f3ed367c509167e5d48b560c5c..af9a2bf45abc81f4914f4bd8105754f9264b295d 100644 --- a/pkg/microservice/aslan/core/service/service/loader.go +++ b/pkg/microservice/aslan/core/service/service/loader.go @@ -34,8 +34,7 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/command" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/codehost" - "github.com/koderover/zadig/pkg/shared/poetry" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" "github.com/koderover/zadig/pkg/tool/codehub" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/gerrit" @@ -53,7 +52,7 @@ type LoadServiceReq struct { func PreloadServiceFromCodeHost(codehostID int, repoOwner, repoName, repoUUID, branchName, remoteName, path string, isDir bool, log *zap.SugaredLogger) ([]string, error) { var ret []string - ch, err := codehost.GetCodeHostInfoByID(codehostID) + ch, err := systemconfig.New().GetCodeHost(codehostID) if err != nil { log.Errorf("Failed to load codehost for preload service list, the error is: %+v", err) return nil, e.ErrPreloadServiceTemplate.AddDesc(err.Error()) @@ -74,7 +73,7 @@ func PreloadServiceFromCodeHost(codehostID int, repoOwner, repoName, repoUUID, b // LoadServiceFromCodeHost 根据提供的codehost信息加载服务 func LoadServiceFromCodeHost(username string, codehostID int, repoOwner, repoName, repoUUID, branchName, remoteName string, args *LoadServiceReq, log *zap.SugaredLogger) error { - ch, err := codehost.GetCodeHostInfoByID(codehostID) + ch, err := systemconfig.New().GetCodeHost(codehostID) if err != nil { log.Errorf("Failed to load codehost for preload service list, the error is: %+v", err) return e.ErrLoadServiceTemplate.AddDesc(err.Error()) @@ -93,7 +92,7 @@ func LoadServiceFromCodeHost(username string, codehostID int, repoOwner, repoNam // ValidateServiceUpdate 根据服务名和提供的加载信息确认是否可以更新服务加载地址 func ValidateServiceUpdate(codehostID int, serviceName, repoOwner, repoName, repoUUID, branchName, remoteName, path string, isDir bool, log *zap.SugaredLogger) error { - detail, err := codehost.GetCodeHostInfoByID(codehostID) + detail, err := systemconfig.New().GetCodeHost(codehostID) if err != nil { log.Errorf("Failed to load codehost for validate service update, the error is: %+v", err) return e.ErrValidateServiceUpdate.AddDesc(err.Error()) @@ -113,20 +112,12 @@ func ValidateServiceUpdate(codehostID int, serviceName, repoOwner, repoName, rep } // 根据repo信息获取gerrit可以加载的服务列表 -func preloadGerritService(detail *poetry.CodeHost, repoName, branchName, remoteName, loadPath string, isDir bool) ([]string, error) { +func preloadGerritService(detail *systemconfig.CodeHost, repoName, branchName, remoteName, loadPath string, isDir bool) ([]string, error) { ret := make([]string, 0) base := path.Join(config.S3StoragePath(), repoName) if _, err := os.Stat(base); os.IsNotExist(err) { - chDetail := &codehost.Detail{ - ID: detail.ID, - Name: "", - Address: detail.Address, - Owner: detail.Namespace, - Source: detail.Type, - OauthToken: detail.AccessToken, - } - err = command.RunGitCmds(chDetail, setting.GerritDefaultOwner, repoName, branchName, remoteName) + err = command.RunGitCmds(detail, setting.GerritDefaultOwner, repoName, branchName, remoteName) if err != nil { return nil, e.ErrPreloadServiceTemplate.AddDesc(err.Error()) } @@ -182,7 +173,7 @@ func preloadGerritService(detail *poetry.CodeHost, repoName, branchName, remoteN } // 根据 repo 信息获取 codehub 可以加载的服务列表 -func preloadCodehubService(detail *poetry.CodeHost, repoName, repoUUID, branchName, path string, isDir bool) ([]string, error) { +func preloadCodehubService(detail *systemconfig.CodeHost, repoName, repoUUID, branchName, path string, isDir bool) ([]string, error) { var ret []string codeHubClient := codehub.NewCodeHubClient(detail.AccessKey, detail.SecretKey, detail.Region) @@ -239,10 +230,10 @@ func preloadCodehubService(detail *poetry.CodeHost, repoName, repoUUID, branchNa } // 根据repo信息从gerrit加载服务 -func loadGerritService(username string, ch *poetry.CodeHost, repoOwner, repoName, branchName, remoteName string, args *LoadServiceReq, log *zap.SugaredLogger) error { +func loadGerritService(username string, ch *systemconfig.CodeHost, repoOwner, repoName, branchName, remoteName string, args *LoadServiceReq, log *zap.SugaredLogger) error { base := path.Join(config.S3StoragePath(), repoName) if _, err := os.Stat(base); os.IsNotExist(err) { - err = command.RunGitCmds(&codehost.Detail{Source: ch.Type, Address: ch.Address, OauthToken: ch.AccessToken}, repoOwner, repoName, branchName, remoteName) + err = command.RunGitCmds(ch, repoOwner, repoName, branchName, remoteName) if err != nil { return e.ErrLoadServiceTemplate.AddDesc(err.Error()) } @@ -378,7 +369,7 @@ func loadServiceFromGerrit(tree []os.FileInfo, id int, username, branchName, loa } // load codehub service -func loadCodehubService(username string, ch *poetry.CodeHost, repoOwner, repoName, repoUUID, branchName string, args *LoadServiceReq, log *zap.SugaredLogger) error { +func loadCodehubService(username string, ch *systemconfig.CodeHost, repoOwner, repoName, repoUUID, branchName string, args *LoadServiceReq, log *zap.SugaredLogger) error { codeHubClient := codehub.NewCodeHubClient(ch.AccessKey, ch.SecretKey, ch.Region) if !args.LoadFromDir { @@ -449,7 +440,7 @@ func loadCodehubService(username string, ch *poetry.CodeHost, repoOwner, repoNam return nil } -func loadServiceFromCodehub(client *codehub.CodeHubClient, tree []*codehub.TreeNode, ch *poetry.CodeHost, username, repoOwner, repoName, repoUUID, branchName, path string, args *LoadServiceReq, log *zap.SugaredLogger) error { +func loadServiceFromCodehub(client *codehub.CodeHubClient, tree []*codehub.TreeNode, ch *systemconfig.CodeHost, username, repoOwner, repoName, repoUUID, branchName, path string, args *LoadServiceReq, log *zap.SugaredLogger) error { pathList := strings.Split(path, "/") var splittedYaml []string serviceName := pathList[len(pathList)-1] @@ -504,7 +495,7 @@ func loadServiceFromCodehub(client *codehub.CodeHubClient, tree []*codehub.TreeN } // 根据github repo决定服务是否可以更新这个repo地址 -func validateServiceUpdateGithub(detail *poetry.CodeHost, serviceName, repoOwner, repoName, branchName, path string, isDir bool) error { +func validateServiceUpdateGithub(detail *systemconfig.CodeHost, serviceName, repoOwner, repoName, branchName, path string, isDir bool) error { ctx := context.Background() tokenSource := oauth2.StaticTokenSource( &oauth2.Token{AccessToken: detail.AccessToken}, @@ -551,7 +542,7 @@ func validateServiceUpdateGithub(detail *poetry.CodeHost, serviceName, repoOwner } // 根据gitlab repo决定服务是否可以更新这个repo地址 -func validateServiceUpdateGitlab(detail *poetry.CodeHost, serviceName, repoOwner, repoName, branchName, path string, isDir bool) error { +func validateServiceUpdateGitlab(detail *systemconfig.CodeHost, serviceName, repoOwner, repoName, branchName, path string, isDir bool) error { repoInfo := fmt.Sprintf("%s/%s", repoOwner, repoName) gitlabClient, err := gitlab.NewOAuthClient(detail.AccessToken, gitlab.WithBaseURL(detail.Address)) @@ -603,18 +594,10 @@ func validateServiceUpdateGitlab(detail *poetry.CodeHost, serviceName, repoOwner } // 根据gerrit repo决定服务是否可以更新这个repo地址 -func validateServiceUpdateGerrit(detail *poetry.CodeHost, serviceName, repoName, branchName, remoteName, loadPath string, isDir bool) error { +func validateServiceUpdateGerrit(detail *systemconfig.CodeHost, serviceName, repoName, branchName, remoteName, loadPath string, isDir bool) error { base := path.Join(config.S3StoragePath(), repoName) if _, err := os.Stat(base); os.IsNotExist(err) { - chDetail := &codehost.Detail{ - ID: detail.ID, - Name: "", - Address: detail.Address, - Owner: detail.Namespace, - Source: detail.Type, - OauthToken: detail.AccessToken, - } - err = command.RunGitCmds(chDetail, setting.GerritDefaultOwner, repoName, branchName, remoteName) + err = command.RunGitCmds(detail, setting.GerritDefaultOwner, repoName, branchName, remoteName) if err != nil { return e.ErrValidateServiceUpdate.AddDesc(err.Error()) } @@ -655,7 +638,7 @@ func validateServiceUpdateGerrit(detail *poetry.CodeHost, serviceName, repoName, return e.ErrValidateServiceUpdate.AddDesc("所选路径中没有yaml,请重新选择") } -func validateServiceUpdateCodehub(detail *poetry.CodeHost, serviceName, repoName, repoUUID, branchName, loadPath string, isDir bool) error { +func validateServiceUpdateCodehub(detail *systemconfig.CodeHost, serviceName, repoName, repoUUID, branchName, loadPath string, isDir bool) error { codeHubClient := codehub.NewCodeHubClient(detail.AccessKey, detail.SecretKey, detail.Region) // 非文件夹情况下直接获取文件信息 if !isDir { diff --git a/pkg/microservice/aslan/core/service/service/new_loader.go b/pkg/microservice/aslan/core/service/service/new_loader.go index 3c2a05765058ae3d81f814b134ea93bf8b56b8bd..181c18e255f25cb31f44740b030c93f26e393462 100644 --- a/pkg/microservice/aslan/core/service/service/new_loader.go +++ b/pkg/microservice/aslan/core/service/service/new_loader.go @@ -30,13 +30,13 @@ import ( githubservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/github" gitlabservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/gitlab" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/poetry" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/log" "github.com/koderover/zadig/pkg/util" ) -func preloadService(ch *poetry.CodeHost, owner, repo, branch, path string, isDir bool, logger *zap.SugaredLogger) ([]string, error) { +func preloadService(ch *systemconfig.CodeHost, owner, repo, branch, path string, isDir bool, logger *zap.SugaredLogger) ([]string, error) { logger.Infof("Preloading service from %s with owner %s, repo %s, branch %s and path %s", ch.Type, owner, repo, branch, path) loader, err := getLoader(ch) @@ -95,7 +95,7 @@ type serviceInfo struct { yamls []string } -func loadService(username string, ch *poetry.CodeHost, owner, repo, branch string, args *LoadServiceReq, logger *zap.SugaredLogger) error { +func loadService(username string, ch *systemconfig.CodeHost, owner, repo, branch string, args *LoadServiceReq, logger *zap.SugaredLogger) error { logger.Infof("Loading service from %s with owner %s, repo %s, branch %s and path %s", ch.Type, owner, repo, branch, args.LoadPath) project, err := templaterepo.NewProductColl().Find(args.ProductName) @@ -236,7 +236,7 @@ type yamlLoader interface { GetTree(owner, repo, path, branch string) ([]*git.TreeNode, error) } -func getLoader(ch *poetry.CodeHost) (yamlLoader, error) { +func getLoader(ch *systemconfig.CodeHost) (yamlLoader, error) { switch ch.Type { case setting.SourceFromGithub: return githubservice.NewClient(ch.AccessToken, config.ProxyHTTPSAddr()), nil diff --git a/pkg/microservice/aslan/core/service/service/service.go b/pkg/microservice/aslan/core/service/service/service.go index 17cf5c53cef058136ac4b093037136c359e4b89b..73c3733f5af93c9c5055625980588b96b2acff8b 100644 --- a/pkg/microservice/aslan/core/service/service/service.go +++ b/pkg/microservice/aslan/core/service/service/service.go @@ -46,7 +46,7 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/microservice/aslan/core/environment/service" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/codehost" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/gerrit" "github.com/koderover/zadig/pkg/tool/httpclient" @@ -437,13 +437,6 @@ func UpdateWorkloads(ctx context.Context, requestID, username, productName, envN } } } - // pre judge workLoads same name - //services, _ := commonrepo.NewServiceColl().ListExternalWorkloadsBy(productName, "") - //for _, v := range services { - // if addString.Has(v.ServiceName) { - // return e.ErrCreateTemplate.AddDesc(fmt.Sprintf("do not support import same service name: %s", v.ServiceName)) - // } - //} for _, v := range args.WorkLoads { if addString.Has(v.Name) { @@ -465,26 +458,38 @@ func UpdateWorkloads(ctx context.Context, requestID, username, productName, envN log.Errorf("failed to list external service, error:%s", err) } - externalEnvServiceM := make(map[string]bool) + externalEnvServiceM := make(map[string]*commonmodels.ServicesInExternalEnv) for _, externalEnvService := range otherExternalEnvServices { - externalEnvServiceM[externalEnvService.ServiceName] = true + externalEnvServiceM[externalEnvService.ServiceName] = externalEnvService } for _, v := range diff { switch v.Operation { // 删除workload的引用 case "delete": - if _, isExist := externalEnvServiceM[v.Name]; !isExist { - err = commonrepo.NewServiceColl().UpdateExternalServicesStatus(v.Name, productName, setting.ProductStatusDeleting, envName) - if err != nil { + if externalService, isExist := externalEnvServiceM[v.Name]; !isExist { + if err = commonrepo.NewServiceColl().UpdateExternalServicesStatus(v.Name, productName, setting.ProductStatusDeleting, envName); err != nil { log.Errorf("UpdateStatus external services error:%s", err) } + } else { + // Update the env name in the service + if err = commonrepo.NewServiceColl().UpdateExternalServiceEnvName(v.Name, productName, externalService.EnvName); err != nil { + log.Errorf("UpdateEnvName external services error:%s", err) + } + // Delete the reference in the original service + if err = commonrepo.NewServicesInExternalEnvColl().Delete(&commonrepo.ServicesInExternalEnvArgs{ + ProductName: externalService.ProductName, + EnvName: externalService.EnvName, + ServiceName: externalService.ServiceName, + }); err != nil { + log.Errorf("delete service in external env envName:%s error:%s", externalService.EnvName, err) + } } if err = commonrepo.NewServicesInExternalEnvColl().Delete(&commonrepo.ServicesInExternalEnvArgs{ ProductName: productName, EnvName: envName, ServiceName: v.Name, }); err != nil { - log.Errorf("delete services in external env error:%s", err) + log.Errorf("delete service in external env envName:%s error:%s", envName, err) } // 添加workload的引用 case "add": @@ -1279,15 +1284,15 @@ func getCronJobContainers(data string) ([]*commonmodels.Container, error) { } func updateGerritWebhookByService(lastService, currentService *commonmodels.Service) error { - var codehostDetail *codehost.Detail + var codehostDetail *systemconfig.CodeHost var err error if lastService != nil && lastService.Source == setting.SourceFromGerrit { - codehostDetail, err = codehost.GetCodehostDetail(lastService.GerritCodeHostID) + codehostDetail, err = systemconfig.New().GetCodeHost(lastService.GerritCodeHostID) if err != nil { log.Errorf("updateGerritWebhookByService GetCodehostDetail err:%v", err) return err } - cl := gerrit.NewHTTPClient(codehostDetail.Address, codehostDetail.OauthToken) + cl := gerrit.NewHTTPClient(codehostDetail.Address, codehostDetail.AccessToken) webhookURLPrefix := fmt.Sprintf("/%s/%s/%s", "a/config/server/webhooks~projects", gerrit.Escape(lastService.GerritRepoName), "remotes") _, _ = cl.Delete(fmt.Sprintf("%s/%s", webhookURLPrefix, gerrit.RemoteName)) _, err = cl.Delete(fmt.Sprintf("%s/%s", webhookURLPrefix, lastService.ServiceName)) @@ -1295,14 +1300,14 @@ func updateGerritWebhookByService(lastService, currentService *commonmodels.Serv log.Errorf("updateGerritWebhookByService deleteGerritWebhook err:%v", err) } } - var detail *codehost.Detail + var detail *systemconfig.CodeHost if lastService.GerritCodeHostID == currentService.GerritCodeHostID && codehostDetail != nil { detail = codehostDetail } else { - detail, _ = codehost.GetCodehostDetail(currentService.GerritCodeHostID) + detail, _ = systemconfig.New().GetCodeHost(currentService.GerritCodeHostID) } - cl := gerrit.NewHTTPClient(detail.Address, detail.OauthToken) + cl := gerrit.NewHTTPClient(detail.Address, detail.AccessToken) webhookURL := fmt.Sprintf("/%s/%s/%s/%s", "a/config/server/webhooks~projects", gerrit.Escape(currentService.GerritRepoName), "remotes", currentService.ServiceName) if _, err := cl.Get(webhookURL); err != nil { log.Errorf("updateGerritWebhookByService getGerritWebhook err:%v", err) @@ -1322,13 +1327,13 @@ func updateGerritWebhookByService(lastService, currentService *commonmodels.Serv } func createGerritWebhookByService(codehostID int, serviceName, repoName, branchName string) error { - detail, err := codehost.GetCodehostDetail(codehostID) + detail, err := systemconfig.New().GetCodeHost(codehostID) if err != nil { log.Errorf("createGerritWebhookByService GetCodehostDetail err:%v", err) return err } - cl := gerrit.NewHTTPClient(detail.Address, detail.OauthToken) + cl := gerrit.NewHTTPClient(detail.Address, detail.AccessToken) webhookURL := fmt.Sprintf("/%s/%s/%s/%s", "a/config/server/webhooks~projects", gerrit.Escape(repoName), "remotes", serviceName) if _, err := cl.Get(webhookURL); err != nil { log.Errorf("createGerritWebhookByService getGerritWebhook err:%v", err) @@ -1347,7 +1352,7 @@ func createGerritWebhookByService(codehostID int, serviceName, repoName, branchN return nil } -func syncGerritLatestCommit(service *commonmodels.Service) (*codehost.Detail, error) { +func syncGerritLatestCommit(service *commonmodels.Service) (*systemconfig.CodeHost, error) { if service.GerritCodeHostID == 0 { return nil, fmt.Errorf("codehostId不能是空的") } @@ -1357,9 +1362,9 @@ func syncGerritLatestCommit(service *commonmodels.Service) (*codehost.Detail, er if service.GerritBranchName == "" { return nil, fmt.Errorf("branchName不能是空的") } - ch, _ := codehost.GetCodehostDetail(service.GerritCodeHostID) + ch, _ := systemconfig.New().GetCodeHost(service.GerritCodeHostID) - gerritCli := gerrit.NewClient(ch.Address, ch.OauthToken) + gerritCli := gerrit.NewClient(ch.Address, ch.AccessToken) commit, err := gerritCli.GetCommitByBranch(service.GerritRepoName, service.GerritBranchName) if err != nil { return nil, err diff --git a/pkg/microservice/aslan/core/setting/handler/router.go b/pkg/microservice/aslan/core/setting/handler/router.go index 2b4eef2e9f36dbdabba0a1857ea5aede9432f4a9..1148a6084b12f3b42d016551a8d929b9cd6a8fed 100644 --- a/pkg/microservice/aslan/core/setting/handler/router.go +++ b/pkg/microservice/aslan/core/setting/handler/router.go @@ -18,15 +18,11 @@ package handler import ( "github.com/gin-gonic/gin" - - gin2 "github.com/koderover/zadig/pkg/middleware/gin" ) type Router struct{} func (*Router) Inject(router *gin.RouterGroup) { - router.Use(gin2.Auth()) - user := router.Group("user") { user.GET("/kube/config", GetUserKubeConfig) diff --git a/pkg/microservice/aslan/core/setting/handler/user.go b/pkg/microservice/aslan/core/setting/handler/user.go index c453d691a39fb127f866adb435e752d968e241b0..0dc66b84ad84ca2accf69f629a2bc549bf6b5c35 100644 --- a/pkg/microservice/aslan/core/setting/handler/user.go +++ b/pkg/microservice/aslan/core/setting/handler/user.go @@ -27,5 +27,5 @@ func GetUserKubeConfig(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - ctx.Resp, ctx.Err = settingservice.GetUserKubeConfig(ctx.User.Name, ctx.User.ID, ctx.User.IsSuperUser, ctx.Logger) + ctx.Resp, ctx.Err = settingservice.GetUserKubeConfig(ctx.UserName, ctx.Logger) } diff --git a/pkg/microservice/aslan/core/setting/service/user.go b/pkg/microservice/aslan/core/setting/service/user.go index 45ef8f90c7353d3ca6657da0ece56be530ff94f2..11eea83a60ca8dad229162c8787acb10ff079669 100644 --- a/pkg/microservice/aslan/core/setting/service/user.go +++ b/pkg/microservice/aslan/core/setting/service/user.go @@ -40,12 +40,10 @@ import ( commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" "github.com/koderover/zadig/pkg/setting" "github.com/koderover/zadig/pkg/shared/kube/wrapper" - "github.com/koderover/zadig/pkg/shared/poetry" e "github.com/koderover/zadig/pkg/tool/errors" krkubeclient "github.com/koderover/zadig/pkg/tool/kube/client" "github.com/koderover/zadig/pkg/tool/kube/getter" "github.com/koderover/zadig/pkg/tool/kube/updater" - "github.com/koderover/zadig/pkg/types/permission" ) type kubeCfgTmplArgs struct { @@ -58,75 +56,23 @@ type kubeCfgTmplArgs struct { ClientKeyBase64 string } -func GetUserKubeConfig(userName string, userID int, superUser bool, log *zap.SugaredLogger) (string, error) { +func GetUserKubeConfig(userName string, log *zap.SugaredLogger) (string, error) { username := strings.ToLower(userName) username = config.NameSpaceRegex.ReplaceAllString(username, "-") var ( - err error - productEnvs = make([]*commonmodels.Product, 0) - productNameMap map[string][]int64 + err error + productEnvs = make([]*commonmodels.Product, 0) ) - if superUser { - productEnvs, err = commonrepo.NewProductColl().List(&commonrepo.ProductListOptions{}) - if err != nil { - log.Errorf("GetUserKubeConfig Collection.Product.List error: %v", err) - return "", e.ErrListProducts.AddDesc(err.Error()) - } - // 只管理同集群的资源,且排除状态为Terminating的namespace - productEnvs = filterProductWithoutExternalCluster(productEnvs) - } else { - //项目下所有公开环境 - publicProducts, err := commonrepo.NewProductColl().List(&commonrepo.ProductListOptions{IsPublic: true}) - if err != nil { - log.Errorf("GetUserKubeConfig Collection.Product.List List product error: %v", err) - return "", e.ErrListProducts.AddDesc(err.Error()) - } - // 只管理同集群的资源,且排除状态为Terminating的namespace - filterPublicProductEnvs := filterProductWithoutExternalCluster(publicProducts) - namespaceSet := sets.NewString() - for _, publicProduct := range filterPublicProductEnvs { - productEnvs = append(productEnvs, publicProduct) - namespaceSet.Insert(publicProduct.Namespace) - } - poetryClient := poetry.New(config.PoetryAPIServer(), config.PoetryAPIRootKey()) - productNameMap, err = poetryClient.GetUserProject(userID, log) - if err != nil { - log.Errorf("GetUserKubeConfig Collection.Product.List GetUserProject error: %v", err) - return "", e.ErrListProducts.AddDesc(err.Error()) - } - for productName, roleIDs := range productNameMap { - //用户关联角色所关联的环境 - for _, roleID := range roleIDs { - if roleID == setting.RoleOwnerID { - tmpProducts, err := commonrepo.NewProductColl().List(&commonrepo.ProductListOptions{Name: productName}) - if err != nil { - log.Errorf("GetUserKubeConfig Collection.Product.List product error: %v", err) - return "", e.ErrListProducts.AddDesc(err.Error()) - } - for _, product := range tmpProducts { - if !namespaceSet.Has(product.Namespace) { - productEnvs = append(productEnvs, product) - } - } - } else { - roleEnvs, err := poetryClient.ListRoleEnvs(productName, "", roleID, log) - if err != nil { - log.Errorf("GetUserKubeConfig Collection.Product.List ListRoleEnvs error: %v", err) - return "", e.ErrListProducts.AddDesc(err.Error()) - } - for _, roleEnv := range roleEnvs { - product, err := commonrepo.NewProductColl().Find(&commonrepo.ProductFindOptions{Name: productName, EnvName: roleEnv.EnvName}) - if err != nil { - log.Errorf("GetUserKubeConfig Collection.Product.List Find product error: %v", err) - return "", e.ErrListProducts.AddDesc(err.Error()) - } - productEnvs = append(productEnvs, product) - } - } - } - } + productEnvs, err = commonrepo.NewProductColl().List(&commonrepo.ProductListOptions{}) + if err != nil { + log.Errorf("GetUserKubeConfig Collection.Product.List error: %v", err) + return "", e.ErrListProducts.AddDesc(err.Error()) } + + // 只管理同集群的资源,且排除状态为Terminating的namespace + productEnvs = filterProductWithoutExternalCluster(productEnvs) + saNamespace := config.Namespace() if err := ensureServiceAccount(saNamespace, username, log); err != nil { return "", err @@ -139,7 +85,6 @@ func GetUserKubeConfig(userName string, userID int, superUser bool, log *zap.Sug ) for _, productEnv := range productEnvs { namespace := productEnv.Namespace - productName := productEnv.ProductName if _, found, err := getter.GetNamespace(namespace, krkubeclient.Client()); err != nil || !found { log.Error(err) @@ -153,7 +98,7 @@ func GetUserKubeConfig(userName string, userID int, superUser bool, log *zap.Sug wg.Done() <-pool }() - if err := ensureUserRole(namespace, username, productName, userID, superUser, log); err != nil { + if err := ensureUserRole(namespace, username, log); err != nil { log.Error(err) errList = multierror.Append(errList, err) } @@ -236,13 +181,9 @@ func ensureServiceAccount(namespace, username string, log *zap.SugaredLogger) er return nil } -func ensureUserRole(namespace, username, productName string, userID int, superUser bool, log *zap.SugaredLogger) error { - poetryClient := poetry.New(config.PoetryAPIServer(), config.PoetryAPIRootKey()) +func ensureUserRole(namespace, username string, _ *zap.SugaredLogger) error { roleName := fmt.Sprintf("%s-role", username) - verbs := []string{"get", "list", "watch"} - if poetryClient.HasOperatePermission(productName, permission.TestEnvManageUUID, userID, superUser, log) { - verbs = []string{"*"} - } + verbs := []string{"*"} role := &rbacv1beta1.Role{ ObjectMeta: metav1.ObjectMeta{ Name: roleName, diff --git a/pkg/microservice/aslan/core/system/handler/announcement.go b/pkg/microservice/aslan/core/system/handler/announcement.go index 739b84cab8f5ca0a2e4a072ec2354bc78340f91c..30227aa79fd4b9aac209eb23c512b7a7583d1c79 100644 --- a/pkg/microservice/aslan/core/system/handler/announcement.go +++ b/pkg/microservice/aslan/core/system/handler/announcement.go @@ -35,7 +35,7 @@ func CreateAnnouncement(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("invalid notify args") return } - ctx.Err = service.CreateAnnouncement(ctx.Username, args, ctx.Logger) + ctx.Err = service.CreateAnnouncement(ctx.UserName, args, ctx.Logger) } func UpdateAnnouncement(c *gin.Context) { @@ -48,21 +48,21 @@ func UpdateAnnouncement(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("invalid notify args") return } - ctx.Err = service.UpdateAnnouncement(ctx.Username, args.ID.Hex(), args, ctx.Logger) + ctx.Err = service.UpdateAnnouncement(ctx.UserName, args.ID.Hex(), args, ctx.Logger) } func PullAllAnnouncement(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - ctx.Resp, ctx.Err = service.PullAllAnnouncement(ctx.Username, ctx.Logger) + ctx.Resp, ctx.Err = service.PullAllAnnouncement(ctx.UserName, ctx.Logger) } func PullNotifyAnnouncement(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - ctx.Resp, ctx.Err = service.PullNotifyAnnouncement(ctx.Username, ctx.Logger) + ctx.Resp, ctx.Err = service.PullNotifyAnnouncement(ctx.UserName, ctx.Logger) } func DeleteAnnouncement(c *gin.Context) { @@ -71,5 +71,5 @@ func DeleteAnnouncement(c *gin.Context) { ID := c.Param("id") - ctx.Err = service.DeleteAnnouncement(ctx.Username, ID, ctx.Logger) + ctx.Err = service.DeleteAnnouncement(ctx.UserName, ID, ctx.Logger) } diff --git a/pkg/microservice/aslan/core/system/handler/basic_images.go b/pkg/microservice/aslan/core/system/handler/basic_images.go index 5e4a7ebfe199e25d0d3a34bd0a2af2456bd00d8b..be11a6701ff8b83b37fc242f88a7a1f905be12f4 100644 --- a/pkg/microservice/aslan/core/system/handler/basic_images.go +++ b/pkg/microservice/aslan/core/system/handler/basic_images.go @@ -58,7 +58,7 @@ func CreateBasicImage(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("CreateBasicImage json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, "", "新增", "基础镜像", fmt.Sprintf("label:%s", args.Label), string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, "", "新增", "基础镜像", fmt.Sprintf("label:%s", args.Label), string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) @@ -66,7 +66,7 @@ func CreateBasicImage(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("invalid BasicImage args") return } - args.UpdateBy = ctx.Username + args.UpdateBy = ctx.UserName ctx.Err = service.CreateBasicImage(args, ctx.Logger) } @@ -83,7 +83,7 @@ func UpdateBasicImage(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("UpdateBasicImage json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, "", "更新", "基础镜像", fmt.Sprintf("id:%s", args.ID), string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, "", "更新", "基础镜像", fmt.Sprintf("id:%s", args.ID), string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) @@ -91,7 +91,7 @@ func UpdateBasicImage(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("invalid BasicImage args") return } - args.UpdateBy = ctx.Username + args.UpdateBy = ctx.UserName ctx.Err = service.UpdateBasicImage(c.Param("id"), args, ctx.Logger) } @@ -100,7 +100,7 @@ func DeleteBasicImage(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - internalhandler.InsertOperationLog(c, ctx.Username, "", "删除", "基础镜像", fmt.Sprintf("id:%s", c.Param("id")), "", ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, "", "删除", "基础镜像", fmt.Sprintf("id:%s", c.Param("id")), "", ctx.Logger) ctx.Err = service.DeleteBasicImage(c.Param("id"), ctx.Logger) } diff --git a/pkg/microservice/aslan/core/system/handler/external_link.go b/pkg/microservice/aslan/core/system/handler/external_link.go new file mode 100644 index 0000000000000000000000000000000000000000..cbe7c44c0dde699f3ba26ca7a9977ac4cd82955f --- /dev/null +++ b/pkg/microservice/aslan/core/system/handler/external_link.go @@ -0,0 +1,81 @@ +package handler + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + + "github.com/gin-gonic/gin" + + commonmodels "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" + "github.com/koderover/zadig/pkg/microservice/aslan/core/system/service" + internalhandler "github.com/koderover/zadig/pkg/shared/handler" + e "github.com/koderover/zadig/pkg/tool/errors" + "github.com/koderover/zadig/pkg/tool/log" +) + +func ListExternalLinks(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + ctx.Resp, ctx.Err = service.ListExternalLinks(ctx.Logger) +} + +func CreateExternalLink(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + args := new(commonmodels.ExternalLink) + data, err := c.GetRawData() + if err != nil { + log.Errorf("CreateExternalLink c.GetRawData() err : %s", err) + } + if err = json.Unmarshal(data, args); err != nil { + log.Errorf("CreateExternalLink json.Unmarshal err : %s", err) + } + internalhandler.InsertOperationLog(c, ctx.UserName, "", "新增", "系统配置-快捷链接", fmt.Sprintf("name:%s url:%s", args.Name, args.URL), string(data), ctx.Logger) + + c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) + + if err := c.ShouldBindJSON(&args); err != nil { + ctx.Err = e.ErrInvalidParam.AddDesc("invalid externalLink args") + return + } + args.UpdateBy = ctx.UserName + + ctx.Err = service.CreateExternalLink(args, ctx.Logger) +} + +func UpdateExternalLink(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + args := new(commonmodels.ExternalLink) + data, err := c.GetRawData() + if err != nil { + log.Errorf("UpdateExternal c.GetRawData() err : %s", err) + } + if err = json.Unmarshal(data, args); err != nil { + log.Errorf("UpdateExternal json.Unmarshal err : %s", err) + } + internalhandler.InsertOperationLog(c, ctx.UserName, "", "更新", "系统配置-快捷链接", fmt.Sprintf("name:%s url:%s", args.Name, args.URL), string(data), ctx.Logger) + + c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) + + if err := c.ShouldBindJSON(&args); err != nil { + ctx.Err = e.ErrInvalidParam.AddDesc("invalid externalLink args") + return + } + args.UpdateBy = ctx.UserName + + ctx.Err = service.UpdateExternalLink(c.Param("id"), args, ctx.Logger) +} + +func DeleteExternalLink(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + internalhandler.InsertOperationLog(c, ctx.UserName, "", "删除", "系统配置-快捷链接", fmt.Sprintf("id:%s", c.Param("id")), "", ctx.Logger) + ctx.Err = service.DeleteExternalLink(c.Param("id"), ctx.Logger) +} diff --git a/pkg/microservice/aslan/core/system/handler/helm.go b/pkg/microservice/aslan/core/system/handler/helm.go index 928791483835d5dd77e56d1590f0383e36bed8f5..31a84a53daa99dc9ec778705ea19d41741dc6bc9 100644 --- a/pkg/microservice/aslan/core/system/handler/helm.go +++ b/pkg/microservice/aslan/core/system/handler/helm.go @@ -44,7 +44,7 @@ func CreateHelmRepo(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("invalid helmRepo json args") return } - args.UpdateBy = ctx.Username + args.UpdateBy = ctx.UserName if _, err := url.Parse(args.URL); err != nil { ctx.Err = e.ErrInvalidParam.AddDesc("invalid url") return @@ -61,7 +61,7 @@ func UpdateHelmRepo(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("invalid helmRepo json args") return } - args.UpdateBy = ctx.Username + args.UpdateBy = ctx.UserName ctx.Err = service.UpdateHelmRepo(c.Param("id"), args, ctx.Logger) } diff --git a/pkg/microservice/aslan/core/system/handler/install.go b/pkg/microservice/aslan/core/system/handler/install.go index f2347d9fe3e82b4162963ac7794447e5a085640a..35532d16249d3a96932f00c12c38a9d84d4998c2 100644 --- a/pkg/microservice/aslan/core/system/handler/install.go +++ b/pkg/microservice/aslan/core/system/handler/install.go @@ -44,14 +44,14 @@ func CreateInstall(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("CreateInstall json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, "", "新增", "系统设置-应用设置", fmt.Sprintf("应用名称:%s,应用版本:%s", args.Name, args.Version), string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, "", "新增", "系统设置-应用设置", fmt.Sprintf("应用名称:%s,应用版本:%s", args.Name, args.Version), string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) if err := c.ShouldBindWith(&args, binding.JSON); err != nil { ctx.Err = e.ErrInvalidParam.AddDesc("invalid Install args") return } - args.UpdateBy = ctx.Username + args.UpdateBy = ctx.UserName ctx.Err = service.CreateInstall(args, ctx.Logger) } @@ -68,14 +68,14 @@ func UpdateInstall(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("UpdateInstall json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, "", "更新", "系统设置-应用设置", fmt.Sprintf("应用名称:%s,应用版本:%s", args.Name, args.Version), string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, "", "更新", "系统设置-应用设置", fmt.Sprintf("应用名称:%s,应用版本:%s", args.Name, args.Version), string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) if err := c.ShouldBindWith(&args, binding.JSON); err != nil { ctx.Err = e.ErrInvalidParam.AddDesc("invalid Install args") return } - args.UpdateBy = ctx.Username + args.UpdateBy = ctx.UserName name := args.Name version := args.Version if name == "" || version == "" { @@ -116,7 +116,7 @@ func DeleteInstall(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("DeleteInstall json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, "", "删除", "系统设置-应用设置", fmt.Sprintf("应用名称:%s,应用版本:%s", args.Name, args.Version), string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, "", "删除", "系统设置-应用设置", fmt.Sprintf("应用名称:%s,应用版本:%s", args.Name, args.Version), string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) if err := c.ShouldBindWith(&args, binding.JSON); err != nil { diff --git a/pkg/microservice/aslan/core/system/handler/jenkins.go b/pkg/microservice/aslan/core/system/handler/jenkins.go index 20e7962191625051361fa4b1a690c10c92af0fab..3f0620816c829d4f6f40f7e3f2cc4b5de712994e 100644 --- a/pkg/microservice/aslan/core/system/handler/jenkins.go +++ b/pkg/microservice/aslan/core/system/handler/jenkins.go @@ -36,7 +36,7 @@ func CreateJenkinsIntegration(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("invalid jenkinsIntegration json args") return } - args.UpdateBy = ctx.Username + args.UpdateBy = ctx.UserName if _, err := url.Parse(args.URL); err != nil { ctx.Err = e.ErrInvalidParam.AddDesc("invalid url") return @@ -60,7 +60,7 @@ func UpdateJenkinsIntegration(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("invalid jenkinsIntegration json args") return } - args.UpdateBy = ctx.Username + args.UpdateBy = ctx.UserName ctx.Err = service.UpdateJenkinsIntegration(c.Param("id"), args, ctx.Logger) } diff --git a/pkg/microservice/aslan/core/system/handler/notify.go b/pkg/microservice/aslan/core/system/handler/notify.go index 5093cea28bc736eb4ee7cfe66961f2b22c7721bf..f654e8a195416d9f10b3b9c84e97dd79f8805ed1 100644 --- a/pkg/microservice/aslan/core/system/handler/notify.go +++ b/pkg/microservice/aslan/core/system/handler/notify.go @@ -31,7 +31,7 @@ func PullNotify(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - ctx.Resp, ctx.Err = service.PullNotify(ctx.Username, ctx.Logger) + ctx.Resp, ctx.Err = service.PullNotify(ctx.UserName, ctx.Logger) } type readNotificationsArgs struct { @@ -48,7 +48,7 @@ func ReadNotify(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("invalid readnotificationsargs") return } - ctx.Err = service.ReadNotify(ctx.Username, args.IDs, ctx.Logger) + ctx.Err = service.ReadNotify(ctx.UserName, args.IDs, ctx.Logger) } type deleteNotificationsArgs struct { @@ -65,7 +65,7 @@ func DeleteNotifies(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("invalid args") return } - ctx.Err = service.DeleteNotifies(ctx.Username, args.IDs, ctx.Logger) + ctx.Err = service.DeleteNotifies(ctx.UserName, args.IDs, ctx.Logger) } func UpsertSubscription(c *gin.Context) { @@ -78,7 +78,7 @@ func UpsertSubscription(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("invalid subscription args") return } - ctx.Err = service.UpsertSubscription(ctx.Username, args, ctx.Logger) + ctx.Err = service.UpsertSubscription(ctx.UserName, args, ctx.Logger) } func UpdateSubscribe(c *gin.Context) { @@ -96,7 +96,7 @@ func UpdateSubscribe(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("invalid notification type") return } - ctx.Err = service.UpdateSubscribe(ctx.Username, notifytype, args, ctx.Logger) + ctx.Err = service.UpdateSubscribe(ctx.UserName, notifytype, args, ctx.Logger) } func Unsubscribe(c *gin.Context) { @@ -107,12 +107,12 @@ func Unsubscribe(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("invalid notification type") return } - ctx.Err = service.Unsubscribe(ctx.Username, notifytype, ctx.Logger) + ctx.Err = service.Unsubscribe(ctx.UserName, notifytype, ctx.Logger) } func ListSubscriptions(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - ctx.Resp, ctx.Err = service.ListSubscriptions(ctx.Username, ctx.Logger) + ctx.Resp, ctx.Err = service.ListSubscriptions(ctx.UserName, ctx.Logger) } diff --git a/pkg/microservice/aslan/core/system/handler/operation.go b/pkg/microservice/aslan/core/system/handler/operation.go index d4d97b7751ef848d9d7935eb8cdaa22a6b1af2e8..10547c2ddf096a15b82f68c3a3fd8aec52c3e5bf 100644 --- a/pkg/microservice/aslan/core/system/handler/operation.go +++ b/pkg/microservice/aslan/core/system/handler/operation.go @@ -51,7 +51,7 @@ func GetOperationLogs(c *gin.Context) { args := &service.OperationLogArgs{ Username: c.Query("username"), - ProductName: c.Query("product_name"), + ProductName: c.Query("projectName"), Function: c.Query("function"), Status: status, PerPage: perPage, diff --git a/pkg/microservice/aslan/core/system/handler/private_key.go b/pkg/microservice/aslan/core/system/handler/private_key.go index aef54436f9784a25a9170f125625b662953bef5b..a6967d13db9ef74f94cc354f1415dfd6a99a6fa5 100644 --- a/pkg/microservice/aslan/core/system/handler/private_key.go +++ b/pkg/microservice/aslan/core/system/handler/private_key.go @@ -58,7 +58,7 @@ func CreatePrivateKey(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("CreatePrivateKey json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, "", "新增", "资源管理-主机管理", fmt.Sprintf("hostName:%s ip:%s", args.Name, args.IP), string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, "", "新增", "资源管理-主机管理", fmt.Sprintf("hostName:%s ip:%s", args.Name, args.IP), string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) @@ -66,7 +66,7 @@ func CreatePrivateKey(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("invalid PrivateKey args") return } - args.UpdateBy = ctx.Username + args.UpdateBy = ctx.UserName ctx.Err = service.CreatePrivateKey(args, ctx.Logger) } @@ -83,7 +83,7 @@ func UpdatePrivateKey(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("UpdatePrivateKey json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, "", "更新", "资源管理-主机管理", fmt.Sprintf("hostName:%s ip:%s", args.Name, args.IP), string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, "", "更新", "资源管理-主机管理", fmt.Sprintf("hostName:%s ip:%s", args.Name, args.IP), string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) @@ -91,7 +91,7 @@ func UpdatePrivateKey(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("invalid PrivateKey args") return } - args.UpdateBy = ctx.Username + args.UpdateBy = ctx.UserName ctx.Err = service.UpdatePrivateKey(c.Param("id"), args, ctx.Logger) } @@ -100,7 +100,7 @@ func DeletePrivateKey(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - internalhandler.InsertOperationLog(c, ctx.Username, "", "删除", "资源管理-主机管理", fmt.Sprintf("id:%s", c.Param("id")), "", ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, "", "删除", "资源管理-主机管理", fmt.Sprintf("id:%s", c.Param("id")), "", ctx.Logger) ctx.Err = service.DeletePrivateKey(c.Param("id"), ctx.Logger) } @@ -128,7 +128,8 @@ func BatchCreatePrivateKey(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("batchCreatePrivateKey json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, "", "批量新增", "资源管理-主机管理", "", string(data), ctx.Logger) + + internalhandler.InsertOperationLog(c, ctx.UserName, "", "批量新增", "资源管理-主机管理", "", string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) @@ -137,5 +138,5 @@ func BatchCreatePrivateKey(c *gin.Context) { return } - ctx.Err = service.BatchCreatePrivateKey(args.Data, args.Option, ctx.Username, ctx.Logger) + ctx.Err = service.BatchCreatePrivateKey(args.Data, args.Option, ctx.UserName, ctx.Logger) } diff --git a/pkg/microservice/aslan/core/system/handler/proxy.go b/pkg/microservice/aslan/core/system/handler/proxy.go index 2f0ed2602c4151a951540d1b869642a2f1a538d2..896bca8b10a2284528a99a2138c367d1f380c300 100644 --- a/pkg/microservice/aslan/core/system/handler/proxy.go +++ b/pkg/microservice/aslan/core/system/handler/proxy.go @@ -69,7 +69,7 @@ func CreateProxy(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("CreateProxy json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, "", "新增", "代理", fmt.Sprintf("server:%s:%d", args.Address, args.Port), string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, "", "新增", "代理", fmt.Sprintf("server:%s:%d", args.Address, args.Port), string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) @@ -77,7 +77,7 @@ func CreateProxy(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("invalid proxy args") return } - args.UpdateBy = ctx.Username + args.UpdateBy = ctx.UserName ctx.Err = service.CreateProxy(args, ctx.Logger) } @@ -94,7 +94,7 @@ func UpdateProxy(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("UpdateProxy json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, "", "更新", "代理", fmt.Sprintf("id:%s", args.ID), string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, "", "更新", "代理", fmt.Sprintf("id:%s", args.ID), string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) @@ -102,7 +102,7 @@ func UpdateProxy(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("invalid proxy args") return } - args.UpdateBy = ctx.Username + args.UpdateBy = ctx.UserName ctx.Err = service.UpdateProxy(c.Param("id"), args, ctx.Logger) } @@ -111,7 +111,7 @@ func DeleteProxy(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - internalhandler.InsertOperationLog(c, ctx.Username, "", "删除", "代理", fmt.Sprintf("id:%s", c.Param("id")), "", ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, "", "删除", "代理", fmt.Sprintf("id:%s", c.Param("id")), "", ctx.Logger) ctx.Err = service.DeleteProxy(c.Param("id"), ctx.Logger) } diff --git a/pkg/microservice/aslan/core/system/handler/registry.go b/pkg/microservice/aslan/core/system/handler/registry.go index 61e7f23bf1715c22405f0bd42ef8430a0095152c..7a419d0cbd173adfbb610c09fbee92d35aecf000 100644 --- a/pkg/microservice/aslan/core/system/handler/registry.go +++ b/pkg/microservice/aslan/core/system/handler/registry.go @@ -79,7 +79,7 @@ func CreateRegistryNamespace(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("CreateRegistryNamespace json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, "", "新增", "系统设置-Registry", fmt.Sprintf("提供商:%s,Namespace:%s", args.RegProvider, args.Namespace), string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, "", "新增", "系统设置-Registry", fmt.Sprintf("提供商:%s,Namespace:%s", args.RegProvider, args.Namespace), string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) if err := c.BindJSON(args); err != nil { @@ -92,7 +92,7 @@ func CreateRegistryNamespace(c *gin.Context) { return } - ctx.Err = service.CreateRegistryNamespace(ctx.Username, args, ctx.Logger) + ctx.Err = service.CreateRegistryNamespace(ctx.UserName, args, ctx.Logger) } func UpdateRegistryNamespace(c *gin.Context) { @@ -107,7 +107,7 @@ func UpdateRegistryNamespace(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("UpdateRegistryNamespace json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, "", "更新", "系统设置-Registry", fmt.Sprintf("提供商:%s,Namespace:%s", args.RegProvider, args.Namespace), string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, "", "更新", "系统设置-Registry", fmt.Sprintf("提供商:%s,Namespace:%s", args.RegProvider, args.Namespace), string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) if err := c.BindJSON(args); err != nil { @@ -120,14 +120,14 @@ func UpdateRegistryNamespace(c *gin.Context) { return } - ctx.Err = service.UpdateRegistryNamespace(ctx.Username, c.Param("id"), args, ctx.Logger) + ctx.Err = service.UpdateRegistryNamespace(ctx.UserName, c.Param("id"), args, ctx.Logger) } func DeleteRegistryNamespace(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - internalhandler.InsertOperationLog(c, ctx.Username, "", "删除", "系统设置-Registry", fmt.Sprintf("registry ID:%s", c.Param("id")), "", ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, "", "删除", "系统设置-Registry", fmt.Sprintf("registry ID:%s", c.Param("id")), "", ctx.Logger) ctx.Err = service.DeleteRegistryNamespace(c.Param("id"), ctx.Logger) } diff --git a/pkg/microservice/aslan/core/system/handler/router.go b/pkg/microservice/aslan/core/system/handler/router.go index bf5a2040a45cdfa7be5f0e6b82aa355c5786643c..9de790a64336842bcd2ad797ed92519733fa1a2b 100644 --- a/pkg/microservice/aslan/core/system/handler/router.go +++ b/pkg/microservice/aslan/core/system/handler/router.go @@ -30,18 +30,16 @@ func (*Router) Inject(router *gin.RouterGroup) { proxy.GET("/config", GetProxyConfig) } - router.Use(gin2.Auth()) - // --------------------------------------------------------------------------------------- // 安装脚本管理接口 // --------------------------------------------------------------------------------------- install := router.Group("install") { - install.POST("", gin2.RequireSuperAdminAuth, gin2.UpdateOperationLogStatus, CreateInstall) - install.PUT("", gin2.RequireSuperAdminAuth, gin2.UpdateOperationLogStatus, UpdateInstall) + install.POST("", gin2.UpdateOperationLogStatus, CreateInstall) + install.PUT("", gin2.UpdateOperationLogStatus, UpdateInstall) install.GET("/:name/:version", GetInstall) install.GET("", ListInstalls) - install.PUT("/delete", gin2.RequireSuperAdminAuth, gin2.UpdateOperationLogStatus, DeleteInstall) + install.PUT("/delete", gin2.UpdateOperationLogStatus, DeleteInstall) } // --------------------------------------------------------------------------------------- @@ -51,9 +49,9 @@ func (*Router) Inject(router *gin.RouterGroup) { { proxyManage.GET("", ListProxies) proxyManage.GET("/:id", GetProxy) - proxyManage.POST("", gin2.RequireSuperAdminAuth, gin2.UpdateOperationLogStatus, CreateProxy) - proxyManage.PUT("/:id", gin2.RequireSuperAdminAuth, gin2.UpdateOperationLogStatus, UpdateProxy) - proxyManage.DELETE("/:id", gin2.RequireSuperAdminAuth, gin2.UpdateOperationLogStatus, DeleteProxy) + proxyManage.POST("", gin2.UpdateOperationLogStatus, CreateProxy) + proxyManage.PUT("/:id", gin2.UpdateOperationLogStatus, UpdateProxy) + proxyManage.DELETE("/:id", gin2.UpdateOperationLogStatus, DeleteProxy) proxyManage.POST("/connectionTest", TestConnection) } @@ -63,11 +61,11 @@ func (*Router) Inject(router *gin.RouterGroup) { registry.GET("", ListRegistries) // 获取默认的镜像仓库配置,用于kodespace CLI调用 registry.GET("/namespaces/default", GetDefaultRegistryNamespace) - registry.GET("/namespaces", gin2.RequireSuperAdminAuth, ListRegistryNamespaces) - registry.POST("/namespaces", gin2.RequireSuperAdminAuth, gin2.UpdateOperationLogStatus, CreateRegistryNamespace) - registry.PUT("/namespaces/:id", gin2.RequireSuperAdminAuth, gin2.UpdateOperationLogStatus, UpdateRegistryNamespace) + registry.GET("/namespaces", ListRegistryNamespaces) + registry.POST("/namespaces", gin2.UpdateOperationLogStatus, CreateRegistryNamespace) + registry.PUT("/namespaces/:id", gin2.UpdateOperationLogStatus, UpdateRegistryNamespace) - registry.DELETE("/namespaces/:id", gin2.RequireSuperAdminAuth, gin2.UpdateOperationLogStatus, DeleteRegistryNamespace) + registry.DELETE("/namespaces/:id", gin2.UpdateOperationLogStatus, DeleteRegistryNamespace) registry.GET("/release/repos", ListAllRepos) registry.POST("/images", ListImages) registry.GET("/images/repos/:name", ListRepoImages) @@ -76,10 +74,10 @@ func (*Router) Inject(router *gin.RouterGroup) { s3storage := router.Group("s3storage") { s3storage.GET("", ListS3Storage) - s3storage.POST("", gin2.RequireSuperAdminAuth, gin2.UpdateOperationLogStatus, CreateS3Storage) + s3storage.POST("", gin2.UpdateOperationLogStatus, CreateS3Storage) s3storage.GET("/:id", GetS3Storage) - s3storage.PUT("/:id", gin2.RequireSuperAdminAuth, gin2.UpdateOperationLogStatus, UpdateS3Storage) - s3storage.DELETE("/:id", gin2.RequireSuperAdminAuth, gin2.UpdateOperationLogStatus, DeleteS3Storage) + s3storage.PUT("/:id", gin2.UpdateOperationLogStatus, UpdateS3Storage) + s3storage.DELETE("/:id", gin2.UpdateOperationLogStatus, DeleteS3Storage) s3storage.POST("/:id/releases/search", ListTars) } @@ -96,8 +94,8 @@ func (*Router) Inject(router *gin.RouterGroup) { github := router.Group("githubApp") { github.GET("", GetGithubApp) - github.POST("", gin2.RequireSuperAdminAuth, CreateGithubApp) - github.DELETE("/:id", gin2.RequireSuperAdminAuth, DeleteGithubApp) + github.POST("", CreateGithubApp) + github.DELETE("/:id", DeleteGithubApp) } // --------------------------------------------------------------------------------------- @@ -105,13 +103,13 @@ func (*Router) Inject(router *gin.RouterGroup) { // --------------------------------------------------------------------------------------- jenkins := router.Group("jenkins") { - jenkins.POST("/integration", gin2.RequireSuperAdminAuth, CreateJenkinsIntegration) + jenkins.POST("/integration", CreateJenkinsIntegration) jenkins.GET("/integration", ListJenkinsIntegration) - jenkins.PUT("/integration/:id", gin2.RequireSuperAdminAuth, UpdateJenkinsIntegration) - jenkins.DELETE("/integration/:id", gin2.RequireSuperAdminAuth, DeleteJenkinsIntegration) - jenkins.POST("/user/connection", gin2.RequireSuperAdminAuth, TestJenkinsConnection) - jenkins.GET("/jobNames", gin2.RequireSuperAdminAuth, ListJobNames) - jenkins.GET("/buildArgs/:jobName", gin2.RequireSuperAdminAuth, ListJobBuildArgs) + jenkins.PUT("/integration/:id", UpdateJenkinsIntegration) + jenkins.DELETE("/integration/:id", DeleteJenkinsIntegration) + jenkins.POST("/user/connection", TestJenkinsConnection) + jenkins.GET("/jobNames", ListJobNames) + jenkins.GET("/buildArgs/:jobName", ListJobBuildArgs) } //系统配额 @@ -131,9 +129,9 @@ func (*Router) Inject(router *gin.RouterGroup) { { basicImages.GET("", ListBasicImages) basicImages.GET("/:id", GetBasicImage) - basicImages.POST("", gin2.RequireSuperAdminAuth, gin2.UpdateOperationLogStatus, CreateBasicImage) - basicImages.PUT("/:id", gin2.RequireSuperAdminAuth, gin2.UpdateOperationLogStatus, UpdateBasicImage) - basicImages.DELETE("/:id", gin2.RequireSuperAdminAuth, gin2.UpdateOperationLogStatus, DeleteBasicImage) + basicImages.POST("", gin2.UpdateOperationLogStatus, CreateBasicImage) + basicImages.PUT("/:id", gin2.UpdateOperationLogStatus, UpdateBasicImage) + basicImages.DELETE("/:id", gin2.UpdateOperationLogStatus, DeleteBasicImage) } // --------------------------------------------------------------------------------------- @@ -142,9 +140,9 @@ func (*Router) Inject(router *gin.RouterGroup) { integration := router.Group("helm") { integration.GET("", ListHelmRepos) - integration.POST("", gin2.RequireSuperAdminAuth, CreateHelmRepo) - integration.PUT("/:id", gin2.RequireSuperAdminAuth, UpdateHelmRepo) - integration.DELETE("/:id", gin2.RequireSuperAdminAuth, DeleteHelmRepo) + integration.POST("", CreateHelmRepo) + integration.PUT("/:id", UpdateHelmRepo) + integration.DELETE("/:id", DeleteHelmRepo) } // --------------------------------------------------------------------------------------- @@ -155,10 +153,10 @@ func (*Router) Inject(router *gin.RouterGroup) { privateKey.GET("", ListPrivateKeys) privateKey.GET("/:id", GetPrivateKey) privateKey.GET("/labels", ListLabels) - privateKey.POST("", gin2.RequireSuperAdminAuth, gin2.UpdateOperationLogStatus, CreatePrivateKey) - privateKey.POST("/batch", gin2.RequireSuperAdminAuth, gin2.UpdateOperationLogStatus, BatchCreatePrivateKey) - privateKey.PUT("/:id", gin2.RequireSuperAdminAuth, gin2.UpdateOperationLogStatus, UpdatePrivateKey) - privateKey.DELETE("/:id", gin2.RequireSuperAdminAuth, gin2.UpdateOperationLogStatus, DeletePrivateKey) + privateKey.POST("", gin2.UpdateOperationLogStatus, CreatePrivateKey) + privateKey.POST("/batch", gin2.UpdateOperationLogStatus, BatchCreatePrivateKey) + privateKey.PUT("/:id", gin2.UpdateOperationLogStatus, UpdatePrivateKey) + privateKey.DELETE("/:id", gin2.UpdateOperationLogStatus, DeletePrivateKey) } notification := router.Group("notification") @@ -174,18 +172,28 @@ func (*Router) Inject(router *gin.RouterGroup) { announcement := router.Group("announcement") { - announcement.POST("", gin2.RequireSuperAdminAuth, CreateAnnouncement) - announcement.PUT("/update", gin2.RequireSuperAdminAuth, UpdateAnnouncement) - announcement.GET("/all", gin2.RequireSuperAdminAuth, PullAllAnnouncement) + announcement.POST("", CreateAnnouncement) + announcement.PUT("/update", UpdateAnnouncement) + announcement.GET("/all", PullAllAnnouncement) announcement.GET("", PullNotifyAnnouncement) - announcement.DELETE("/:id", gin2.RequireSuperAdminAuth, DeleteAnnouncement) + announcement.DELETE("/:id", DeleteAnnouncement) } operation := router.Group("operation") { - operation.GET("", gin2.RequireSuperAdminAuth, GetOperationLogs) - operation.POST("", gin2.RequireSuperAdminAuth, AddSystemOperationLog) - operation.PUT("/:id", gin2.RequireSuperAdminAuth, UpdateOperationLog) + operation.GET("", GetOperationLogs) + operation.POST("", AddSystemOperationLog) + operation.PUT("/:id", UpdateOperationLog) } + // --------------------------------------------------------------------------------------- + // system external link + // --------------------------------------------------------------------------------------- + externalLink := router.Group("externalLink") + { + externalLink.GET("", ListExternalLinks) + externalLink.POST("", gin2.UpdateOperationLogStatus, CreateExternalLink) + externalLink.PUT("/:id", gin2.UpdateOperationLogStatus, UpdateExternalLink) + externalLink.DELETE("/:id", gin2.UpdateOperationLogStatus, DeleteExternalLink) + } } diff --git a/pkg/microservice/aslan/core/system/handler/s3.go b/pkg/microservice/aslan/core/system/handler/s3.go index 8819a32321d84710bb3d174b2f9dee03536cb514..f8e534ad01701d63d02733668e2f314de5622621 100644 --- a/pkg/microservice/aslan/core/system/handler/s3.go +++ b/pkg/microservice/aslan/core/system/handler/s3.go @@ -51,7 +51,7 @@ func CreateS3Storage(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("CreateS3Storage json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, "", "新增", "系统设置-对象存储", fmt.Sprintf("地址:%s", c.GetString("s3StorageEndpoint")), string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, "", "新增", "系统设置-对象存储", fmt.Sprintf("地址:%s", c.GetString("s3StorageEndpoint")), string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) if err := c.BindJSON(args); err != nil { @@ -67,7 +67,7 @@ func CreateS3Storage(c *gin.Context) { return } - ctx.Err = service.CreateS3Storage(ctx.Username, args, ctx.Logger) + ctx.Err = service.CreateS3Storage(ctx.UserName, args, ctx.Logger) } func GetS3Storage(c *gin.Context) { @@ -89,7 +89,7 @@ func UpdateS3Storage(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("UpdateS3Storage json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, "", "更新", "系统设置-对象存储", fmt.Sprintf("地址:%s", c.GetString("s3StorageEndpoint")), string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, "", "更新", "系统设置-对象存储", fmt.Sprintf("地址:%s", c.GetString("s3StorageEndpoint")), string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) if err := c.BindJSON(args); err != nil { @@ -106,16 +106,16 @@ func UpdateS3Storage(c *gin.Context) { } id := c.Param("id") - ctx.Err = service.UpdateS3Storage(ctx.Username, id, args, ctx.Logger) + ctx.Err = service.UpdateS3Storage(ctx.UserName, id, args, ctx.Logger) } func DeleteS3Storage(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - internalhandler.InsertOperationLog(c, ctx.Username, "", "删除", "系统设置-对象存储", fmt.Sprintf("s3Storage ID:%s", c.Param("id")), "", ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, "", "删除", "系统设置-对象存储", fmt.Sprintf("s3Storage ID:%s", c.Param("id")), "", ctx.Logger) - ctx.Err = service.DeleteS3Storage(ctx.Username, c.Param("id"), ctx.Logger) + ctx.Err = service.DeleteS3Storage(ctx.UserName, c.Param("id"), ctx.Logger) } type ListTarsOption struct { diff --git a/pkg/microservice/aslan/core/system/service/capacity.go b/pkg/microservice/aslan/core/system/service/capacity.go index fba668bfc07a1ac88ecf1279c5a137f6d7dffd98..31419d11346edca63e24990ce27a3eed56ed24c2 100644 --- a/pkg/microservice/aslan/core/system/service/capacity.go +++ b/pkg/microservice/aslan/core/system/service/capacity.go @@ -25,10 +25,8 @@ import ( commonmodels "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models/task" commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" - "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/notify" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/s3" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/poetry" "github.com/koderover/zadig/pkg/tool/log" s3tool "github.com/koderover/zadig/pkg/tool/s3" "github.com/koderover/zadig/pkg/util" @@ -172,20 +170,6 @@ func sendSyscapNotify(handleErr error, totalCleanTasks *int) { if handleErr != nil { content.Content = fmt.Sprintf("清理时间: %s, 状态: 失败, 内容: %v", now, handleErr) } - - notifyInfo := &commonmodels.Notify{ - Type: config.Message, - Content: content, - CreateTime: time.Now().Unix(), - IsRead: false, - } - - poetryClient := poetry.New(config.PoetryAPIServer(), config.PoetryAPIRootKey()) - users, _ := poetryClient.ListProductPermissionUsers("", "", log.SugaredLogger()) - for _, user := range users { - notifyInfo.Receiver = user - notify.NewNotifyClient().CreateNotify(user, notifyInfo) - } } func handleWorkflowTaskRetentionCenter(strategy *commonmodels.CapacityStrategy, dryRun bool) error { diff --git a/pkg/microservice/aslan/core/system/service/external_link.go b/pkg/microservice/aslan/core/system/service/external_link.go new file mode 100644 index 0000000000000000000000000000000000000000..b468b2013ef6ec194bbf24f037a0246bdf7b0884 --- /dev/null +++ b/pkg/microservice/aslan/core/system/service/external_link.go @@ -0,0 +1,45 @@ +package service + +import ( + "go.uber.org/zap" + + commonmodels "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" + commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" + e "github.com/koderover/zadig/pkg/tool/errors" +) + +func ListExternalLinks(log *zap.SugaredLogger) ([]*commonmodels.ExternalLink, error) { + resp, err := commonrepo.NewExternalLinkColl().List() + if err != nil { + log.Errorf("ExternalLink.List error: %s", err) + return resp, e.ErrListExternalLink.AddErr(err) + } + return resp, nil +} + +func CreateExternalLink(args *commonmodels.ExternalLink, log *zap.SugaredLogger) error { + err := commonrepo.NewExternalLinkColl().Create(args) + if err != nil { + log.Errorf("ExternalLink.Create error: %s", err) + return e.ErrCreateExternalLink.AddErr(err) + } + return nil +} + +func UpdateExternalLink(id string, args *commonmodels.ExternalLink, log *zap.SugaredLogger) error { + err := commonrepo.NewExternalLinkColl().Update(id, args) + if err != nil { + log.Errorf("ExternalLink.Update %s error: %s", id, err) + return e.ErrUpdateExternalLink.AddErr(err) + } + return nil +} + +func DeleteExternalLink(id string, log *zap.SugaredLogger) error { + err := commonrepo.NewExternalLinkColl().Delete(id) + if err != nil { + log.Errorf("ExternalLink.Delete %s error: %s", id, err) + return e.ErrDeleteExternalLink.AddErr(err) + } + return nil +} diff --git a/pkg/microservice/aslan/core/templatestore/handler/router.go b/pkg/microservice/aslan/core/templatestore/handler/router.go index 15efec5d9b076b1290a55cb9ba3c2296b5bd3f29..f00fd506d7995b9568a80a2f96c853bae8a47576 100644 --- a/pkg/microservice/aslan/core/templatestore/handler/router.go +++ b/pkg/microservice/aslan/core/templatestore/handler/router.go @@ -18,16 +18,11 @@ package handler import ( "github.com/gin-gonic/gin" - - ginmiddleware "github.com/koderover/zadig/pkg/middleware/gin" ) type Router struct{} func (*Router) Inject(router *gin.RouterGroup) { - - router.Use(ginmiddleware.Auth()) - // --------------------------------------------------------------------------------------- // chart templates // --------------------------------------------------------------------------------------- diff --git a/pkg/microservice/aslan/core/workflow/handler/build.go b/pkg/microservice/aslan/core/workflow/handler/build.go index 79d6e283bdb78fad308cb790b2ed2673aa082ba5..37166728d3e2de4f1f1cf920cb58f2063aef6969 100644 --- a/pkg/microservice/aslan/core/workflow/handler/build.go +++ b/pkg/microservice/aslan/core/workflow/handler/build.go @@ -27,9 +27,10 @@ import ( func BuildModuleToSubTasks(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() + args := &models.BuildModuleArgs{ BuildName: c.Param("name"), - ProductName: c.Query("productName"), + ProductName: c.Query("projectName"), } resp, err := workflow.BuildModuleToSubTasks(args, ctx.Logger) if err != nil { diff --git a/pkg/microservice/aslan/core/workflow/handler/favorate_pipeline.go b/pkg/microservice/aslan/core/workflow/handler/favorate_pipeline.go index bbc4dc59be71f7460e092a20f671cbd5da525d76..0574ffd50e3cece79865d1594da30b71f1146bfa 100644 --- a/pkg/microservice/aslan/core/workflow/handler/favorate_pipeline.go +++ b/pkg/microservice/aslan/core/workflow/handler/favorate_pipeline.go @@ -35,13 +35,13 @@ func ListFavoritePipelines(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - productName := c.Query("productName") + productName := c.Query("projectName") workflowType := c.Query("type") if workflowType == "" { ctx.Err = e.ErrInvalidParam.AddDesc("type can't be empty!") return } - ctx.Resp, ctx.Err = workflow.ListFavoritePipelines(&commonrepo.FavoriteArgs{UserID: ctx.User.ID, ProductName: productName, Type: workflowType}) + ctx.Resp, ctx.Err = workflow.ListFavoritePipelines(&commonrepo.FavoriteArgs{UserID: ctx.UserID, ProductName: productName, Type: workflowType}) } func DeleteFavoritePipeline(c *gin.Context) { @@ -55,8 +55,8 @@ func DeleteFavoritePipeline(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("productName or name or type can't be empty!") return } - internalhandler.InsertOperationLog(c, ctx.Username, productName, "删除", "收藏工作流", workflowName, "", ctx.Logger) - ctx.Err = workflow.DeleteFavoritePipeline(&commonrepo.FavoriteArgs{UserID: ctx.User.ID, ProductName: productName, Type: workflowType, Name: workflowName}) + internalhandler.InsertOperationLog(c, ctx.UserName, productName, "删除", "收藏工作流", workflowName, "", ctx.Logger) + ctx.Err = workflow.DeleteFavoritePipeline(&commonrepo.FavoriteArgs{UserID: ctx.UserID, ProductName: productName, Type: workflowType, Name: workflowName}) } func CreateFavoritePipeline(c *gin.Context) { @@ -71,14 +71,14 @@ func CreateFavoritePipeline(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("CreateFavoritePipeline json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, args.ProductName, "新增", "收藏工作流", args.Name, string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, args.ProductName, "新增", "收藏工作流", args.Name, string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) if err := c.BindJSON(args); err != nil { ctx.Err = e.ErrInvalidParam.AddDesc("invalid Favorite json args") return } - args.UserID = ctx.User.ID + args.UserID = ctx.UserID ctx.Err = workflow.CreateFavoritePipeline(args, ctx.Logger) } diff --git a/pkg/microservice/aslan/core/workflow/handler/pipeline.go b/pkg/microservice/aslan/core/workflow/handler/pipeline.go index cf79ec3e937187b89f9a5666d257d2680c48f4eb..ca3279631b34849a5a28e6e3fced8d55c50e1a04 100644 --- a/pkg/microservice/aslan/core/workflow/handler/pipeline.go +++ b/pkg/microservice/aslan/core/workflow/handler/pipeline.go @@ -54,7 +54,7 @@ func GetProductNameByPipeline(c *gin.Context) { if pipelineName == "" { pipelineName = c.Param("name") } - pipeline, err := workflow.GetPipeline(ctx.User.ID, pipelineName, ctx.Logger) + pipeline, err := workflow.GetPipeline(ctx.UserID, pipelineName, ctx.Logger) if err != nil { log.Errorf("GetProductNameByPipeline err : %v", err) return @@ -85,7 +85,7 @@ func GetPipeline(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - ctx.Resp, ctx.Err = workflow.GetPipeline(ctx.User.ID, c.Param("name"), ctx.Logger) + ctx.Resp, ctx.Err = workflow.GetPipeline(ctx.UserID, c.Param("name"), ctx.Logger) } // UpsertPipeline create a new pipeline @@ -101,7 +101,7 @@ func UpsertPipeline(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("UpsertPipeline json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, args.ProductName, "新增", "单服务-工作流", args.Name, string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, args.ProductName, "新增", "单服务-工作流", args.Name, string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) if err := c.BindJSON(args); err != nil || len(args.Name) == 0 { @@ -109,7 +109,7 @@ func UpsertPipeline(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc(fmt.Sprintf("invalid pipeline json args: %v", err)) return } - args.UpdateBy = ctx.Username + args.UpdateBy = ctx.UserName ctx.Err = workflow.UpsertPipeline(args, ctx.Logger) } @@ -118,8 +118,8 @@ func CopyPipeline(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - internalhandler.InsertOperationLog(c, ctx.Username, c.GetString("productName"), "复制", "单服务-工作流", fmt.Sprintf("old:%s,new:%s", c.Param("old"), c.Param("new")), "", ctx.Logger) - ctx.Err = workflow.CopyPipeline(c.Param("old"), c.Param("new"), ctx.Username, ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, c.GetString("productName"), "复制", "单服务-工作流", fmt.Sprintf("old:%s,new:%s", c.Param("old"), c.Param("new")), "", ctx.Logger) + ctx.Err = workflow.CopyPipeline(c.Param("old"), c.Param("new"), ctx.UserName, ctx.Logger) } // RenamePipeline rename pipeline @@ -127,7 +127,7 @@ func RenamePipeline(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - internalhandler.InsertOperationLog(c, ctx.Username, c.GetString("productName"), "修改", "单服务-工作流", fmt.Sprintf("old:%s,new:%s", c.Param("old"), c.Param("new")), "", ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, c.GetString("productName"), "修改", "单服务-工作流", fmt.Sprintf("old:%s,new:%s", c.Param("old"), c.Param("new")), "", ctx.Logger) ctx.Err = workflow.RenamePipeline(c.Param("old"), c.Param("new"), ctx.Logger) } @@ -136,6 +136,6 @@ func DeletePipeline(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - internalhandler.InsertOperationLog(c, ctx.Username, c.GetString("productName"), "删除", "单服务-工作流", c.Param("name"), "", ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, c.GetString("productName"), "删除", "单服务-工作流", c.Param("name"), "", ctx.Logger) ctx.Err = commonservice.DeletePipeline(c.Param("name"), ctx.RequestID, false, ctx.Logger) } diff --git a/pkg/microservice/aslan/core/workflow/handler/pipeline_status.go b/pkg/microservice/aslan/core/workflow/handler/pipeline_status.go index be25decbe2ccc3f932ff900cf81d6d6d6cb2d434..a171d0e0d1ed6862d60d3dc8a83f4ad1a96b246f 100644 --- a/pkg/microservice/aslan/core/workflow/handler/pipeline_status.go +++ b/pkg/microservice/aslan/core/workflow/handler/pipeline_status.go @@ -28,7 +28,7 @@ func ListPipelinesPreview(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - ctx.Resp, ctx.Err = workflow.ListPipelinesPreview(ctx.User.ID, ctx.Logger) + ctx.Resp, ctx.Err = workflow.ListPipelinesPreview(ctx.UserID, ctx.Logger) } // find task by commitId diff --git a/pkg/microservice/aslan/core/workflow/handler/pipeline_task.go b/pkg/microservice/aslan/core/workflow/handler/pipeline_task.go index 40b5f9dc69f1ab3a9168c5c308bc7883a08f94ca..476b8412059dd9401e341341be217880a87fe01c 100644 --- a/pkg/microservice/aslan/core/workflow/handler/pipeline_task.go +++ b/pkg/microservice/aslan/core/workflow/handler/pipeline_task.go @@ -47,7 +47,7 @@ func GetProductNameByPipelineTask(c *gin.Context) { return } - pipeline, err := workflow.GetPipeline(ctx.User.ID, args.PipelineName, ctx.Logger) + pipeline, err := workflow.GetPipeline(ctx.UserID, args.PipelineName, ctx.Logger) if err != nil { log.Errorf("GetProductNameByPipelineTask err : %v", err) return @@ -70,7 +70,7 @@ func CreatePipelineTask(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("CreatePipelineTask json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, c.GetString("productName"), "新增", "单服务-工作流task", args.PipelineName, string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, c.GetString("productName"), "新增", "单服务-工作流task", args.PipelineName, string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) if err := c.BindJSON(args); err != nil { @@ -78,7 +78,7 @@ func CreatePipelineTask(c *gin.Context) { return } if args.TaskCreator == "" { - args.TaskCreator = ctx.Username + args.TaskCreator = ctx.UserName } args.ReqID = ctx.RequestID @@ -86,7 +86,7 @@ func CreatePipelineTask(c *gin.Context) { // 发送通知 if ctx.Err != nil { - commonservice.SendFailedTaskMessage(ctx.Username, args.ProductName, args.PipelineName, ctx.RequestID, config.SingleType, ctx.Err, ctx.Logger) + commonservice.SendFailedTaskMessage(ctx.UserName, args.ProductName, args.PipelineName, ctx.RequestID, config.SingleType, ctx.Err, ctx.Logger) } } @@ -125,7 +125,7 @@ func GetPipelineTask(c *gin.Context) { func RestartPipelineTask(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - internalhandler.InsertOperationLog(c, ctx.Username, c.GetString("productName"), "重启", "单服务-工作流task", c.Param("name"), "", ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, c.GetString("productName"), "重启", "单服务-工作流task", c.Param("name"), "", ctx.Logger) taskID, err := strconv.ParseInt(c.Param("id"), 10, 64) if err != nil { @@ -133,20 +133,20 @@ func RestartPipelineTask(c *gin.Context) { return } - ctx.Err = workflow.RestartPipelineTaskV2(ctx.Username, taskID, c.Param("name"), config.SingleType, ctx.Logger) + ctx.Err = workflow.RestartPipelineTaskV2(ctx.UserName, taskID, c.Param("name"), config.SingleType, ctx.Logger) } func CancelTaskV2(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - internalhandler.InsertOperationLog(c, ctx.Username, c.GetString("productName"), "取消", "单服务-工作流task", c.Param("name"), "", ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, c.GetString("productName"), "取消", "单服务-工作流task", c.Param("name"), "", ctx.Logger) taskID, err := strconv.ParseInt(c.Param("id"), 10, 64) if err != nil { ctx.Err = e.ErrInvalidParam.AddDesc("invalid task id") return } - ctx.Err = commonservice.CancelTaskV2(ctx.Username, c.Param("name"), taskID, config.SingleType, ctx.RequestID, ctx.Logger) + ctx.Err = commonservice.CancelTaskV2(ctx.UserName, c.Param("name"), taskID, config.SingleType, ctx.RequestID, ctx.Logger) } // ListPipelineUpdatableProductNames 启动任务时检查部署环境 @@ -154,7 +154,7 @@ func ListPipelineUpdatableProductNames(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - ctx.Resp, ctx.Err = workflow.ListPipelineUpdatableProductNames(ctx.Username, c.Param("name"), ctx.Logger) + ctx.Resp, ctx.Err = workflow.ListPipelineUpdatableProductNames(ctx.UserName, c.Param("name"), ctx.Logger) } func GetPackageFile(c *gin.Context) { diff --git a/pkg/microservice/aslan/core/workflow/handler/policy.yaml b/pkg/microservice/aslan/core/workflow/handler/policy.yaml new file mode 100644 index 0000000000000000000000000000000000000000..1dc34f8c33faa8cbf207fbd204841cea7ce6b91f --- /dev/null +++ b/pkg/microservice/aslan/core/workflow/handler/policy.yaml @@ -0,0 +1,82 @@ +resource: Workflow +alias: "工作流" +description: "" +rules: + - action: get_workflow + alias: "查看工作流" + description: "" + rules: + - method: GET + endpoint: "api/aslan/workflow/workflow" + - method: GET + endpoint: "/api/aslan/workflow/workflow/find/?*" + - method: GET + endpoint: "/api/aslan/workflow/workflowtask/max/?*/start/?*/pipelines/?*" + - method: GET + endpoint: "/api/aslan/workflow/workflowtask/id/?*/pipelines/?*" + - method: GET + endpoint: "/api/aslan/workflow/sse/workflows/id/?*/pipelines/?*" + - method: GET + endpoint: "/api/aslan/logs/sse/workflow/build/?*/?*/?*/?*" + - method: GET + endpoint: "/api/aslan/logs/log/workflow/?*/tasks/?*/service/?*" + - method: GET + endpoint: "/api/aslan/logs/sse/workflow/test/?*/?*/?*/?*/?*" + - method: GET + endpoint: "/api/aslan/logs/log/workflow/?*/tasks/?*/tests/test/service/?*" + - method: GET + endpoint: "/api/aslan/logs/log/workflow/?*/tasks/?*/tests/test/service/?*" + - method: GET + endpoint: "/api/aslan/testing/itreport/workflow/?*/id/?*/names/?*/service/?*" + - method: GET + endpoint: "/api/directory/workflowTask" + - action: edit_workflow + alias: "编辑工作流" + description: "" + rules: + - method: PUT + endpoint: "api/aslan/workflow/workflow" + - method: GET + endpoint: "/api/aslan/environment/environments" + - method: GET + endpoint: "/api/aslan/workflow/workflow/preset/?*" + - method: GET + endpoint: "/api/aslan/testing/testdetail" + - action: create_workflow + alias: "新建工作流" + description: "" + rules: + - method: POST + endpoint: "api/aslan/workflow/workflow" + - method: PUT + endpoint: "/api/aslan/workflow/workflow/old/?*/new/?*" + - method: POST + endpoint: "/api/directory/workflowTask/create" + - method: GET + endpoint: "/api/aslan/environment/environments" + - method: GET + endpoint: "/api/aslan/testing/testdetail" + - action: delete_workflow + alias: "删除工作流" + description: "" + rules: + - method: DELETE + endpoint: "/api/aslan/workflow/workflow/?*" + - action: run_workflow + alias: "执行工作流" + description: "" + rules: + - method: POST + endpoint: "/api/aslan/workflow/workflowtask" + - method: PUT + endpoint: "/api/aslan/workflow/workflowtask" + - method: POST + endpoint: "/api/aslan/workflow/workflowtask/id/?*/pipelines/?*/restart" + - method: DELETE + endpoint: "/api/aslan/workflow/workflowtask/id/?*/pipelines/?*" + - method: POST + endpoint: "/api/directory/workflowTask/id/?*/pipelines/?*/restart" + - method: POST + endpoint: "/api/directory/workflowTask/id/?*/pipelines/?*/cancel" + - method: GET + endpoint: "/api/aslan/delivery/releases" diff --git a/pkg/microservice/aslan/core/workflow/handler/policy_definitions.go b/pkg/microservice/aslan/core/workflow/handler/policy_definitions.go new file mode 100644 index 0000000000000000000000000000000000000000..a434ba1ddc8fb0fcf719d776fc0e1211fe8a5240 --- /dev/null +++ b/pkg/microservice/aslan/core/workflow/handler/policy_definitions.go @@ -0,0 +1,24 @@ +package handler + +import ( + _ "embed" + + "sigs.k8s.io/yaml" + + "github.com/koderover/zadig/pkg/shared/client/policy" + "github.com/koderover/zadig/pkg/tool/log" +) + +//go:embed policy.yaml +var policyDefinitions []byte + +func (*Router) Policies() *policy.Policy { + res := &policy.Policy{} + err := yaml.Unmarshal(policyDefinitions, res) + if err != nil { + // should not have happened here + log.DPanic(err) + } + + return res +} diff --git a/pkg/microservice/aslan/core/workflow/handler/router.go b/pkg/microservice/aslan/core/workflow/handler/router.go index fa511c593c8a5ad66704a11006488f12b400e257..091767d452cbccf5ccd36fd2b2de9b861793ca4b 100644 --- a/pkg/microservice/aslan/core/workflow/handler/router.go +++ b/pkg/microservice/aslan/core/workflow/handler/router.go @@ -20,7 +20,6 @@ import ( "github.com/gin-gonic/gin" gin2 "github.com/koderover/zadig/pkg/middleware/gin" - "github.com/koderover/zadig/pkg/types/permission" ) type Router struct{} @@ -34,8 +33,6 @@ func (*Router) Inject(router *gin.RouterGroup) { webhook.POST("", ProcessWebHook) } - router.Use(gin2.Auth()) - build := router.Group("build") { build.GET("/:name/:version/to/subtasks", BuildModuleToSubTasks) @@ -59,10 +56,10 @@ func (*Router) Inject(router *gin.RouterGroup) { { pipeline.GET("", ListPipelines) pipeline.GET("/:name", GetPipeline) - pipeline.POST("", GetPipelineProductName, gin2.IsHavePermission([]string{permission.WorkflowCreateUUID}, permission.ContextKeyType), gin2.UpdateOperationLogStatus, UpsertPipeline) - pipeline.POST("/old/:old/new/:new", GetProductNameByPipeline, gin2.IsHavePermission([]string{permission.WorkflowCreateUUID}, permission.ContextKeyType), gin2.UpdateOperationLogStatus, CopyPipeline) - pipeline.PUT("/rename/:old/:new", GetProductNameByPipeline, gin2.IsHavePermission([]string{permission.WorkflowUpdateUUID}, permission.ContextKeyType), gin2.UpdateOperationLogStatus, RenamePipeline) - pipeline.DELETE("/:name", GetProductNameByPipeline, gin2.IsHavePermission([]string{permission.WorkflowDeleteUUID}, permission.ContextKeyType), gin2.UpdateOperationLogStatus, DeletePipeline) + pipeline.POST("", GetPipelineProductName, gin2.UpdateOperationLogStatus, UpsertPipeline) + pipeline.POST("/old/:old/new/:new", GetProductNameByPipeline, gin2.UpdateOperationLogStatus, CopyPipeline) + pipeline.PUT("/rename/:old/:new", GetProductNameByPipeline, gin2.UpdateOperationLogStatus, RenamePipeline) + pipeline.DELETE("/:name", GetProductNameByPipeline, gin2.UpdateOperationLogStatus, DeletePipeline) } // --------------------------------------------------------------------------------------- @@ -79,11 +76,11 @@ func (*Router) Inject(router *gin.RouterGroup) { // --------------------------------------------------------------------------------------- taskV2 := router.Group("v2/tasks") { - taskV2.POST("", GetProductNameByPipelineTask, gin2.IsHavePermission([]string{permission.WorkflowTaskUUID}, permission.ContextKeyType), gin2.UpdateOperationLogStatus, CreatePipelineTask) + taskV2.POST("", GetProductNameByPipelineTask, gin2.UpdateOperationLogStatus, CreatePipelineTask) taskV2.GET("/max/:max/start/:start/pipelines/:name", ListPipelineTasksResult) taskV2.GET("/id/:id/pipelines/:name", GetPipelineTask) - taskV2.POST("/id/:id/pipelines/:name/restart", GetProductNameByPipeline, gin2.IsHavePermission([]string{permission.WorkflowTaskUUID}, permission.ContextKeyType), gin2.UpdateOperationLogStatus, RestartPipelineTask) - taskV2.DELETE("/id/:id/pipelines/:name", GetProductNameByPipeline, gin2.IsHavePermission([]string{permission.WorkflowTaskUUID}, permission.ContextKeyType), gin2.UpdateOperationLogStatus, CancelTaskV2) + taskV2.POST("/id/:id/pipelines/:name/restart", GetProductNameByPipeline, gin2.UpdateOperationLogStatus, RestartPipelineTask) + taskV2.DELETE("/id/:id/pipelines/:name", GetProductNameByPipeline, gin2.UpdateOperationLogStatus, CancelTaskV2) taskV2.GET("/pipelines/:name/products", ListPipelineUpdatableProductNames) taskV2.GET("/file", GetPackageFile) taskV2.GET("/workflow/:pipelineName/taskId/:taskId", GetArtifactFile) @@ -105,12 +102,12 @@ func (*Router) Inject(router *gin.RouterGroup) { workflow := router.Group("workflow") { workflow.POST("/:productName/auto", AutoCreateWorkflow) - workflow.POST("", GetWorkflowProductName, gin2.IsHavePermission([]string{permission.WorkflowCreateUUID}, permission.ContextKeyType), gin2.UpdateOperationLogStatus, CreateWorkflow) - workflow.PUT("", GetWorkflowProductName, gin2.IsHavePermission([]string{permission.WorkflowUpdateUUID}, permission.ContextKeyType), gin2.UpdateOperationLogStatus, UpdateWorkflow) + workflow.POST("", GetWorkflowProductName, gin2.UpdateOperationLogStatus, CreateWorkflow) + workflow.PUT("", GetWorkflowProductName, gin2.UpdateOperationLogStatus, UpdateWorkflow) workflow.GET("", ListWorkflows) - workflow.GET("/testName/:testName", ListAllWorkflows) + workflow.GET("/testName/:testName", ListTestWorkflows) workflow.GET("/find/:name", FindWorkflow) - workflow.DELETE("/:name", GetProductNameByWorkflow, gin2.IsHavePermission([]string{permission.WorkflowDeleteUUID}, permission.ContextKeyType), gin2.UpdateOperationLogStatus, DeleteWorkflow) + workflow.DELETE("/:name", GetProductNameByWorkflow, gin2.UpdateOperationLogStatus, DeleteWorkflow) workflow.GET("/preset/:productName", PreSetWorkflow) workflow.PUT("/old/:old/new/:new", CopyWorkflow) @@ -124,12 +121,12 @@ func (*Router) Inject(router *gin.RouterGroup) { //todo 修改权限的uuid workflowtask.GET("/targets/:productName/:namespace", GetWorkflowArgs) workflowtask.GET("/preset/:namespace/:workflowName", PresetWorkflowArgs) - workflowtask.POST("", GetWorkflowTaskProductName, gin2.IsHavePermission([]string{permission.WorkflowTaskUUID}, permission.ContextKeyType), gin2.UpdateOperationLogStatus, CreateWorkflowTask) - workflowtask.PUT("", GetWorkflowTaskProductName, gin2.IsHavePermission([]string{permission.WorkflowTaskUUID}, permission.ContextKeyType), gin2.UpdateOperationLogStatus, CreateArtifactWorkflowTask) + workflowtask.POST("", GetWorkflowTaskProductName, gin2.UpdateOperationLogStatus, CreateWorkflowTask) + workflowtask.PUT("", GetWorkflowTaskProductName, gin2.UpdateOperationLogStatus, CreateArtifactWorkflowTask) workflowtask.GET("/max/:max/start/:start/pipelines/:name", ListWorkflowTasksResult) workflowtask.GET("/id/:id/pipelines/:name", GetWorkflowTask) - workflowtask.POST("/id/:id/pipelines/:name/restart", GetWorkflowTaskProductNameByTask, gin2.IsHavePermission([]string{permission.WorkflowTaskUUID}, permission.ContextKeyType), gin2.UpdateOperationLogStatus, RestartWorkflowTask) - workflowtask.DELETE("/id/:id/pipelines/:name", GetWorkflowTaskProductNameByTask, gin2.IsHavePermission([]string{permission.WorkflowTaskUUID}, permission.ContextKeyType), gin2.UpdateOperationLogStatus, CancelWorkflowTaskV2) + workflowtask.POST("/id/:id/pipelines/:name/restart", GetWorkflowTaskProductNameByTask, gin2.UpdateOperationLogStatus, RestartWorkflowTask) + workflowtask.DELETE("/id/:id/pipelines/:name", GetWorkflowTaskProductNameByTask, gin2.UpdateOperationLogStatus, CancelWorkflowTaskV2) } serviceTask := router.Group("servicetask") diff --git a/pkg/microservice/aslan/core/workflow/handler/sse.go b/pkg/microservice/aslan/core/workflow/handler/sse.go index a83214fa900888a5d91f9230696b76f61f653b47..3ba90e70ac7b3991fde608da3e8894f8decc0cbf 100644 --- a/pkg/microservice/aslan/core/workflow/handler/sse.go +++ b/pkg/microservice/aslan/core/workflow/handler/sse.go @@ -46,14 +46,14 @@ func GetPipelineTaskSSE(c *gin.Context) { err := wait.PollImmediateUntil(time.Second, func() (bool, error) { res, err := workflow.GetPipelineTaskV2(taskID, c.Param("name"), config.SingleType, ctx.Logger) if err != nil { - ctx.Logger.Errorf("[%s] GetPipelineTaskSSE error: %v", ctx.Username, err) + ctx.Logger.Errorf("[%s] GetPipelineTaskSSE error: %v", ctx.UserName, err) return false, err } msgChan <- res if time.Since(startTime).Minutes() == float64(60) { - ctx.Logger.Warnf("[%s] Query GetPipelineTaskSSE API over 60 minutes", ctx.Username) + ctx.Logger.Warnf("[%s] Query GetPipelineTaskSSE API over 60 minutes", ctx.UserName) } return false, nil @@ -74,7 +74,7 @@ func RunningPipelineTasksSSE(c *gin.Context) { msgChan <- workflow.RunningPipelineTasks() if time.Since(startTime).Minutes() == float64(60) { - ctx.Logger.Warnf("[%s] Query RunningPipelineTasksSSE API over 60 minutes", ctx.Username) + ctx.Logger.Warnf("[%s] Query RunningPipelineTasksSSE API over 60 minutes", ctx.UserName) } }, time.Second) }, ctx.Logger) @@ -89,7 +89,7 @@ func PendingPipelineTasksSSE(c *gin.Context) { msgChan <- workflow.PendingPipelineTasks() if time.Since(startTime).Minutes() == float64(60) { - ctx.Logger.Warnf("[%s] Query PendingPipelineTasksSSE API over 60 minutes", ctx.Username) + ctx.Logger.Warnf("[%s] Query PendingPipelineTasksSSE API over 60 minutes", ctx.UserName) } }, time.Second) }, ctx.Logger) @@ -116,14 +116,14 @@ func GetWorkflowTaskSSE(c *gin.Context) { err := wait.PollImmediateUntil(time.Second, func() (bool, error) { res, err := workflow.GetPipelineTaskV2(taskID, c.Param("name"), workflowTypeString, ctx.Logger) if err != nil { - ctx.Logger.Errorf("[%s] GetPipelineTaskSSE error: %v", ctx.Username, err) + ctx.Logger.Errorf("[%s] GetPipelineTaskSSE error: %v", ctx.UserName, err) return false, err } msgChan <- res if time.Since(startTime).Minutes() == float64(60) { - ctx.Logger.Warnf("[%s] Query GetPipelineTaskSSE API over 60 minutes", ctx.Username) + ctx.Logger.Warnf("[%s] Query GetPipelineTaskSSE API over 60 minutes", ctx.UserName) } return false, nil diff --git a/pkg/microservice/aslan/core/workflow/handler/workflow.go b/pkg/microservice/aslan/core/workflow/handler/workflow.go index 83de02637ea0656f5c9b8c902ec505c6f076b0ab..9f69a055a9290b97f57cb59d8c92717b5455a32b 100644 --- a/pkg/microservice/aslan/core/workflow/handler/workflow.go +++ b/pkg/microservice/aslan/core/workflow/handler/workflow.go @@ -78,15 +78,15 @@ func CreateWorkflow(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("CreateWorkflow json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, args.ProductTmplName, "新增", "工作流", args.Name, string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, args.ProductTmplName, "新增", "工作流", args.Name, string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) if err := c.ShouldBindWith(&args, binding.JSON); err != nil { ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) return } - args.UpdateBy = ctx.Username - args.CreateBy = ctx.Username + args.UpdateBy = ctx.UserName + args.CreateBy = ctx.UserName ctx.Err = workflow.CreateWorkflow(args, ctx.Logger) } @@ -103,14 +103,14 @@ func UpdateWorkflow(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("UpdateWorkflow json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, args.ProductTmplName, "更新", "工作流", args.Name, string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, args.ProductTmplName, "更新", "工作流", args.Name, string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) if err := c.ShouldBindWith(&args, binding.JSON); err != nil { ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) return } - args.UpdateBy = ctx.Username + args.UpdateBy = ctx.UserName ctx.Err = workflow.UpdateWorkflow(args, ctx.Logger) } @@ -118,14 +118,14 @@ func ListWorkflows(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - ctx.Resp, ctx.Err = workflow.ListWorkflows(c.Query("type"), c.Query("productName"), ctx.User.ID, ctx.Logger) + ctx.Resp, ctx.Err = workflow.ListWorkflows(c.Query("type"), c.Query("projectName"), ctx.UserID, ctx.Logger) } -func ListAllWorkflows(c *gin.Context) { +func ListTestWorkflows(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - ctx.Resp, ctx.Err = workflow.ListAllWorkflows(c.Param("testName"), ctx.User.ID, ctx.User.IsSuperUser, ctx.Logger) + ctx.Resp, ctx.Err = workflow.ListTestWorkflows(c.Param("testName"), c.QueryArray("projects"), ctx.Logger) } // FindWorkflow find a workflow @@ -140,7 +140,7 @@ func DeleteWorkflow(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - internalhandler.InsertOperationLog(c, ctx.Username, c.GetString("productName"), "删除", "工作流", c.Param("name"), "", ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, c.GetString("productName"), "删除", "工作流", c.Param("name"), "", ctx.Logger) ctx.Err = commonservice.DeleteWorkflow(c.Param("name"), ctx.RequestID, false, ctx.Logger) } @@ -155,5 +155,5 @@ func CopyWorkflow(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - ctx.Err = workflow.CopyWorkflow(c.Param("old"), c.Param("new"), ctx.Username, ctx.Logger) + ctx.Err = workflow.CopyWorkflow(c.Param("old"), c.Param("new"), ctx.UserName, ctx.Logger) } diff --git a/pkg/microservice/aslan/core/workflow/handler/workflow_task.go b/pkg/microservice/aslan/core/workflow/handler/workflow_task.go index 74b3b708339d608bf0136e0ac82567eefe07fc34..81a250a3d6647564304ef6dd0be841ec5ade8b5a 100644 --- a/pkg/microservice/aslan/core/workflow/handler/workflow_task.go +++ b/pkg/microservice/aslan/core/workflow/handler/workflow_task.go @@ -97,7 +97,7 @@ func CreateWorkflowTask(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("CreateWorkflowTask json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, args.ProductTmplName, "新增", "工作流-task", args.WorkflowName, string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, args.ProductTmplName, "新增", "工作流-task", args.WorkflowName, string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) if err := c.ShouldBindWith(&args, binding.JSON); err != nil { @@ -106,14 +106,14 @@ func CreateWorkflowTask(c *gin.Context) { } if args.WorkflowTaskCreator != setting.CronTaskCreator && args.WorkflowTaskCreator != setting.WebhookTaskCreator { - args.WorkflowTaskCreator = ctx.Username + args.WorkflowTaskCreator = ctx.UserName } - ctx.Resp, ctx.Err = workflow.CreateWorkflowTask(args, args.WorkflowTaskCreator, ctx.User.ID, ctx.User.IsSuperUser, ctx.Logger) + ctx.Resp, ctx.Err = workflow.CreateWorkflowTask(args, args.WorkflowTaskCreator, ctx.Logger) // 发送通知 if ctx.Err != nil { - commonservice.SendFailedTaskMessage(ctx.Username, args.ProductTmplName, args.WorkflowName, ctx.RequestID, config.WorkflowType, ctx.Err, ctx.Logger) + commonservice.SendFailedTaskMessage(ctx.UserName, args.ProductTmplName, args.WorkflowName, ctx.RequestID, config.WorkflowType, ctx.Err, ctx.Logger) } } @@ -130,7 +130,7 @@ func CreateArtifactWorkflowTask(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("CreateArtifactWorkflowTask json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, args.ProductTmplName, "新增", "工作流-task", args.WorkflowName, string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, args.ProductTmplName, "新增", "工作流-task", args.WorkflowName, string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) if err := c.ShouldBindWith(&args, binding.JSON); err != nil { @@ -139,10 +139,10 @@ func CreateArtifactWorkflowTask(c *gin.Context) { } if args.WorkflowTaskCreator != setting.CronTaskCreator && args.WorkflowTaskCreator != setting.WebhookTaskCreator { - args.WorkflowTaskCreator = ctx.Username + args.WorkflowTaskCreator = ctx.UserName } - ctx.Resp, ctx.Err = workflow.CreateArtifactWorkflowTask(args, args.WorkflowTaskCreator, ctx.User.ID, ctx.User.IsSuperUser, ctx.Logger) + ctx.Resp, ctx.Err = workflow.CreateArtifactWorkflowTask(args, args.WorkflowTaskCreator, ctx.Logger) } // ListWorkflowTasksResult workflowtask分页信息 @@ -188,7 +188,7 @@ func GetWorkflowTask(c *gin.Context) { func RestartWorkflowTask(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - internalhandler.InsertOperationLog(c, ctx.Username, c.GetString("productName"), "重启", "工作流-task", c.Param("name"), "", ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, c.GetString("productName"), "重启", "工作流-task", c.Param("name"), "", ctx.Logger) taskID, err := strconv.ParseInt(c.Param("id"), 10, 64) if err != nil { @@ -196,18 +196,18 @@ func RestartWorkflowTask(c *gin.Context) { return } - ctx.Err = workflow.RestartPipelineTaskV2(ctx.Username, taskID, c.Param("name"), config.WorkflowType, ctx.Logger) + ctx.Err = workflow.RestartPipelineTaskV2(ctx.UserName, taskID, c.Param("name"), config.WorkflowType, ctx.Logger) } func CancelWorkflowTaskV2(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - internalhandler.InsertOperationLog(c, ctx.Username, c.GetString("productName"), "取消", "工作流-task", c.Param("name"), "", ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, c.GetString("productName"), "取消", "工作流-task", c.Param("name"), "", ctx.Logger) taskID, err := strconv.ParseInt(c.Param("id"), 10, 64) if err != nil { ctx.Err = e.ErrInvalidParam.AddDesc("invalid task id") return } - ctx.Err = commonservice.CancelTaskV2(ctx.Username, c.Param("name"), taskID, config.WorkflowType, ctx.RequestID, ctx.Logger) + ctx.Err = commonservice.CancelTaskV2(ctx.UserName, c.Param("name"), taskID, config.WorkflowType, ctx.RequestID, ctx.Logger) } diff --git a/pkg/microservice/aslan/core/workflow/service/webhook/codehub_workflow_task.go b/pkg/microservice/aslan/core/workflow/service/webhook/codehub_workflow_task.go index 1b452cbc079ac0af1778cf20542677265aa7c963..10f08d79de7cf1ff33f9f464e10a19ec38ccd31d 100644 --- a/pkg/microservice/aslan/core/workflow/service/webhook/codehub_workflow_task.go +++ b/pkg/microservice/aslan/core/workflow/service/webhook/codehub_workflow_task.go @@ -30,7 +30,6 @@ import ( "github.com/koderover/zadig/pkg/setting" "github.com/koderover/zadig/pkg/tool/codehub" "github.com/koderover/zadig/pkg/types" - "github.com/koderover/zadig/pkg/types/permission" ) type codehubMergeEventMatcher struct { @@ -200,7 +199,7 @@ func TriggerWorkflowByCodehubEvent(event interface{}, baseURI, requestID string, args.RepoOwner = item.MainRepo.RepoOwner args.RepoName = item.MainRepo.RepoName // 3. create task with args - if resp, err := workflowservice.CreateWorkflowTask(args, setting.WebhookTaskCreator, permission.AnonymousUserID, false, log); err != nil { + if resp, err := workflowservice.CreateWorkflowTask(args, setting.WebhookTaskCreator, log); err != nil { log.Errorf("failed to create workflow task when receive push event %v due to %v ", event, err) mErr = multierror.Append(mErr, err) } else { diff --git a/pkg/microservice/aslan/core/workflow/service/webhook/gerrit.go b/pkg/microservice/aslan/core/workflow/service/webhook/gerrit.go index b3df30c12881a8a2dffc36cb72864ade0bc4752e..34e733b1eed4ae3fb4d1e1caa122d128d115c8ed 100644 --- a/pkg/microservice/aslan/core/workflow/service/webhook/gerrit.go +++ b/pkg/microservice/aslan/core/workflow/service/webhook/gerrit.go @@ -36,7 +36,7 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/command" gerritservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/gerrit" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/codehost" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/gerrit" "github.com/koderover/zadig/pkg/util" @@ -94,7 +94,7 @@ func updateServiceTemplateByGerritEvent(uri string, log *zap.SugaredLogger) erro log.Errorf("updateServiceTemplateByGerritEvent GetServiceTemplate err:%v", err) errs = multierror.Append(errs, err) } - detail, err := codehost.GetCodehostDetail(service.GerritCodeHostID) + detail, err := systemconfig.New().GetCodeHost(service.GerritCodeHostID) if err != nil { log.Errorf("updateServiceTemplateByGerritEvent GetCodehostDetail err:%v", err) errs = multierror.Append(errs, err) @@ -228,7 +228,7 @@ func SyncServiceTemplateFromGerrit(service *commonmodels.Service, log *zap.Sugar return nil } -func syncGerritLatestCommit(service *commonmodels.Service) (*codehost.Detail, error) { +func syncGerritLatestCommit(service *commonmodels.Service) (*systemconfig.CodeHost, error) { if service.GerritCodeHostID == 0 { return nil, fmt.Errorf("codehostId不能是空的") } @@ -238,12 +238,12 @@ func syncGerritLatestCommit(service *commonmodels.Service) (*codehost.Detail, er if service.GerritBranchName == "" { return nil, fmt.Errorf("branchName不能是空的") } - detail, err := codehost.GetCodehostDetail(service.GerritCodeHostID) + detail, err := systemconfig.New().GetCodeHost(service.GerritCodeHostID) if err != nil { return nil, err } - gerritCli := gerrit.NewClient(detail.Address, detail.OauthToken) + gerritCli := gerrit.NewClient(detail.Address, detail.AccessToken) commit, err := gerritCli.GetCommitByBranch(service.GerritRepoName, service.GerritBranchName) if err != nil { return detail, err diff --git a/pkg/microservice/aslan/core/workflow/service/webhook/gerrit_workflow_task.go b/pkg/microservice/aslan/core/workflow/service/webhook/gerrit_workflow_task.go index 0e941bd08f7c59ecca2e7e298c7bd29a797b4b7e..6ed9cd1a47d715bc980aed0796224957729612f3 100644 --- a/pkg/microservice/aslan/core/workflow/service/webhook/gerrit_workflow_task.go +++ b/pkg/microservice/aslan/core/workflow/service/webhook/gerrit_workflow_task.go @@ -34,10 +34,9 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/scmnotify" workflowservice "github.com/koderover/zadig/pkg/microservice/aslan/core/workflow/service/workflow" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/codehost" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" "github.com/koderover/zadig/pkg/tool/gerrit" "github.com/koderover/zadig/pkg/types" - "github.com/koderover/zadig/pkg/types/permission" ) type patchsetCreatedEvent struct { @@ -306,12 +305,12 @@ func TriggerWorkflowByGerritEvent(event *gerritTypeEvent, body []byte, uri, base if item.WorkflowArgs == nil { continue } - detail, err := codehost.GetCodehostDetail(item.MainRepo.CodehostID) + detail, err := systemconfig.New().GetCodeHost(item.MainRepo.CodehostID) if err != nil { log.Errorf("TriggerWorkflowByGerritEvent GetCodehostDetail err:%v", err) return err } - if detail.Source == gerrit.CodehostTypeGerrit { + if detail.Type == gerrit.CodehostTypeGerrit { log.Debugf("TriggerWorkflowByGerritEvent find gerrit hook in workflow %s", workflow.Name) matcher := createGerritEventMatcher(event, body, item, workflow, log) if matcher == nil { @@ -382,7 +381,7 @@ func TriggerWorkflowByGerritEvent(event *gerritTypeEvent, body []byte, uri, base workflowArgs.RepoOwner = item.MainRepo.RepoOwner workflowArgs.RepoName = item.MainRepo.RepoName - if resp, err := workflowservice.CreateWorkflowTask(workflowArgs, setting.WebhookTaskCreator, permission.AnonymousUserID, false, log); err != nil { + if resp, err := workflowservice.CreateWorkflowTask(workflowArgs, setting.WebhookTaskCreator, log); err != nil { log.Errorf("TriggerWorkflowByGerritEvent failed to create workflow task when receive push event %v due to %v ", event, err) errorList = multierror.Append(errorList, err) } else { @@ -411,7 +410,7 @@ func addWebHookUser(match gerritEventMatcher, domain string) { } } -func checkLatestTaskStaus(pipelineName, mergeRequestID, commitID string, detail *codehost.Detail, log *zap.SugaredLogger) bool { +func checkLatestTaskStaus(pipelineName, mergeRequestID, commitID string, detail *systemconfig.CodeHost, log *zap.SugaredLogger) bool { opt := &commonrepo.ListTaskOption{ PipelineName: pipelineName, Type: config.WorkflowType, @@ -435,7 +434,7 @@ func checkLatestTaskStaus(pipelineName, mergeRequestID, commitID string, detail } // 比较本次patchset 和 上一个触发任务的patchset 的change file是否相同 - cli := gerrit.NewClient(detail.Address, detail.OauthToken) + cli := gerrit.NewClient(detail.Address, detail.AccessToken) isDiff, err := cli.CompareTwoPatchset(mergeRequestID, commitID, tasks[0].TriggerBy.CommitID) if err != nil { log.Errorf("CompareTwoPatchset failed, mergeRequestID:%s, patchsetID:%s, oldPatchsetID:%s, err:%v", mergeRequestID, commitID, tasks[0].TriggerBy.CommitID, err) diff --git a/pkg/microservice/aslan/core/workflow/service/webhook/github.go b/pkg/microservice/aslan/core/workflow/service/webhook/github.go index 2d6e23ceaef62eae224ea5f551d7b1256cdfc807..19553661294269d029960b136a7895fff85721f1 100644 --- a/pkg/microservice/aslan/core/workflow/service/webhook/github.go +++ b/pkg/microservice/aslan/core/workflow/service/webhook/github.go @@ -37,8 +37,7 @@ import ( gitservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/git" workflowservice "github.com/koderover/zadig/pkg/microservice/aslan/core/workflow/service/workflow" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/codehost" - "github.com/koderover/zadig/pkg/shared/poetry" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" e "github.com/koderover/zadig/pkg/tool/errors" githubtool "github.com/koderover/zadig/pkg/tool/git/github" "github.com/koderover/zadig/pkg/types" @@ -50,32 +49,31 @@ const ( payloadFormParam = "payload" ) -func ProcessGithubHook(payload []byte, req *http.Request, requestID string, log *zap.SugaredLogger) (output string, err error) { +func ProcessGithubHook(payload []byte, req *http.Request, requestID string, log *zap.SugaredLogger) (string, error) { hookType := github.WebHookType(req) if hookType == "integration_installation" || hookType == "installation" || hookType == "ping" { - output = fmt.Sprintf("event %s received", hookType) - return + return fmt.Sprintf("event %s received", hookType), nil } hookSecret := gitservice.GetHookSecret() - if hookSecret == "" { var headers []string for header := range req.Header { headers = append(headers, fmt.Sprintf("%s: %s", header, req.Header.Get(header))) } - log.Infof("[Webhook] hook headers: \n %s", strings.Join(headers, "\n ")) } - err = validateSecret(payload, []byte(hookSecret), req) + err := validateSecret(payload, []byte(hookSecret), req) if err != nil { - return + log.Errorf("Failed to validate secret, err: %s", err) + return "", err } event, err := github.ParseWebHook(github.WebHookType(req), payload) if err != nil { - return + log.Errorf("Failed to parse webhook, err: %s", err) + return "", err } deliveryID := github.DeliveryID(req) @@ -86,15 +84,13 @@ func ProcessGithubHook(payload []byte, req *http.Request, requestID string, log switch et := event.(type) { case *github.PullRequestEvent: if *et.Action != "opened" && *et.Action != "synchronize" && *et.Action != "reopened" { - output = fmt.Sprintf("action %s is skipped", *et.Action) - return + return fmt.Sprintf("action %s is skipped", *et.Action), nil } tasks, err = prEventToPipelineTasks(et, requestID, log) if err != nil { log.Errorf("prEventToPipelineTasks error: %v", err) - err = e.ErrGithubWebHook.AddErr(err) - return + return "", e.ErrGithubWebHook.AddErr(err) } case *github.PushEvent: @@ -112,40 +108,34 @@ func ProcessGithubHook(payload []byte, req *http.Request, requestID string, log tasks, err = pushEventToPipelineTasks(et, requestID, log) if err != nil { - log.Infof("pushEventToPipelineTasks error: %v", err) - err = e.ErrGithubWebHook.AddErr(err) - return + log.Errorf("pushEventToPipelineTasks error: %v", err) + return "", e.ErrGithubWebHook.AddErr(err) } case *github.CheckRunEvent: // The action performed. Can be "created", "updated", "rerequested" or "requested_action". if *et.Action != "rerequested" { - output = fmt.Sprintf("action %s is skipped", *et.Action) - return + return fmt.Sprintf("action %s is skipped", *et.Action), nil } id := et.CheckRun.GetExternalID() items := strings.Split(id, "/") if len(items) != 2 { - err = fmt.Errorf("invalid CheckRun ExternalID %s", id) - return + return "", fmt.Errorf("invalid CheckRun ExternalID %s", id) } pipeName := items[0] var taskID int64 taskID, err = strconv.ParseInt(items[1], 10, 64) if err != nil { - err = fmt.Errorf("invalid taskID in CheckRun ExternalID %s", id) - return + return "", fmt.Errorf("invalid taskID in CheckRun ExternalID %s", id) } if err = workflowservice.RestartPipelineTaskV2("CheckRun", taskID, pipeName, config.SingleType, log); err != nil { - err = e.ErrGithubWebHook.AddErr(err) - return + return "", e.ErrGithubWebHook.AddErr(err) } default: - output = fmt.Sprintf("event %s not support", hookType) - return + return fmt.Sprintf("event %s not support", hookType), nil } for _, task := range tasks { @@ -159,7 +149,7 @@ func ProcessGithubHook(payload []byte, req *http.Request, requestID string, log log.Infof("[Webhook] %s triggered task %s:%d", deliveryID, task.PipelineName, resp.TaskID) } - return + return "", nil } func validateSecret(payload, secretKey []byte, r *http.Request) error { @@ -183,13 +173,13 @@ func prEventToPipelineTasks(event *github.PullRequestEvent, requestID string, lo commitMessage = *event.PullRequest.Title ) - address, err := util.GetAddress(event.Repo.GetURL()) + address, err := util.GetAddress(event.Repo.GetHTMLURL()) if err != nil { log.Errorf("GetAddress failed, url: %s, err: %s", event.Repo.GetURL(), err) return nil, err } - ch, err := codehost.GetCodeHostInfo( - &codehost.Option{CodeHostType: poetry.GitHubProvider, Address: address, Namespace: owner}) + ch, err := systemconfig.GetCodeHostInfo( + &systemconfig.Option{CodeHostType: systemconfig.GitHubProvider, Address: address, Namespace: owner}) if err != nil { log.Errorf("GetCodeHostInfo failed, err: %v", err) return nil, err @@ -327,8 +317,8 @@ func pushEventToPipelineTasks(event *github.PushEvent, requestID string, log *za log.Errorf("GetAddress failed, url: %s, err: %s", event.Repo.GetURL(), err) return nil, err } - ch, err := codehost.GetCodeHostInfo( - &codehost.Option{CodeHostType: poetry.GitHubProvider, Address: address, Namespace: owner}) + ch, err := systemconfig.GetCodeHostInfo( + &systemconfig.Option{CodeHostType: systemconfig.GitHubProvider, Address: address, Namespace: owner}) if err != nil { log.Errorf("GetCodeHostInfo failed, err: %v", err) return nil, err diff --git a/pkg/microservice/aslan/core/workflow/service/webhook/github_workflow_task.go b/pkg/microservice/aslan/core/workflow/service/webhook/github_workflow_task.go index 7f1a379a515f7515991271ee7a7fd0a7d632da95..3cd1f374fdcd9c26cf2700c89920ecb500d90250 100644 --- a/pkg/microservice/aslan/core/workflow/service/webhook/github_workflow_task.go +++ b/pkg/microservice/aslan/core/workflow/service/webhook/github_workflow_task.go @@ -33,9 +33,8 @@ import ( git "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/github" workflowservice "github.com/koderover/zadig/pkg/microservice/aslan/core/workflow/service/workflow" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/codehost" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" "github.com/koderover/zadig/pkg/types" - "github.com/koderover/zadig/pkg/types/permission" ) const SplitSymbol = "&" @@ -324,7 +323,7 @@ func TriggerWorkflowByGithubEvent(event interface{}, baseURI, deliveryID, reques args.HookPayload = hookPayload // 3. create task with args - if resp, err := workflowservice.CreateWorkflowTask(args, setting.WebhookTaskCreator, permission.AnonymousUserID, false, log); err != nil { + if resp, err := workflowservice.CreateWorkflowTask(args, setting.WebhookTaskCreator, log); err != nil { log.Errorf("failed to create workflow task when receive push event due to %v ", err) mErr = multierror.Append(mErr, err) } else { @@ -341,12 +340,12 @@ func TriggerWorkflowByGithubEvent(event interface{}, baseURI, deliveryID, reques } func findChangedFilesOfPullRequest(event *github.PullRequestEvent, codehostID int) ([]string, error) { - detail, err := codehost.GetCodehostDetail(codehostID) + detail, err := systemconfig.New().GetCodeHost(codehostID) if err != nil { return nil, fmt.Errorf("failed to find codehost %d: %v", codehostID, err) } //pullrequest文件修改 - githubCli := git.NewClient(detail.OauthToken, config.ProxyHTTPSAddr()) + githubCli := git.NewClient(detail.AccessToken, config.ProxyHTTPSAddr()) commitComparison, _, err := githubCli.Repositories.CompareCommits(context.Background(), *event.PullRequest.Base.Repo.Owner.Login, *event.PullRequest.Base.Repo.Name, *event.PullRequest.Base.SHA, *event.PullRequest.Head.SHA) if err != nil { return nil, fmt.Errorf("failed to get changes from github, err: %v", err) diff --git a/pkg/microservice/aslan/core/workflow/service/webhook/gitlab.go b/pkg/microservice/aslan/core/workflow/service/webhook/gitlab.go index 390139988c0915ed7c491375c5e4f34efb594134..7fafcdec818fa50e10807552d337ebeb1950bea7 100644 --- a/pkg/microservice/aslan/core/workflow/service/webhook/gitlab.go +++ b/pkg/microservice/aslan/core/workflow/service/webhook/gitlab.go @@ -312,8 +312,8 @@ func updateServiceTemplateByPushEvent(event *EventPush, log *zap.SugaredLogger) func GetGitlabServiceTemplates() ([]*commonmodels.Service, error) { opt := &commonrepo.ServiceListOption{ - Type: setting.K8SDeployType, - Source: setting.SourceFromGitlab, + Type: setting.K8SDeployType, + Source: setting.SourceFromGitlab, } return commonrepo.NewServiceColl().ListMaxRevisions(opt) } diff --git a/pkg/microservice/aslan/core/workflow/service/webhook/gitlab_workflow_task.go b/pkg/microservice/aslan/core/workflow/service/webhook/gitlab_workflow_task.go index 73eeb855d394ca69261e241a9cacb1aebf8ef48a..d8fdc3a4765ecf4914a2a5316fc3b9e31b49abb5 100644 --- a/pkg/microservice/aslan/core/workflow/service/webhook/gitlab_workflow_task.go +++ b/pkg/microservice/aslan/core/workflow/service/webhook/gitlab_workflow_task.go @@ -36,12 +36,11 @@ import ( environmentservice "github.com/koderover/zadig/pkg/microservice/aslan/core/environment/service" workflowservice "github.com/koderover/zadig/pkg/microservice/aslan/core/workflow/service/workflow" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/codehost" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" e "github.com/koderover/zadig/pkg/tool/errors" gitlabtool "github.com/koderover/zadig/pkg/tool/git/gitlab" "github.com/koderover/zadig/pkg/tool/log" "github.com/koderover/zadig/pkg/types" - "github.com/koderover/zadig/pkg/types/permission" "github.com/koderover/zadig/pkg/util" ) @@ -152,13 +151,13 @@ func (gpem *gitlabPushEventMatcher) Match(hookRepo *commonmodels.MainHookRepo) ( hookRepo.Branch = getBranchFromRef(ev.Ref) var changedFiles []string - detail, err := codehost.GetCodehostDetail(hookRepo.CodehostID) + detail, err := systemconfig.New().GetCodeHost(hookRepo.CodehostID) if err != nil { gpem.log.Errorf("GetCodehostDetail error: %s", err) return false, err } - client, err := gitlabtool.NewClient(detail.Address, detail.OauthToken) + client, err := gitlabtool.NewClient(detail.Address, detail.AccessToken) if err != nil { gpem.log.Errorf("NewClient error: %s", err) return false, err @@ -299,7 +298,7 @@ func TriggerWorkflowByGitlabEvent(event interface{}, baseURI, requestID string, args.RepoName = item.MainRepo.RepoName // 3. create task with args if item.WorkflowArgs.BaseNamespace == "" { - if resp, err := workflowservice.CreateWorkflowTask(args, setting.WebhookTaskCreator, permission.AnonymousUserID, false, log); err != nil { + if resp, err := workflowservice.CreateWorkflowTask(args, setting.WebhookTaskCreator, log); err != nil { log.Errorf("failed to create workflow task when receive push event %v due to %v ", event, err) mErr = multierror.Append(mErr, err) // 单独创建一条通知,展示任务创建失败的错误信息 @@ -324,12 +323,12 @@ func TriggerWorkflowByGitlabEvent(event interface{}, baseURI, requestID string, } func findChangedFilesOfMergeRequest(event *gitlab.MergeEvent, codehostID int) ([]string, error) { - detail, err := codehost.GetCodehostDetail(codehostID) + detail, err := systemconfig.New().GetCodeHost(codehostID) if err != nil { return nil, fmt.Errorf("failed to find codehost %d: %v", codehostID, err) } - client, err := gitlabtool.NewClient(detail.Address, detail.OauthToken) + client, err := gitlabtool.NewClient(detail.Address, detail.AccessToken) if err != nil { log.Error(err) return nil, e.ErrCodehostListProjects.AddDesc(err.Error()) @@ -344,12 +343,12 @@ func InitDiffNote(ev *gitlab.MergeEvent, mainRepo *commonmodels.MainHookRepo, lo body := "KodeRover CI 检查中..." // 调用gitlab api获取相关数据 - detail, err := codehost.GetCodehostDetail(mainRepo.CodehostID) + detail, err := systemconfig.New().GetCodeHost(mainRepo.CodehostID) if err != nil { log.Errorf("GetCodehostDetail failed, codehost:%d, err:%v", mainRepo.CodehostID, err) return fmt.Errorf("failed to find codehost %d: %v", mainRepo.CodehostID, err) } - cli, _ := gitlab.NewOAuthClient(detail.OauthToken, gitlab.WithBaseURL(detail.Address)) + cli, _ := gitlab.NewOAuthClient(detail.AccessToken, gitlab.WithBaseURL(detail.Address)) opt := &commonrepo.DiffNoteFindOpt{ CodehostID: mainRepo.CodehostID, @@ -403,7 +402,7 @@ func InitDiffNote(ev *gitlab.MergeEvent, mainRepo *commonmodels.MainHookRepo, lo Source: "gitlab", ProjectID: mainRepo.RepoOwner + "/" + mainRepo.RepoName, Address: detail.Address, - OauthToken: detail.OauthToken, + OauthToken: detail.AccessToken, }, MergeRequestID: ev.ObjectAttributes.IID, CommitID: commitID, @@ -471,7 +470,7 @@ func CreateEnvAndTaskByPR(workflowArgs *commonmodels.WorkflowTaskArgs, prID int, } workflowArgs.Namespace = envName - taskResp, err := workflowservice.CreateWorkflowTask(workflowArgs, setting.WebhookTaskCreator, permission.AnonymousUserID, false, log) + taskResp, err := workflowservice.CreateWorkflowTask(workflowArgs, setting.WebhookTaskCreator, log) if err != nil { return fmt.Errorf("CreateEnvAndTaskByPR CreateWorkflowTask err:%v ", err) } diff --git a/pkg/microservice/aslan/core/workflow/service/webhook/utils.go b/pkg/microservice/aslan/core/workflow/service/webhook/utils.go index 2b5531c6733df7f5cbf2dc4239b3deeed0479267..57951755e22369058012e8379dbe5ef56155e2a0 100644 --- a/pkg/microservice/aslan/core/workflow/service/webhook/utils.go +++ b/pkg/microservice/aslan/core/workflow/service/webhook/utils.go @@ -35,8 +35,7 @@ import ( commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/codehub" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/codehost" - "github.com/koderover/zadig/pkg/shared/poetry" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" e "github.com/koderover/zadig/pkg/tool/errors" githubtool "github.com/koderover/zadig/pkg/tool/git/github" gitlabtool "github.com/koderover/zadig/pkg/tool/git/gitlab" @@ -199,11 +198,11 @@ func syncCodehubLatestCommit(service *commonmodels.Service) error { } func getCodehubClientByAddress(address string) (*codehub.Client, error) { - opt := &codehost.Option{ + opt := &systemconfig.Option{ Address: address, - CodeHostType: codehost.CodeHubProvider, + CodeHostType: systemconfig.CodeHubProvider, } - codehost, err := codehost.GetCodeHostInfo(opt) + codehost, err := systemconfig.GetCodeHostInfo(opt) if err != nil { log.Error(err) return nil, e.ErrCodehostListProjects.AddDesc("git client is nil") @@ -214,11 +213,11 @@ func getCodehubClientByAddress(address string) (*codehub.Client, error) { } func getGitlabClientByAddress(address string) (*gitlabtool.Client, error) { - opt := &codehost.Option{ + opt := &systemconfig.Option{ Address: address, - CodeHostType: codehost.GitLabProvider, + CodeHostType: systemconfig.GitLabProvider, } - codehost, err := codehost.GetCodeHostInfo(opt) + codehost, err := systemconfig.GetCodeHostInfo(opt) if err != nil { log.Error(err) return nil, e.ErrCodehostListProjects.AddDesc("git client is nil") @@ -337,8 +336,8 @@ func syncContentFromGithub(args *commonmodels.Service, log *zap.SugaredLogger) e return errors.New("invalid url " + args.SrcPath) } - ch, err := codehost.GetCodeHostInfo( - &codehost.Option{CodeHostType: poetry.GitHubProvider, Address: address, Namespace: owner}) + ch, err := systemconfig.GetCodeHostInfo( + &systemconfig.Option{CodeHostType: systemconfig.GitHubProvider, Address: address, Namespace: owner}) if err != nil { log.Errorf("GetCodeHostInfo failed, srcPath:%s, err:%v", args.SrcPath, err) return err diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/convert.go b/pkg/microservice/aslan/core/workflow/service/workflow/convert.go index 8116274260d8665e29a909c85358ab53a6a029da..7d98f8c953a5c84932003280b188e04d5c076f7c 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/convert.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/convert.go @@ -61,7 +61,6 @@ func ConvertQueueToTask(queueTask *commonmodels.Queue) *task.Task { ServiceTaskArgs: queueTask.ServiceTaskArgs, ConfigPayload: queueTask.ConfigPayload, Error: queueTask.Error, - OrgID: queueTask.OrgID, Services: queueTask.Services, Render: queueTask.Render, StorageURI: queueTask.StorageURI, @@ -107,7 +106,6 @@ func ConvertTaskToQueue(task *task.Task) *commonmodels.Queue { ServiceTaskArgs: task.ServiceTaskArgs, ConfigPayload: task.ConfigPayload, Error: task.Error, - OrgID: task.OrgID, Services: task.Services, Render: task.Render, StorageURI: task.StorageURI, diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/gerrit.go b/pkg/microservice/aslan/core/workflow/service/workflow/gerrit.go index b5be0c5edd1078286fe01d64f4d5553dff5e97a8..dae225e4c46e8138ee856a0217f5d75a74246156 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/gerrit.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/gerrit.go @@ -24,7 +24,7 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/config" commonmodels "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/codehost" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" "github.com/koderover/zadig/pkg/tool/gerrit" "github.com/koderover/zadig/pkg/tool/httpclient" ) @@ -36,10 +36,7 @@ func CreateGerritWebhook(workflow *commonmodels.Workflow, log *zap.SugaredLogger continue } - opt := &codehost.Option{ - CodeHostID: workflowWebhook.MainRepo.CodehostID, - } - detail, err := codehost.GetCodeHostInfo(opt) + detail, err := systemconfig.New().GetCodeHost(workflowWebhook.MainRepo.CodehostID) if err != nil { return err } @@ -88,10 +85,7 @@ func UpdateGerritWebhook(currentWorkflow *commonmodels.Workflow, log *zap.Sugare continue } - opt := &codehost.Option{ - CodeHostID: oldWorkflowWebhook.MainRepo.CodehostID, - } - detail, err := codehost.GetCodeHostInfo(opt) + detail, err := systemconfig.New().GetCodeHost(oldWorkflowWebhook.MainRepo.CodehostID) if err != nil { return err } @@ -113,10 +107,7 @@ func UpdateGerritWebhook(currentWorkflow *commonmodels.Workflow, log *zap.Sugare continue } - opt := &codehost.Option{ - CodeHostID: workflowWebhook.MainRepo.CodehostID, - } - detail, err := codehost.GetCodeHostInfo(opt) + detail, err := systemconfig.New().GetCodeHost(workflowWebhook.MainRepo.CodehostID) if err != nil { return err } @@ -155,10 +146,7 @@ func DeleteGerritWebhook(workflow *commonmodels.Workflow, log *zap.SugaredLogger continue } - opt := &codehost.Option{ - CodeHostID: workflowWebhook.MainRepo.CodehostID, - } - detail, err := codehost.GetCodeHostInfo(opt) + detail, err := systemconfig.New().GetCodeHost(workflowWebhook.MainRepo.CodehostID) if err != nil { return err } diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/github.go b/pkg/microservice/aslan/core/workflow/service/workflow/github.go index 4a93821185fac319d3a2c4d2702bb2d46a5c44cc..57155407bcce28d87d42d5d4b3d605b66eb7cc00 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/github.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/github.go @@ -27,7 +27,7 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models/task" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/github" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/codehost" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" e "github.com/koderover/zadig/pkg/tool/errors" ) @@ -85,9 +85,9 @@ func createGitCheck(pt *task.Task, log *zap.SugaredLogger) error { } log.Infof("Init GitHub status") - ch, err := codehost.GetCodeHostInfoByID(pt.TriggerBy.CodehostID) + ch, err := systemconfig.New().GetCodeHost(pt.TriggerBy.CodehostID) if err != nil { - log.Errorf("GetCodeHostInfoByID failed, err:%v", err) + log.Errorf("Failed to get codeHost, err:%v", err) return e.ErrGithubUpdateStatus.AddErr(err) } gc := github.NewClient(ch.AccessToken, config.ProxyHTTPSAddr()) diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/gitlab.go b/pkg/microservice/aslan/core/workflow/service/workflow/gitlab.go index 1d15a7d656e619d9865d14975401386ed6815cea..21549bdea125fe4bed3a4ca9824977cdf532bdad 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/gitlab.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/gitlab.go @@ -26,7 +26,7 @@ import ( "go.uber.org/zap" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/codehost" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" "github.com/koderover/zadig/pkg/tool/gerrit" ) @@ -40,10 +40,7 @@ type RepoCommit struct { } func QueryByBranch(id int, owner, name, branch string, log *zap.SugaredLogger) (*RepoCommit, error) { - opt := &codehost.Option{ - CodeHostID: id, - } - ch, err := codehost.GetCodeHostInfo(opt) + ch, err := systemconfig.New().GetCodeHost(id) if err != nil { return nil, err } @@ -90,10 +87,7 @@ func QueryByBranch(id int, owner, name, branch string, log *zap.SugaredLogger) ( } func QueryByTag(id int, owner, name, tag string, log *zap.SugaredLogger) (*RepoCommit, error) { - opt := &codehost.Option{ - CodeHostID: id, - } - ch, err := codehost.GetCodeHostInfo(opt) + ch, err := systemconfig.New().GetCodeHost(id) if err != nil { return nil, err } @@ -150,10 +144,7 @@ type PRCommit struct { func GetLatestPrCommit(codehostID, pr int, namespace, projectName string, log *zap.SugaredLogger) (*PRCommit, error) { projectID := fmt.Sprintf("%s/%s", namespace, projectName) - opt := &codehost.Option{ - CodeHostID: codehostID, - } - ch, err := codehost.GetCodeHostInfo(opt) + ch, err := systemconfig.New().GetCodeHost(codehostID) if err != nil { return nil, err } diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/nsq_handlers.go b/pkg/microservice/aslan/core/workflow/service/workflow/nsq_handlers.go index 2b72a867e50bdffc4d1e70fd247e5404936bad2a..5837a6b9fd004f4476c3b44fd4f6a23fba9a1f48 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/nsq_handlers.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/nsq_handlers.go @@ -18,10 +18,8 @@ package workflow import ( "context" - "encoding/base64" "encoding/json" "encoding/xml" - "errors" "fmt" "io/ioutil" "net/http" @@ -33,6 +31,7 @@ import ( dockerCli "github.com/docker/docker/client" "github.com/docker/go-connections/sockets" "github.com/nsqio/go-nsq" + "github.com/pkg/errors" "go.uber.org/zap" "github.com/koderover/zadig/pkg/microservice/aslan/config" @@ -46,10 +45,11 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/registry" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/s3" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/poetry" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" "github.com/koderover/zadig/pkg/tool/git/gitlab" "github.com/koderover/zadig/pkg/tool/log" s3tool "github.com/koderover/zadig/pkg/tool/s3" + "github.com/koderover/zadig/pkg/types" "github.com/koderover/zadig/pkg/util" ) @@ -64,12 +64,11 @@ type TaskAckHandler struct { deliveryArtifactColl *commonrepo.DeliveryArtifactColl deliveryActivityColl *commonrepo.DeliveryActivityColl TestTaskStatColl *commonrepo.TestTaskStatColl - PoetryClient *poetry.Client messages chan *nsq.Message log *zap.SugaredLogger } -func NewTaskAckHandler(poetryServer, poetryRootKey string, maxInFlight int, log *zap.SugaredLogger) *TaskAckHandler { +func NewTaskAckHandler(maxInFlight int, log *zap.SugaredLogger) *TaskAckHandler { return &TaskAckHandler{ queue: NewPipelineQueue(log), ptColl: commonrepo.NewTaskColl(), @@ -79,7 +78,6 @@ func NewTaskAckHandler(poetryServer, poetryRootKey string, maxInFlight int, log deliveryArtifactColl: commonrepo.NewDeliveryArtifactColl(), deliveryActivityColl: commonrepo.NewDeliveryActivityColl(), TestTaskStatColl: commonrepo.NewTestTaskStatColl(), - PoetryClient: poetry.New(poetryServer, poetryRootKey), messages: make(chan *nsq.Message, maxInFlight*10), log: log, } @@ -215,6 +213,57 @@ func (h *TaskAckHandler) handle(message *nsq.Message) error { return nil } +// get docker file content from codehost +// TODO need to support codehub and gerrit +func getRawFileContent(codehostID int, repo, owner, branch, filePath string) ([]byte, error) { + ch, err := systemconfig.New().GetCodeHost(codehostID) + if err != nil { + return nil, errors.Wrapf(err, "Failed to get codeHost info %d", codehostID) + } + switch ch.Type { + case setting.SourceFromGitlab: + cli, err := gitlab.NewClient(ch.Address, ch.AccessToken) + if err != nil { + return nil, errors.Wrapf(err, "Failed to get gitlab client") + } + return cli.GetRawFile(repo, owner, branch, filePath) + case setting.SourceFromGithub: + gitClient := git.NewClient(ch.AccessToken, config.ProxyHTTPSAddr()) + return gitClient.GetFileContent(owner, repo, filePath, branch) + default: + return nil, fmt.Errorf("Failed to create client for codehostID: %d", codehostID) + } +} + +func (h *TaskAckHandler) getDockerfileContent(build *types.Repository, ctx *task.DockerBuildCtx) string { + switch ctx.Source { + case setting.DockerfileSourceTemplate: + content, err := commonservice.GetDockerfileTemplateContent(ctx.TemplateID) + if err != nil { + h.log.Errorf("Failed to get dockerfile template content, err: %v", err) + return "" + } + return content + case setting.DockerfileSourceLocal: + path := ctx.DockerFile + pathArray := strings.Split(path, "/") + if len(pathArray[0])+1 >= len(path) { + h.log.Errorf("Failed to get dockerfile content, build context: %+v", *ctx) + return "" + } + dockerfilePath := path[len(pathArray[0])+1:] + content, err := getRawFileContent(build.CodehostID, build.RepoName, build.RepoOwner, build.Branch, dockerfilePath) + if err != nil { + h.log.Errorf("Failed to get dockerfile content, err %s", err) + return "" + } + return string(content) + default: // from local + h.log.Errorf("Failed to get dockerfile content, illegal source %s", ctx.Source) + return "" + } +} + func (h *TaskAckHandler) uploadTaskData(pt *task.Task) error { deliveryArtifacts := make([]*commonmodels.DeliveryArtifact, 0) if pt.Type == config.WorkflowType { @@ -292,35 +341,7 @@ func (h *TaskAckHandler) uploadTaskData(pt *task.Task) error { if buildInfo.JobCtx.DockerBuildCtx != nil { for _, build := range buildInfo.JobCtx.Builds { - path := buildInfo.JobCtx.DockerBuildCtx.DockerFile - pathArray := strings.Split(path, "/") - dockerfilePath := path[len(pathArray[0])+1:] - if strings.Contains(build.Address, "gitlab") { - cli, err := gitlab.NewClient(build.Address, build.OauthToken) - if err != nil { - h.log.Errorf("Failed to get gitlab client, err: %v", err) - continue - } - content, err := cli.GetRawFile(build.RepoOwner, build.RepoName, build.Branch, dockerfilePath) - if err != nil { - h.log.Errorf("uploadTaskData gitlab GetRawFile err:%v", err) - continue - } - deliveryArtifact.DockerFile = string(content) - } else { - gitClient := git.NewClient(build.OauthToken, config.ProxyHTTPSAddr()) - fileContent, _, _, _ := gitClient.Repositories.GetContents(context.Background(), build.RepoOwner, build.RepoName, dockerfilePath, nil) - if fileContent != nil { - dockerfileContent := *fileContent.Content - dockerfileContent = dockerfileContent[:len(dockerfileContent)-2] - content, err := base64.StdEncoding.DecodeString(dockerfileContent) - if err != nil { - h.log.Errorf("uploadTaskData github GetRawFile err:%v", err) - continue - } - deliveryArtifact.DockerFile = string(content) - } - } + deliveryArtifact.DockerFile = h.getDockerfileContent(build, buildInfo.JobCtx.DockerBuildCtx) } } deliveryArtifactArray = append(deliveryArtifactArray, deliveryArtifact) @@ -693,7 +714,7 @@ func (h *TaskAckHandler) createVersion(pt *task.Task) error { } if isDeploy { //版本交付 - return commonservice.AddDeliveryVersion(1, int(pt.TaskID), pt.ProductName, pt.PipelineName, pt, log.SugaredLogger()) + return commonservice.AddDeliveryVersion(int(pt.TaskID), pt.ProductName, pt.PipelineName, pt, log.SugaredLogger()) } } } diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/pipeline.go b/pkg/microservice/aslan/core/workflow/service/workflow/pipeline.go index 345edc271cb166c99965f4c8100be33fc403820e..8ba33b4a1b920efa5a35c845801b5d31bfa813f7 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/pipeline.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/pipeline.go @@ -42,7 +42,7 @@ func ListPipelines(log *zap.SugaredLogger) ([]*commonmodels.Pipeline, error) { return resp, nil } -func GetPipeline(userID int, pipelineName string, log *zap.SugaredLogger) (*commonmodels.Pipeline, error) { +func GetPipeline(userID, pipelineName string, log *zap.SugaredLogger) (*commonmodels.Pipeline, error) { resp, err := commonrepo.NewPipelineColl().Find(&commonrepo.PipelineFindOption{Name: pipelineName}) if err != nil { log.Error(err) diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_controller.go b/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_controller.go index 7329538d8756a0cff77684be5cabb706f2719987..d368d0b5adc55a5ef0ff0265701ab26f37566fad 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_controller.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_controller.go @@ -43,7 +43,7 @@ func SubScribeNSQ() error { // init ack consumer ackConfig := nsqservice.Config() ackConfig.MaxInFlight = 50 - ackHandler := NewTaskAckHandler(config.PoetryAPIServer(), config.PoetryAPIRootKey(), ackConfig.MaxInFlight, logger) + ackHandler := NewTaskAckHandler(ackConfig.MaxInFlight, logger) err := nsqservice.SubScribe(setting.TopicAck, "ack", 1, ackConfig, ackHandler) if err != nil { logger.Errorf("ack subscription failed, the error is: %v", err) diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_status.go b/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_status.go index 3f50ddafd40b6b9b50ccfc23113d6d2e8f54d307..3d468e7e6b7d0a68890b01bd8dc3be7a3d7b71c2 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_status.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_status.go @@ -50,7 +50,7 @@ type PipelinePreview struct { TotalSuccess int `bson:"-" json:"total_success"` } -func ListPipelinesPreview(userID int, log *zap.SugaredLogger) ([]*PipelinePreview, error) { +func ListPipelinesPreview(userID string, log *zap.SugaredLogger) ([]*PipelinePreview, error) { resp := make([]*PipelinePreview, 0) pipelineList, err := commonrepo.NewPipelineColl().List(&commonrepo.PipelineListOption{}) diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_task.go index f8d594e5a1b2999a62bba424657708cd738cbae2..2114029637005a8afcc8b8853a76396727dc0293 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_task.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_task.go @@ -40,7 +40,7 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/s3" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/scmnotify" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/poetry" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" e "github.com/koderover/zadig/pkg/tool/errors" krkubeclient "github.com/koderover/zadig/pkg/tool/kube/client" "github.com/koderover/zadig/pkg/tool/kube/getter" @@ -165,7 +165,7 @@ func CreatePipelineTask(args *commonmodels.TaskArgs, log *zap.SugaredLogger) (*C } } - jiraInfo, _ := poetry.GetJiraInfo(config.PoetryAPIServer(), config.PoetryAPIRootKey()) + jiraInfo, _ := systemconfig.New().GetJiraInfo() if jiraInfo != nil { jiraTask, err := AddPipelineJiraSubTask(pipeline, log) if err != nil { @@ -198,7 +198,6 @@ func CreatePipelineTask(args *commonmodels.TaskArgs, log *zap.SugaredLogger) (*C MultiRun: pipeline.MultiRun, BuildModuleVer: pipeline.BuildModuleVer, Target: pipeline.Target, - OrgID: pipeline.OrgID, StorageURI: defaultStorageURI, } @@ -387,7 +386,7 @@ func RestartPipelineTaskV2(userName string, taskID int64, pipelineName string, t subBuildTaskMap := subStage.SubTasks for serviceModule, subTask := range subBuildTaskMap { if buildInfo, err := base.ToBuildTask(subTask); err == nil { - if newModules, err := commonrepo.NewBuildColl().List(&commonrepo.BuildListOption{Targets: []string{serviceModule}, ServiceName: buildInfo.Service, ProductName: t.ProductName}); err == nil { + if newModules, err := commonrepo.NewBuildColl().List(&commonrepo.BuildListOption{Targets: []string{serviceModule}, ServiceName: buildInfo.Service, ProductName: t.ProductName}); err == nil && len(newModules) > 0 { newBuildInfo := newModules[0] buildInfo.JobCtx.BuildSteps = []*task.BuildStep{} if newBuildInfo.Scripts != "" { diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_validation.go b/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_validation.go index 8eb8f220b319a3b0798f8b2c97ad0afe20f09fa7..58099249081c06d6f672727374e1964f807d9149 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_validation.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_validation.go @@ -45,7 +45,7 @@ import ( git "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/github" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/codehost" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" "github.com/koderover/zadig/pkg/shared/kube/wrapper" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/kube/getter" @@ -257,10 +257,7 @@ func FmtBuilds(builds []*types.Repository, log *zap.SugaredLogger) { log.Error("codehostID can't be empty") return } - opt := &codehost.Option{ - CodeHostID: cID, - } - detail, err := codehost.GetCodeHostInfo(opt) + detail, err := systemconfig.New().GetCodeHost(cID) if err != nil { log.Error(err) return @@ -305,15 +302,12 @@ func SetTriggerBuilds(builds []*types.Repository, buildArgs []*types.Repository, } func setBuildInfo(build *types.Repository, log *zap.SugaredLogger) { - opt := &codehost.Option{ - CodeHostID: build.CodehostID, - } - codeHostInfo, err := codehost.GetCodeHostInfo(opt) + codeHostInfo, err := systemconfig.New().GetCodeHost(build.CodehostID) if err != nil { log.Errorf("failed to get codehost detail %d %v", build.CodehostID, err) return } - if codeHostInfo.Type == codehost.GitLabProvider || codeHostInfo.Type == codehost.GerritProvider { + if codeHostInfo.Type == systemconfig.GitLabProvider || codeHostInfo.Type == systemconfig.GerritProvider { if build.CommitID == "" { var commit *RepoCommit var pr *PRCommit @@ -348,7 +342,7 @@ func setBuildInfo(build *types.Repository, log *zap.SugaredLogger) { build.CommitMessage = commit.Message build.AuthorName = commit.AuthorName } - } else if codeHostInfo.Type == codehost.CodeHubProvider { + } else if codeHostInfo.Type == systemconfig.CodeHubProvider { codeHubClient := codehub.NewClient(codeHostInfo.AccessKey, codeHostInfo.SecretKey, codeHostInfo.Region) if build.CommitID == "" && build.Branch != "" { branchList, _ := codeHubClient.BranchList(build.RepoUUID) diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/workflow.go b/pkg/microservice/aslan/core/workflow/service/workflow/workflow.go index f2c8a35742ecb941dfdc0dcfafcfe42e6fc1b70b..98387c82986f6bcf690540e2884168b3dda9e5ce 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/workflow.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/workflow.go @@ -33,10 +33,8 @@ import ( commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/webhook" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/poetry" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/types" - "github.com/koderover/zadig/pkg/types/permission" ) var mut sync.Mutex @@ -64,6 +62,10 @@ func (args *workflowCreateArgs) addWorkflowArg(envName string, buildStageEnabled if artifactStageEnabled { wName = fmt.Sprintf("%s-%s-workflow", args.productName, "ops") } + // The hosting env workflow name is not bound to the environment + if !artifactStageEnabled && envName == "" { + wName = fmt.Sprintf("%s-workflow", args.productName) + } args.argsMap[wName] = &workflowCreateArg{ name: wName, envName: envName, @@ -116,10 +118,10 @@ func AutoCreateWorkflow(productName string, log *zap.SugaredLogger) *EnvStatus { createArgs.addWorkflowArg("", false, true) } - // 云主机场景不创建ops工作流 + // Only one workflow is created in the hosting environment if productTmpl.ProductFeature != nil && productTmpl.ProductFeature.CreateEnvType == setting.SourceFromExternal { createArgs.clear() - createArgs.addWorkflowArg("dev", true, false) + createArgs.addWorkflowArg("", true, false) } workflowSlice := sets.NewString() @@ -474,7 +476,7 @@ func validateWorkflowHookNames(w *commonmodels.Workflow) error { return validateHookNames(names) } -func ListWorkflows(queryType string, productName string, userID int, log *zap.SugaredLogger) ([]*commonmodels.Workflow, error) { +func ListWorkflows(queryType string, productName string, userID string, log *zap.SugaredLogger) ([]*commonmodels.Workflow, error) { workflows, err := commonrepo.NewWorkflowColl().List(&commonrepo.ListWorkflowOption{ProductName: productName}) if err != nil { log.Errorf("Workflow.List error: %v", err) @@ -540,51 +542,11 @@ func findWorkflowStat(workflow *commonmodels.Workflow, workflowStats []*commonmo return 0, 0, 0 } -func ListAllWorkflows(testName string, userID int, superUser bool, log *zap.SugaredLogger) ([]*commonmodels.Workflow, error) { - allWorkflows := make([]*commonmodels.Workflow, 0) - workflows := make([]*commonmodels.Workflow, 0) - var err error - if superUser { - allWorkflows, err = commonrepo.NewWorkflowColl().List(&commonrepo.ListWorkflowOption{}) - if err != nil { - log.Errorf("Workflow.List error: %v", err) - return allWorkflows, e.ErrListWorkflow.AddDesc(err.Error()) - } - } else { - poetryCtl := poetry.New(config.PoetryAPIServer(), config.PoetryAPIRootKey()) - productNameMap, err := poetryCtl.GetUserProject(userID, log) - if err != nil { - log.Errorf("ListAllWorkflows GetUserProject error: %v", err) - return nil, fmt.Errorf("ListAllWorkflows GetUserProject error: %v", err) - } - productNames := make([]string, 0) - for productName, roleIDs := range productNameMap { - roleID := roleIDs[0] - if roleID == setting.RoleOwnerID { - productNames = append(productNames, productName) - } else { - uuids, err := poetryCtl.GetUserPermissionUUIDs(roleID, productName, log) - if err != nil { - log.Errorf("ListAllWorkflows GetUserPermissionUUIDs error: %v", err) - return nil, fmt.Errorf("ListAllWorkflows GetUserPermissionUUIDs error: %v", err) - } - - ids := sets.NewString(uuids...) - if ids.Has(permission.WorkflowUpdateUUID) { - productNames = append(productNames, productName) - } - } - } - for _, productName := range productNames { - tempWorkflows, err := commonrepo.NewWorkflowColl().List(&commonrepo.ListWorkflowOption{ProductName: productName}) - if err != nil { - log.Errorf("ListAllWorkflows Workflow.List error: %v", err) - return nil, fmt.Errorf("ListAllWorkflows Workflow.List error: %v", err) - } - allWorkflows = append(allWorkflows, tempWorkflows...) - } +func ListTestWorkflows(testName string, projects []string, log *zap.SugaredLogger) (workflows []*commonmodels.Workflow, err error) { + allWorkflows, err := commonrepo.NewWorkflowColl().ListWorkflowsByProjects(projects) + if err != nil { + return nil, err } - for _, workflow := range allWorkflows { if workflow.TestStage != nil { testNames := sets.NewString(workflow.TestStage.TestNames...) diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go index 9e5d49cf05f4c537d565019b41aecd615c66aea2..368a4352902aa5e42102b2fe173e5639fb6b007a 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go @@ -41,11 +41,10 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/s3" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/scmnotify" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/poetry" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/log" "github.com/koderover/zadig/pkg/types" - "github.com/koderover/zadig/pkg/types/permission" "github.com/koderover/zadig/pkg/util" ) @@ -437,7 +436,7 @@ func PresetWorkflowArgs(namespace, workflowName string, log *zap.SugaredLogger) return resp, nil } -func CreateWorkflowTask(args *commonmodels.WorkflowTaskArgs, taskCreator string, userID int, superUser bool, log *zap.SugaredLogger) (*CreateTaskResp, error) { +func CreateWorkflowTask(args *commonmodels.WorkflowTaskArgs, taskCreator string, log *zap.SugaredLogger) (*CreateTaskResp, error) { if args == nil { return nil, fmt.Errorf("args should not be nil") } @@ -465,11 +464,6 @@ func CreateWorkflowTask(args *commonmodels.WorkflowTaskArgs, taskCreator string, } args.IsParallel = workflow.IsParallel - if !HasPermission(workflow.ProductTmplName, workflow.EnvName, args, userID, superUser, log) { - log.Warnf("该工作流[%s]绑定的环境您没有权限,用户[%s]不能执行该工作流!", workflow.Name, taskCreator) - return nil, e.ErrCreateTask.AddDesc("该工作流绑定的环境您没有更新环境或者环境管理权限,不能执行该工作流!") - } - var env *commonmodels.Product if args.Namespace != "" { // 处理namespace,避免开头或者结尾出现多余的逗号 @@ -608,7 +602,7 @@ func CreateWorkflowTask(args *commonmodels.WorkflowTaskArgs, taskCreator string, subTasks = append(subTasks, distributeTasks...) } - jiraInfo, _ := poetry.GetJiraInfo(config.PoetryAPIServer(), config.PoetryAPIRootKey()) + jiraInfo, _ := systemconfig.New().GetJiraInfo() if jiraInfo != nil { jiraTask, err := AddJiraSubTask("", target.Name, target.ServiceName, args.ProductTmplName, log) if err != nil { @@ -886,86 +880,6 @@ func AddDataToArgs(args *commonmodels.WorkflowTaskArgs, log *zap.SugaredLogger) return nil } -func HasPermission(productName, envName string, args *commonmodels.WorkflowTaskArgs, userID int, superUser bool, log *zap.SugaredLogger) bool { - //排除触发器触发和工作流没有绑定环境的情况 - if userID == permission.AnonymousUserID || envName == "" { - return true - } - // 只有测试任务的情况 - if len(args.Target) == 0 && len(args.Tests) > 0 { - return true - } - //权限判断 - if superUser { - return true - } - poetryClient := poetry.New(config.PoetryAPIServer(), config.PoetryAPIRootKey()) - productNameMap, err := poetryClient.GetUserProject(userID, log) - if err != nil { - log.Errorf("Collection.Product.List GetUserProject error: %v", err) - return false - } - //判断环境是类生产环境还是测试环境 - isProd := false - opt := &commonrepo.ProductFindOptions{Name: productName, EnvName: envName} - prod, _ := commonrepo.NewProductColl().Find(opt) - if prod != nil && prod.ClusterID != "" { - if cluster, _ := commonrepo.NewK8SClusterColl().Get(prod.ClusterID); cluster != nil { - isProd = cluster.Production - } - } - for _, roleID := range productNameMap[productName] { - if roleID == poetry.ProjectOwner { - return true - } - if envRolePermissions, _ := poetryClient.ListEnvRolePermission(productName, envName, roleID, log); len(envRolePermissions) > 0 { - for _, envRolePermission := range envRolePermissions { - if envRolePermission.PermissionUUID == permission.TestEnvManageUUID { - return true - } - } - } else { - if !isProd { - if poetryClient.HasOperatePermission(productName, permission.TestUpdateEnvUUID, userID, superUser, log) { - return true - } - if poetryClient.HasOperatePermission(productName, permission.TestEnvManageUUID, userID, superUser, log) { - return true - } - - envRolePermissions, _ := poetryClient.ListEnvRolePermission(productName, envName, 0, log) - for _, envRolePermission := range envRolePermissions { - if envRolePermission.PermissionUUID == permission.TestEnvManageUUID { - return true - } - } - } else { - if poetryClient.HasOperatePermission(productName, permission.ProdEnvManageUUID, userID, superUser, log) { - return true - } - - envRolePermissions, _ := poetryClient.ListEnvRolePermission(productName, envName, 0, log) - for _, envRolePermission := range envRolePermissions { - if envRolePermission.PermissionUUID == permission.ProdEnvManageUUID { - return true - } - } - } - } - } - // 如果该项目设置过all-users,判断all-users的权限 - productRole, _ := poetryClient.ListRoles(productName, log) - if productRole != nil { - permissionUUIDs, _ := poetryClient.GetUserPermissionUUIDs(productRole.ID, productName, log) - if isProd && sets.NewString(permissionUUIDs...).Has(permission.ProdEnvManageUUID) { - return true - } else if !isProd && sets.NewString(permissionUUIDs...).Has(permission.TestEnvManageUUID) { - return true - } - } - return false -} - func dealWithNamespace(args *commonmodels.WorkflowTaskArgs) { args.Namespace = strings.TrimPrefix(args.Namespace, ",") args.Namespace = strings.TrimSuffix(args.Namespace, ",") @@ -1330,7 +1244,7 @@ func testArgsToSubtask(args *commonmodels.WorkflowTaskArgs, pt *task.Task, log * return resp, nil } -func CreateArtifactWorkflowTask(args *commonmodels.WorkflowTaskArgs, taskCreator string, userID int, superUser bool, log *zap.SugaredLogger) (*CreateTaskResp, error) { +func CreateArtifactWorkflowTask(args *commonmodels.WorkflowTaskArgs, taskCreator string, log *zap.SugaredLogger) (*CreateTaskResp, error) { if args == nil { return nil, fmt.Errorf("args should not be nil") } @@ -1346,11 +1260,6 @@ func CreateArtifactWorkflowTask(args *commonmodels.WorkflowTaskArgs, taskCreator return nil, e.ErrFindWorkflow.AddDesc(err.Error()) } - if !HasPermission(workflow.ProductTmplName, workflow.EnvName, args, userID, superUser, log) { - log.Warnf("该工作流[%s]绑定的环境您没有权限,用户[%s]不能执行该工作流!", workflow.Name, taskCreator) - return nil, e.ErrCreateTask.AddDesc("该工作流绑定的环境您没有更新环境或者环境管理权限,不能执行该工作流") - } - var env *commonmodels.Product if args.Namespace != "" { // 查找要部署的环境 diff --git a/pkg/microservice/aslan/core/workflow/testing/handler/policy.yaml b/pkg/microservice/aslan/core/workflow/testing/handler/policy.yaml new file mode 100644 index 0000000000000000000000000000000000000000..56b2c62adce5d487f208cce12d1df38acb33b9d2 --- /dev/null +++ b/pkg/microservice/aslan/core/workflow/testing/handler/policy.yaml @@ -0,0 +1,42 @@ +resource: Test +alias: "质量管理" +description: "" +rules: + - action: get_test + alias: "查看测试" + description: "" + rules: + - method: GET + endpoint: "/api/aslan/testing/test" + - method: GET + endpoint: "/api/aslan/testing/test/?*" + - method: GET + endpoint: "/api/aslan/testing/testdetail" + - method: GET + endpoint: "/api/aslan/workflow/workflow/testName/?*" + - method: GET + endpoint: "/api/aslan/workflow/v2/tasks/workflow/workflow/?*/taskId/?*" + - action: edit_test + alias: "编辑测试" + description: "" + rules: + - method: PUT + endpoint: "/api/aslan/testing/test" + - action: delete_test + alias: "删除测试" + description: "" + rules: + - method: DELETE + endpoint: "/api/aslan/testing/test/?*" + - action: create_test + alias: "新建测试" + description: "" + rules: + - method: POST + endpoint: "/api/aslan/testing/test" + - action: run_test + alias: "执行测试" + description: "" + rules: + - method: POST + endpoint: "/api/aslan/testing/testtask" diff --git a/pkg/microservice/aslan/core/workflow/testing/handler/policy_definitions.go b/pkg/microservice/aslan/core/workflow/testing/handler/policy_definitions.go new file mode 100644 index 0000000000000000000000000000000000000000..a434ba1ddc8fb0fcf719d776fc0e1211fe8a5240 --- /dev/null +++ b/pkg/microservice/aslan/core/workflow/testing/handler/policy_definitions.go @@ -0,0 +1,24 @@ +package handler + +import ( + _ "embed" + + "sigs.k8s.io/yaml" + + "github.com/koderover/zadig/pkg/shared/client/policy" + "github.com/koderover/zadig/pkg/tool/log" +) + +//go:embed policy.yaml +var policyDefinitions []byte + +func (*Router) Policies() *policy.Policy { + res := &policy.Policy{} + err := yaml.Unmarshal(policyDefinitions, res) + if err != nil { + // should not have happened here + log.DPanic(err) + } + + return res +} diff --git a/pkg/microservice/aslan/core/workflow/testing/handler/router.go b/pkg/microservice/aslan/core/workflow/testing/handler/router.go index e0701d22cd020586fa6cf90fe5f58babbf3f9d8f..ccc942936dcab8346e72e90b01c939fadab6bb06 100644 --- a/pkg/microservice/aslan/core/workflow/testing/handler/router.go +++ b/pkg/microservice/aslan/core/workflow/testing/handler/router.go @@ -20,7 +20,6 @@ import ( "github.com/gin-gonic/gin" gin2 "github.com/koderover/zadig/pkg/middleware/gin" - "github.com/koderover/zadig/pkg/types/permission" ) type Router struct{} @@ -32,8 +31,6 @@ func (*Router) Inject(router *gin.RouterGroup) { testReport.GET("", GetHTMLTestReport) } - router.Use(gin2.Auth()) - // --------------------------------------------------------------------------------------- // 系统测试接口 // --------------------------------------------------------------------------------------- @@ -49,11 +46,11 @@ func (*Router) Inject(router *gin.RouterGroup) { // --------------------------------------------------------------------------------------- tester := router.Group("test") { - tester.POST("", GetTestProductName, gin2.IsHavePermission([]string{permission.TestManageUUID}, permission.ContextKeyType), gin2.UpdateOperationLogStatus, CreateTestModule) - tester.PUT("", GetTestProductName, gin2.IsHavePermission([]string{permission.TestManageUUID}, permission.ContextKeyType), gin2.UpdateOperationLogStatus, UpdateTestModule) + tester.POST("", GetTestProductName, gin2.UpdateOperationLogStatus, CreateTestModule) + tester.PUT("", GetTestProductName, gin2.UpdateOperationLogStatus, UpdateTestModule) tester.GET("", ListTestModules) tester.GET("/:name", GetTestModule) - tester.DELETE("/:name", gin2.IsHavePermission([]string{permission.TestDeleteUUID}, permission.QueryType), gin2.UpdateOperationLogStatus, DeleteTestModule) + tester.DELETE("/:name", gin2.UpdateOperationLogStatus, DeleteTestModule) } testStat := router.Group("teststat") diff --git a/pkg/microservice/aslan/core/workflow/testing/handler/test_detail.go b/pkg/microservice/aslan/core/workflow/testing/handler/test_detail.go index 02295c3e80f3a4325961e0c5d696fff4fe99d7eb..492db2a97cff71a4f51ec4163ba0f6f8a37fa60f 100644 --- a/pkg/microservice/aslan/core/workflow/testing/handler/test_detail.go +++ b/pkg/microservice/aslan/core/workflow/testing/handler/test_detail.go @@ -27,5 +27,5 @@ func ListDetailTestModules(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - ctx.Resp, ctx.Err = service.ListTestingDetails(c.Query("productName"), ctx.Logger) + ctx.Resp, ctx.Err = service.ListTestingDetails(c.Query("projectName"), ctx.Logger) } diff --git a/pkg/microservice/aslan/core/workflow/testing/handler/test_task.go b/pkg/microservice/aslan/core/workflow/testing/handler/test_task.go index 80ebf4911102eb5698b306f3889f6dd2e62b938f..099cebcf98c80fd923a3407c2b500bb6359cfc2a 100644 --- a/pkg/microservice/aslan/core/workflow/testing/handler/test_task.go +++ b/pkg/microservice/aslan/core/workflow/testing/handler/test_task.go @@ -49,7 +49,7 @@ func CreateTestTask(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("CreateTestTask json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, args.ProductName, "新增", "测试-task", fmt.Sprintf("%s-%s", args.TestName, "job"), string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, args.ProductName, "新增", "测试-task", fmt.Sprintf("%s-%s", args.TestName, "job"), string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) if err := c.ShouldBindWith(&args, binding.JSON); err != nil { @@ -58,13 +58,13 @@ func CreateTestTask(c *gin.Context) { } if args.TestTaskCreator != setting.CronTaskCreator && args.TestTaskCreator != setting.WebhookTaskCreator { - args.TestTaskCreator = ctx.Username + args.TestTaskCreator = ctx.UserName } ctx.Resp, ctx.Err = service.CreateTestTask(args, ctx.Logger) // 发送通知 if ctx.Err != nil { - commonservice.SendFailedTaskMessage(ctx.Username, args.ProductName, args.TestName, ctx.RequestID, config.TestType, ctx.Err, ctx.Logger) + commonservice.SendFailedTaskMessage(ctx.UserName, args.ProductName, args.TestName, ctx.RequestID, config.TestType, ctx.Err, ctx.Logger) } } @@ -72,7 +72,7 @@ func RestartTestTask(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - internalhandler.InsertOperationLog(c, ctx.Username, c.Param("productName"), "重启", "测试任务", c.Param("name"), "", ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, c.Param("productName"), "重启", "测试任务", c.Param("name"), "", ctx.Logger) taskID, err := strconv.ParseInt(c.Param("id"), 10, 64) if err != nil { @@ -80,18 +80,18 @@ func RestartTestTask(c *gin.Context) { return } - ctx.Err = workflowservice.RestartPipelineTaskV2(ctx.Username, taskID, c.Param("name"), config.TestType, ctx.Logger) + ctx.Err = workflowservice.RestartPipelineTaskV2(ctx.UserName, taskID, c.Param("name"), config.TestType, ctx.Logger) } func CancelTestTaskV2(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - internalhandler.InsertOperationLog(c, ctx.Username, c.Param("productName"), "取消", "测试任务", c.Param("name"), "", ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, c.Param("productName"), "取消", "测试任务", c.Param("name"), "", ctx.Logger) taskID, err := strconv.ParseInt(c.Param("id"), 10, 64) if err != nil { ctx.Err = e.ErrInvalidParam.AddDesc("invalid task id") return } - ctx.Err = commonservice.CancelTaskV2(ctx.Username, c.Param("name"), taskID, config.TestType, ctx.RequestID, ctx.Logger) + ctx.Err = commonservice.CancelTaskV2(ctx.UserName, c.Param("name"), taskID, config.TestType, ctx.RequestID, ctx.Logger) } diff --git a/pkg/microservice/aslan/core/workflow/testing/handler/testing.go b/pkg/microservice/aslan/core/workflow/testing/handler/testing.go index 24c35774d495fbe51269fae99b975e3a29724f10..33837f805bbeebe06eaea535d96726b5656c9d01 100644 --- a/pkg/microservice/aslan/core/workflow/testing/handler/testing.go +++ b/pkg/microservice/aslan/core/workflow/testing/handler/testing.go @@ -59,7 +59,7 @@ func CreateTestModule(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("CreateTestModule json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, args.ProductName, "新增", "项目管理-测试", args.Name, string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, args.ProductName, "新增", "项目管理-测试", args.Name, string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) err = c.BindJSON(args) @@ -68,7 +68,7 @@ func CreateTestModule(c *gin.Context) { return } - ctx.Err = service.CreateTesting(ctx.Username, args, ctx.Logger) + ctx.Err = service.CreateTesting(ctx.UserName, args, ctx.Logger) } func UpdateTestModule(c *gin.Context) { @@ -83,7 +83,7 @@ func UpdateTestModule(c *gin.Context) { if err = json.Unmarshal(data, args); err != nil { log.Errorf("UpdateTestModule json.Unmarshal err : %v", err) } - internalhandler.InsertOperationLog(c, ctx.Username, args.ProductName, "更新", "项目管理-测试", args.Name, string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, args.ProductName, "更新", "项目管理-测试", args.Name, string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) err = c.BindJSON(args) @@ -92,14 +92,14 @@ func UpdateTestModule(c *gin.Context) { return } - ctx.Err = service.UpdateTesting(ctx.Username, args, ctx.Logger) + ctx.Err = service.UpdateTesting(ctx.UserName, args, ctx.Logger) } func ListTestModules(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - ctx.Resp, ctx.Err = service.ListTestingOpt(c.Query("productName"), c.Query("testType"), ctx.Logger) + ctx.Resp, ctx.Err = service.ListTestingOpt(c.Query("projectName"), c.Query("testType"), ctx.Logger) } func GetTestModule(c *gin.Context) { @@ -112,14 +112,14 @@ func GetTestModule(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("empty Name") return } - ctx.Resp, ctx.Err = service.GetTesting(name, c.Query("productName"), ctx.Logger) + ctx.Resp, ctx.Err = service.GetTesting(name, c.Query("projectName"), ctx.Logger) } func DeleteTestModule(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - internalhandler.InsertOperationLog(c, ctx.Username, c.Query("productName"), "删除", "项目管理-测试", c.Param("name"), "", ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, c.Query("projectName"), "删除", "项目管理-测试", c.Param("name"), "", ctx.Logger) name := c.Param("name") if name == "" { @@ -127,7 +127,7 @@ func DeleteTestModule(c *gin.Context) { return } - ctx.Err = service.DeleteTestModule(name, c.Query("productName"), ctx.RequestID, ctx.Logger) + ctx.Err = service.DeleteTestModule(name, c.Query("projectName"), ctx.RequestID, ctx.Logger) } func GetHTMLTestReport(c *gin.Context) { diff --git a/pkg/microservice/aslan/server/rest/router.go b/pkg/microservice/aslan/server/rest/router.go index 1339a6f96a8e3f375bfebe57569a2d04fab7e49f..960dd7909b62ef66e21251e6b38755225d7f4066 100644 --- a/pkg/microservice/aslan/server/rest/router.go +++ b/pkg/microservice/aslan/server/rest/router.go @@ -17,8 +17,6 @@ limitations under the License. package rest import ( - "github.com/gin-contrib/sessions" - "github.com/gin-contrib/sessions/cookie" "github.com/gin-gonic/gin" swaggerfiles "github.com/swaggo/files" ginswagger "github.com/swaggo/gin-swagger" @@ -38,7 +36,6 @@ import ( templatehandler "github.com/koderover/zadig/pkg/microservice/aslan/core/templatestore/handler" workflowhandler "github.com/koderover/zadig/pkg/microservice/aslan/core/workflow/handler" testinghandler "github.com/koderover/zadig/pkg/microservice/aslan/core/workflow/testing/handler" - gin2 "github.com/koderover/zadig/pkg/middleware/gin" // Note: have to load docs for swagger to work. See https://blog.csdn.net/weixin_43249914/article/details/103035711 _ "github.com/koderover/zadig/pkg/microservice/aslan/server/rest/doc" @@ -54,14 +51,6 @@ import ( // @license.url http://www.apache.org/licenses/LICENSE-2.0.html // @BasePath /api/aslan func (s *engine) injectRouterGroup(router *gin.RouterGroup) { - store := cookie.NewStore([]byte("C12f4d5957k345e9g6e86c117e1bfu5kndjevf8u")) - cookieOption := sessions.Options{ - Path: "/", - HttpOnly: true, - } - store.Options(cookieOption) - router.Use(sessions.Sessions("ASLAN", store)) - Auth := gin2.Auth() // --------------------------------------------------------------------------------------- // 对外公共接口 // --------------------------------------------------------------------------------------- @@ -74,15 +63,11 @@ func (s *engine) injectRouterGroup(router *gin.RouterGroup) { public.GET("/health", commonhandler.Health) } - // no auth required, should not be exposed via poetry-api-proxy or will fail + // no auth required router.GET("/api/hub/connect", multiclusterhandler.ClusterConnectFromAgent) - router.GET("/api/kodespace/downloadUrl", Auth, commonhandler.GetToolDownloadURL) + router.GET("/api/kodespace/downloadUrl", commonhandler.GetToolDownloadURL) - jwt := router.Group("/api/token", Auth) - { - jwt.GET("", commonhandler.GetToken) - } for name, r := range map[string]injector{ "/api/project": new(projecthandler.Router), "/api/code": new(codehosthandler.Router), diff --git a/pkg/microservice/cron/config/config.go b/pkg/microservice/cron/config/config.go index b044a63338fab341e9fe8ef80cb4c86576e80189..95f8c0805a070298ba0a14312a5c440aa0e5118d 100644 --- a/pkg/microservice/cron/config/config.go +++ b/pkg/microservice/cron/config/config.go @@ -25,18 +25,10 @@ import ( "github.com/koderover/zadig/pkg/setting" ) -func RootToken() string { - return viper.GetString(setting.ENVRootToken) -} - func CollieAPI() string { return configbase.CollieServiceAddress() } -func CollieToken() string { - return RootToken() -} - func NsqLookupAddrs() []string { return strings.Split(viper.GetString(setting.ENVNsqLookupAddrs), ",") } diff --git a/pkg/microservice/cron/core/service/client/caller.go b/pkg/microservice/cron/core/service/client/caller.go index dca82f3794b8e40a66cf76e7974ea1371164c161..2f144cd1418faa61f9beef355aeeb3b128a75f26 100644 --- a/pkg/microservice/cron/core/service/client/caller.go +++ b/pkg/microservice/cron/core/service/client/caller.go @@ -24,8 +24,6 @@ import ( "net/http" "go.uber.org/zap" - - "github.com/koderover/zadig/pkg/setting" ) func (c *Client) ScheduleCall(api string, args interface{}, log *zap.SugaredLogger) error { @@ -41,7 +39,7 @@ func (c *Client) ScheduleCall(api string, args interface{}, log *zap.SugaredLogg log.Errorf("create post request error : %v", err) return err } - request.Header.Set("Authorization", fmt.Sprintf("%s %s", setting.TIMERAPIKEY, c.Token)) + var resp *http.Response resp, err = c.Conn.Do(request) if err == nil { diff --git a/pkg/microservice/cron/core/service/client/client.go b/pkg/microservice/cron/core/service/client/client.go index 7d41290cf7eadc311df6233a4caaa42027bfcad5..ab416baaffa0233dc1b803c6dcbdc1e92f0d0abf 100644 --- a/pkg/microservice/cron/core/service/client/client.go +++ b/pkg/microservice/cron/core/service/client/client.go @@ -23,17 +23,15 @@ import ( type Client struct { APIBase string - Token string Conn *http.Client } // NewAslanClient is to get aslan client func -func NewAslanClient(host, token string) *Client { +func NewAslanClient(host string) *Client { jar, _ := cookiejar.New(nil) c := &Client{ APIBase: host, - Token: token, Conn: &http.Client{Transport: http.DefaultTransport, Jar: jar}, } diff --git a/pkg/microservice/cron/core/service/client/collie_client.go b/pkg/microservice/cron/core/service/client/collie_client.go index 413a8151dbb083c59ae8997e6d8feeef00ae4950..dbf6a1182898e735e7c6f2a13a58573d827b4732 100644 --- a/pkg/microservice/cron/core/service/client/collie_client.go +++ b/pkg/microservice/cron/core/service/client/collie_client.go @@ -17,27 +17,22 @@ limitations under the License. package client import ( - "github.com/koderover/zadig/pkg/setting" "github.com/koderover/zadig/pkg/tool/httpclient" ) type CollieClient struct { *httpclient.Client - host string - token string + host string } -func NewCollieClient(host, token string) *CollieClient { +func NewCollieClient(host string) *CollieClient { c := httpclient.New( - httpclient.SetAuthScheme(setting.RootAPIKey), - httpclient.SetAuthToken(token), httpclient.SetHostURL(host), ) return &CollieClient{ Client: c, host: host, - token: token, } } diff --git a/pkg/microservice/cron/core/service/client/cronjob.go b/pkg/microservice/cron/core/service/client/cronjob.go index 2509b2f500708fb122d7fbfed84e051a3c9fe08b..c1c727cf0aaab403d90bf96f7fccd39adf0892f5 100644 --- a/pkg/microservice/cron/core/service/client/cronjob.go +++ b/pkg/microservice/cron/core/service/client/cronjob.go @@ -29,7 +29,6 @@ import ( "go.uber.org/zap" "github.com/koderover/zadig/pkg/microservice/cron/core/service" - "github.com/koderover/zadig/pkg/setting" "github.com/koderover/zadig/pkg/tool/rsa" ) @@ -169,7 +168,7 @@ func (c *Client) sendRequest(url string) error { if err != nil { return err } - request.Header.Set("Authorization", fmt.Sprintf("%s %s", setting.TIMERAPIKEY, c.Token)) + resp, err := c.Conn.Do(request) if err == nil { defer func() { _ = resp.Body.Close() }() @@ -183,7 +182,6 @@ func (c *Client) sendPostRequest(url string, body io.Reader, log *zap.SugaredLog log.Errorf("create post request error : %v", err) return "", err } - request.Header.Set("Authorization", fmt.Sprintf("%s %s", setting.TIMERAPIKEY, c.Token)) var resp *http.Response resp, err = c.Conn.Do(request) if err != nil { diff --git a/pkg/microservice/cron/core/service/client/env.go b/pkg/microservice/cron/core/service/client/env.go index 468b0190c334d44ea06466891c7ab5c58314bd1a..b50274e0ebb2cc0a4303c8cba7e42c932af9f036 100644 --- a/pkg/microservice/cron/core/service/client/env.go +++ b/pkg/microservice/cron/core/service/client/env.go @@ -27,7 +27,6 @@ import ( "go.uber.org/zap" "github.com/koderover/zadig/pkg/microservice/cron/core/service" - "github.com/koderover/zadig/pkg/setting" ) func (c *Client) ListEnvs(log *zap.SugaredLogger) ([]*service.ProductRevision, error) { @@ -44,7 +43,6 @@ func (c *Client) ListEnvs(log *zap.SugaredLogger) ([]*service.ProductRevision, e return nil, err } - request.Header.Set("Authorization", fmt.Sprintf("%s %s", setting.RootAPIKey, c.Token)) var ret *http.Response if ret, err = c.Conn.Do(request); err == nil { defer func() { _ = ret.Body.Close() }() @@ -71,7 +69,6 @@ func (c *Client) GetEnvService(productName, envName string, log *zap.SugaredLogg return nil, err } - request.Header.Set("Authorization", fmt.Sprintf("%s %s", setting.RootAPIKey, c.Token)) var ret *http.Response if ret, err = c.Conn.Do(request); err == nil { defer func() { _ = ret.Body.Close() }() @@ -99,7 +96,6 @@ func (c *Client) GetService(serviceName, productName, serviceType string, revisi return nil, err } - request.Header.Set("Authorization", fmt.Sprintf("%s %s", setting.RootAPIKey, c.Token)) var ret *http.Response if ret, err = c.Conn.Do(request); err == nil { defer func() { _ = ret.Body.Close() }() @@ -129,7 +125,6 @@ func (c *Client) UpdateService(args *service.ServiceTmplObject, log *zap.Sugared return err } - request.Header.Set("Authorization", fmt.Sprintf("%s %s", setting.RootAPIKey, c.Token)) var ret *http.Response if ret, err = c.Conn.Do(request); err == nil { defer func() { _ = ret.Body.Close() }() @@ -154,7 +149,6 @@ func (c *Client) GetHostInfo(hostID string, log *zap.SugaredLogger) (*service.Pr return nil, err } - request.Header.Set("Authorization", fmt.Sprintf("%s %s", setting.RootAPIKey, c.Token)) var ret *http.Response if ret, err = c.Conn.Do(request); err == nil { defer func() { _ = ret.Body.Close() }() diff --git a/pkg/microservice/cron/core/service/client/operation.go b/pkg/microservice/cron/core/service/client/operation.go index d7f1b4840203c64ff39239c2ad371aed3880d82a..94f2db1bdb7940502bae5f8e66552e7cbc212030 100644 --- a/pkg/microservice/cron/core/service/client/operation.go +++ b/pkg/microservice/cron/core/service/client/operation.go @@ -26,7 +26,6 @@ import ( "go.uber.org/zap" "github.com/koderover/zadig/pkg/microservice/cron/core/service" - "github.com/koderover/zadig/pkg/setting" ) func (c *Client) GetWebHookUser(log *zap.SugaredLogger) (*service.DomainWebHookUser, error) { @@ -42,7 +41,6 @@ func (c *Client) GetWebHookUser(log *zap.SugaredLogger) (*service.DomainWebHookU return domainWebHookUser, err } - request.Header.Set("Authorization", fmt.Sprintf("%s %s", setting.RootAPIKey, c.Token)) var ret *http.Response if ret, err = c.Conn.Do(request); err == nil { defer func() { _ = ret.Body.Close() }() diff --git a/pkg/microservice/cron/core/service/client/pipeline.go b/pkg/microservice/cron/core/service/client/pipeline.go index dacbe0bab9a16e13f567e3d7655a093c9ef5b734..0d1aba96ac95fe7ab39368edeab095fca71ff029 100644 --- a/pkg/microservice/cron/core/service/client/pipeline.go +++ b/pkg/microservice/cron/core/service/client/pipeline.go @@ -26,7 +26,6 @@ import ( "go.uber.org/zap" "github.com/koderover/zadig/pkg/microservice/cron/core/service" - "github.com/koderover/zadig/pkg/setting" ) func (c *Client) ListPipelines(log *zap.SugaredLogger) ([]*service.Pipeline, error) { @@ -40,7 +39,6 @@ func (c *Client) ListPipelines(log *zap.SugaredLogger) ([]*service.Pipeline, err return nil, err } - request.Header.Set("Authorization", fmt.Sprintf("%s %s", setting.RootAPIKey, c.Token)) var ret *http.Response if ret, err = c.Conn.Do(request); err == nil { defer func() { _ = ret.Body.Close() }() diff --git a/pkg/microservice/cron/core/service/client/sonar.go b/pkg/microservice/cron/core/service/client/sonar.go index d97e988430c1973e949b66b43379b15f87a96de0..4b50f102f0dd51bab762f34ce26b724a4ff63a79 100644 --- a/pkg/microservice/cron/core/service/client/sonar.go +++ b/pkg/microservice/cron/core/service/client/sonar.go @@ -24,7 +24,6 @@ import ( "go.uber.org/zap" configbase "github.com/koderover/zadig/pkg/config" - "github.com/koderover/zadig/pkg/setting" ) func (c *Client) InitPullSonarStatScheduler(log *zap.SugaredLogger) error { @@ -45,7 +44,6 @@ func (c *Client) InitPullSonarTestsMeasure(log *zap.SugaredLogger) error { log.Errorf("create post request error : %v", err) return err } - request.Header.Set("Authorization", fmt.Sprintf("%s %s", setting.RootAPIKey, c.Token)) var resp *http.Response resp, err = c.Conn.Do(request) @@ -76,7 +74,6 @@ func (c *Client) InitPullSonarDeliveryMeasure(log *zap.SugaredLogger) error { log.Errorf("create post request error : %v", err) return err } - request.Header.Set("Authorization", fmt.Sprintf("%s %s", setting.RootAPIKey, c.Token)) var resp *http.Response resp, err = c.Conn.Do(request) @@ -107,7 +104,6 @@ func (c *Client) InitPullSonarRepos(log *zap.SugaredLogger) error { log.Errorf("create post request error : %v", err) return err } - request.Header.Set("Authorization", fmt.Sprintf("%s %s", setting.RootAPIKey, c.Token)) var resp *http.Response resp, err = c.Conn.Do(request) diff --git a/pkg/microservice/cron/core/service/client/testing.go b/pkg/microservice/cron/core/service/client/testing.go index bb7e50d9e114541ce96f22cb3da907f57b508169..4154a01086d9f1bc95c39df69e80ca01c86dfb2f 100644 --- a/pkg/microservice/cron/core/service/client/testing.go +++ b/pkg/microservice/cron/core/service/client/testing.go @@ -26,7 +26,6 @@ import ( "go.uber.org/zap" "github.com/koderover/zadig/pkg/microservice/cron/core/service" - "github.com/koderover/zadig/pkg/setting" ) func (c *Client) ListTests(log *zap.SugaredLogger) ([]*service.TestingOpt, error) { @@ -39,7 +38,6 @@ func (c *Client) ListTests(log *zap.SugaredLogger) ([]*service.TestingOpt, error return nil, err } - request.Header.Set("Authorization", fmt.Sprintf("%s %s", setting.RootAPIKey, c.Token)) var ret *http.Response ret, err = c.Conn.Do(request) diff --git a/pkg/microservice/cron/core/service/client/workflow.go b/pkg/microservice/cron/core/service/client/workflow.go index 894a0687a05fab85c565a719a6a5be0074b5e9ba..6884d9f5b341b2e0d25344f7434e7acc596247a3 100644 --- a/pkg/microservice/cron/core/service/client/workflow.go +++ b/pkg/microservice/cron/core/service/client/workflow.go @@ -26,7 +26,6 @@ import ( "go.uber.org/zap" "github.com/koderover/zadig/pkg/microservice/cron/core/service" - "github.com/koderover/zadig/pkg/setting" ) // ListWorkflows ... @@ -71,6 +70,5 @@ func (c *Client) genListWorkFlowReq(log *zap.SugaredLogger) (*http.Request, erro return nil, err } - request.Header.Set(setting.AuthorizationHeader, fmt.Sprintf("%s %s", setting.RootAPIKey, c.Token)) return request, nil } diff --git a/pkg/microservice/cron/core/service/scheduler/cronjob_handler.go b/pkg/microservice/cron/core/service/scheduler/cronjob_handler.go index a3a678fc8e6c277c2c80036d2281b703ff0774ec..2844897455165c4273a6e00b03bf684fd4f744e8 100644 --- a/pkg/microservice/cron/core/service/scheduler/cronjob_handler.go +++ b/pkg/microservice/cron/core/service/scheduler/cronjob_handler.go @@ -69,14 +69,10 @@ func InitExistedCronjob(client *client.Client, scheduler *cronlib.CronSchduler) failsafeJobList []*service.Cronjob ) listAPI := fmt.Sprintf("%s/cron/cronjob", client.APIBase) - header := http.Header{} - header.Set("Authorization", fmt.Sprintf("%s %s", setting.TIMERAPIKEY, client.Token)) // failsafe function: get enabled workflow and register them failsafeAPI := fmt.Sprintf("%s/cron/cronjob/failsafe", client.APIBase) cl := httpclient.New( - httpclient.SetAuthScheme(setting.TIMERAPIKEY), - httpclient.SetAuthToken(client.Token), httpclient.SetRetryCount(100), httpclient.SetRetryWaitTime(PullInterval), ) @@ -304,7 +300,6 @@ func (h *CronjobHandler) stopCronjob(name, ptype string) error { var jobList []*service.Cronjob listAPI := fmt.Sprintf("%s/cron/cronjob/type/%s/name/%s", h.aslanCli.APIBase, ptype, name) header := http.Header{} - header.Set("Authorization", fmt.Sprintf("%s %s", setting.TIMERAPIKEY, h.aslanCli.Token)) resp, err := util.SendRequest(listAPI, "GET", header, nil) if err != nil { log.Errorf("Failed to get job list, the error is: %v, reconsuming", err) diff --git a/pkg/microservice/cron/core/service/scheduler/scheduler.go b/pkg/microservice/cron/core/service/scheduler/scheduler.go index 5ab7e04642e3b363c6bc316608179b439607348f..5bcb91f3e939f9267c27a3d6d610dee6f68eb222 100644 --- a/pkg/microservice/cron/core/service/scheduler/scheduler.go +++ b/pkg/microservice/cron/core/service/scheduler/scheduler.go @@ -20,7 +20,6 @@ import ( "fmt" stdlog "log" "os" - "strings" "time" "github.com/jasonlvhit/gocron" @@ -33,7 +32,7 @@ import ( "github.com/koderover/zadig/pkg/microservice/cron/core/service" "github.com/koderover/zadig/pkg/microservice/cron/core/service/client" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/poetry" + configclient "github.com/koderover/zadig/pkg/shared/config" "github.com/koderover/zadig/pkg/tool/log" ) @@ -74,8 +73,6 @@ const ( //InitHealthCheckScheduler InitHealthCheckScheduler = "InitHealthCheckScheduler" - // FreestyleType 自由编排工作流 - freestyleType = "freestyle" ) // NewCronClient ... @@ -83,8 +80,8 @@ const ( func NewCronClient() *CronClient { nsqLookupAddrs := config.NsqLookupAddrs() - aslanCli := client.NewAslanClient(fmt.Sprintf("%s/api", configbase.AslanServiceAddress()), config.RootToken()) - collieCli := client.NewCollieClient(config.CollieAPI(), config.CollieToken()) + aslanCli := client.NewAslanClient(fmt.Sprintf("%s/api", configbase.AslanServiceAddress())) + collieCli := client.NewCollieClient(config.CollieAPI()) //初始化nsq config := nsq.NewConfig() // 注意 WD_POD_NAME 必须使用 Downward API 配置环境变量 @@ -142,8 +139,8 @@ func (c *CronClient) Init() { c.InitTestScheduler() // 自由编排工作流定时任务触发 - features, _ := getFeatures() - if strings.Contains(features, freestyleType) { + cl := configclient.New(configbase.ConfigServiceAddress()) + if enable, err := cl.CheckFeature(setting.ModernWorkflowType);err ==nil && enable{ c.InitColliePipelineScheduler() } @@ -159,15 +156,6 @@ func (c *CronClient) Init() { c.InitHealthCheckScheduler() } -func getFeatures() (string, error) { - cl := poetry.New(configbase.PoetryServiceAddress(), config.RootToken()) - fs, err := cl.ListFeatures() - if err != nil { - return "", err - } - - return strings.Join(fs, ","), nil -} // InitCleanJobScheduler ... func (c *CronClient) InitCleanJobScheduler() { diff --git a/pkg/microservice/cron/core/service/types.go b/pkg/microservice/cron/core/service/types.go index 96c0c907f088bec1fe0ba4bfe1d7d9488c743574..f1c5c917c6f9aaea420a5f0e440a10365dc02d68 100644 --- a/pkg/microservice/cron/core/service/types.go +++ b/pkg/microservice/cron/core/service/types.go @@ -440,8 +440,6 @@ type Pipeline struct { Enabled bool `bson:"enabled" json:"enabled"` TeamName string `bson:"team" json:"team"` ProductName string `bson:"product_name" json:"product_name"` - // OrgID 单租户ID - OrgID int `bson:"org_id" json:"org_id"` // target 服务名称, k8s为容器名称, 物理机为服务名 Target string `bson:"target" json:"target"` // 使用预定义编译管理模块中的内容生成SubTasks, diff --git a/pkg/shared/poetry/check.go b/pkg/microservice/picket/client/aslan/client.go similarity index 69% rename from pkg/shared/poetry/check.go rename to pkg/microservice/picket/client/aslan/client.go index d205c5121359b8ef13f4e891f6b645eb82ca084c..42302493d54c6f9f8cd231965aed1f716b1f82aa 100644 --- a/pkg/shared/poetry/check.go +++ b/pkg/microservice/picket/client/aslan/client.go @@ -14,24 +14,28 @@ See the License for the specific language governing permissions and limitations under the License. */ -package poetry +package aslan import ( + "github.com/koderover/zadig/pkg/config" "github.com/koderover/zadig/pkg/tool/httpclient" ) -type features struct { - Features []string `json:"features"` +type Client struct { + *httpclient.Client + + host string } -func (c *Client) ListFeatures() ([]string, error) { - url := "/directory/check" +func New() *Client { + host := config.AslanServiceAddress() - fs := &features{} - _, err := c.Get(url, httpclient.SetResult(fs)) - if err != nil { - return nil, err - } + c := httpclient.New( + httpclient.SetHostURL(host + "/api"), + ) - return fs.Features, nil + return &Client{ + Client: c, + host: host, + } } diff --git a/pkg/microservice/picket/client/aslan/project.go b/pkg/microservice/picket/client/aslan/project.go new file mode 100644 index 0000000000000000000000000000000000000000..7aaf053e007bd40a899d8f7ba70abee1b615f1d7 --- /dev/null +++ b/pkg/microservice/picket/client/aslan/project.go @@ -0,0 +1,51 @@ +package aslan + +import ( + "fmt" + "net/http" + "net/url" + + "github.com/koderover/zadig/pkg/tool/httpclient" +) + +func (c *Client) DeleteProject(header http.Header, qs url.Values, productName string) ([]byte, error) { + url := fmt.Sprintf("/project/products/%s", productName) + + res, err := c.Delete(url, httpclient.SetHeadersFromHTTPHeader(header), httpclient.SetQueryParamsFromValues(qs)) + if err != nil { + return nil, err + } + + return res.Body(), nil +} + +func (c *Client) ListProjects(header http.Header, qs url.Values) ([]byte, error) { + url := "/project/projects" + + res, err := c.Get(url, httpclient.SetHeadersFromHTTPHeader(header), httpclient.SetQueryParamsFromValues(qs)) + if err != nil { + return nil, err + } + + return res.Body(), nil +} + +func (c *Client) CreateProject(header http.Header, qs url.Values, body []byte) ([]byte, error) { + url := "/project/products" + res, err := c.Post(url, httpclient.SetHeadersFromHTTPHeader(header), httpclient.SetQueryParamsFromValues(qs), httpclient.SetBody(body)) + if err != nil { + return nil, err + } + + return res.Body(), nil +} + +func (c *Client) UpdateProject(header http.Header, qs url.Values, body []byte) ([]byte, error) { + url := "/project/products" + res, err := c.Put(url, httpclient.SetHeadersFromHTTPHeader(header), httpclient.SetQueryParamsFromValues(qs), httpclient.SetBody(body)) + if err != nil { + return nil, err + } + + return res.Body(), nil +} diff --git a/pkg/microservice/picket/client/aslan/workflow.go b/pkg/microservice/picket/client/aslan/workflow.go new file mode 100644 index 0000000000000000000000000000000000000000..5bd8014ce283909979d025b1c219bd0bb1a2ae13 --- /dev/null +++ b/pkg/microservice/picket/client/aslan/workflow.go @@ -0,0 +1,76 @@ +package aslan + +import ( + "fmt" + "net/http" + "net/url" + + "github.com/koderover/zadig/pkg/tool/httpclient" + "github.com/koderover/zadig/pkg/tool/log" +) + +func (c *Client) ListTestWorkflows(testName string, header http.Header, qs url.Values) ([]byte, error) { + url := fmt.Sprintf("/workflow/workflow/testName/%s", testName) + + res, err := c.Get(url, httpclient.SetHeadersFromHTTPHeader(header), httpclient.SetQueryParamsFromValues(qs)) + if err != nil { + return nil, err + } + + return res.Body(), nil +} + +func (c *Client) CreateWorkflowTask(header http.Header, qs url.Values, body []byte) ([]byte, error) { + url := "/workflow/workflowtask" + + res, err := c.Post(url, httpclient.SetHeadersFromHTTPHeader(header), httpclient.SetQueryParamsFromValues(qs), httpclient.SetBody(body)) + if err != nil { + return nil, err + } + + return res.Body(), nil +} + +func (c *Client) CancelWorkflowTask(header http.Header, qs url.Values, id string, name string) (statusCode int, err error) { + url := fmt.Sprintf("/workflow/workflowtask/id/%s/pipelines/%s", id, name) + + res, err := c.Delete(url, httpclient.SetHeadersFromHTTPHeader(header), httpclient.SetQueryParamsFromValues(qs)) + if err != nil { + return http.StatusInternalServerError, err + } + + return res.StatusCode(), nil +} + +func (c *Client) RestartWorkflowTask(header http.Header, qs url.Values, id string, name string) (statusCode int, err error) { + url := fmt.Sprintf("/workflow/workflowtask/id/%s/pipelines/%s/restart", id, name) + + res, err := c.Post(url, httpclient.SetHeadersFromHTTPHeader(header), httpclient.SetQueryParamsFromValues(qs)) + if err != nil { + log.Errorf("RestartWorkflowTask err: %s,res: %s", err, string(res.Body())) + return http.StatusInternalServerError, err + } + + return res.StatusCode(), nil +} +func (c *Client) ListWorkflowTask(header http.Header, qs url.Values, commitId string) ([]byte, error) { + url := fmt.Sprintf("/workflow/v2/status/task/info?commitId=%s", commitId) + + res, err := c.Get(url, httpclient.SetHeadersFromHTTPHeader(header), httpclient.SetQueryParamsFromValues(qs)) + if err != nil { + return nil, err + } + + return res.Body(), nil +} + +func (c *Client) ListDelivery(header http.Header, qs url.Values, productName, workflowName, taskId, perPage, page string) ([]byte, error) { + url := fmt.Sprintf("/delivery/releases?orgId=1&productName=%s&workflowName=%s&taskId=%s&per_page=%s&page=%s", productName, workflowName, taskId, perPage, page) + + res, err := c.Get(url, httpclient.SetHeadersFromHTTPHeader(header), httpclient.SetQueryParamsFromValues(qs)) + if err != nil { + return nil, err + } + + return res.Body(), nil +} diff --git a/pkg/microservice/picket/client/opa/evaluate.go b/pkg/microservice/picket/client/opa/evaluate.go index f5920ae629c829680dfbc99d6bef1e78d76a2d59..d0fb31f964567b5372c3490ecb5968f3f95e60f3 100644 --- a/pkg/microservice/picket/client/opa/evaluate.go +++ b/pkg/microservice/picket/client/opa/evaluate.go @@ -7,20 +7,27 @@ import ( "github.com/koderover/zadig/pkg/tool/httpclient" ) +type InputGenerator func() (*Input, error) + // Evaluate evaluates the query with the given input and return a json response which has a field called "result" -func (c *Client) Evaluate(query string, input interface{}) ([]byte, error) { +func (c *Client) Evaluate(query string, result interface{}, ig InputGenerator) error { + input, err := ig() + if err != nil { + return err + } + url := "v1/data" - req := struct{ + req := struct { Input interface{} `json:"input"` }{ Input: input, } queryURL := fmt.Sprintf("%s/%s", url, strings.ReplaceAll(query, ".", "/")) - res, err := c.Post(queryURL, httpclient.SetBody(req)) + _, err = c.Post(queryURL, httpclient.SetBody(req), httpclient.SetResult(result)) if err != nil { - return nil, err + return err } - return res.Body(), nil + return nil } diff --git a/pkg/microservice/picket/client/opa/input.go b/pkg/microservice/picket/client/opa/input.go new file mode 100644 index 0000000000000000000000000000000000000000..df28516dc9d89fbf6a9b8a51fbcd822b5ace0d19 --- /dev/null +++ b/pkg/microservice/picket/client/opa/input.go @@ -0,0 +1,23 @@ +package opa + +type Input struct { + ParsedQuery *ParseQuery `json:"parsed_query"` + ParsedPath []string `json:"parsed_path"` + Attributes *Attributes `json:"attributes"` +} +type ParseQuery struct { + ProjectName []string `json:"projectName"` +} + +type Attributes struct { + Request *Request `json:"request"` +} + +type Request struct { + HTTP *HTTPSpec `json:"http"` +} + +type HTTPSpec struct { + Method string `json:"method"` + Headers map[string]string `json:"headers"` +} diff --git a/pkg/microservice/picket/client/policy/client.go b/pkg/microservice/picket/client/policy/client.go new file mode 100644 index 0000000000000000000000000000000000000000..18b72463d9e3f55d41b208494c279b9a400c55d0 --- /dev/null +++ b/pkg/microservice/picket/client/policy/client.go @@ -0,0 +1,25 @@ +package policy + +import ( + "github.com/koderover/zadig/pkg/config" + "github.com/koderover/zadig/pkg/tool/httpclient" +) + +type Client struct { + *httpclient.Client + + host string +} + +func New() *Client { + host := config.PolicyServiceAddress() + + c := httpclient.New( + httpclient.SetHostURL(host + "/api/v1"), + ) + + return &Client{ + Client: c, + host: host, + } +} diff --git a/pkg/microservice/picket/client/policy/rolebinding.go b/pkg/microservice/picket/client/policy/rolebinding.go new file mode 100644 index 0000000000000000000000000000000000000000..faa2e2a7033a7565c0acfad4b5d5658717aa475f --- /dev/null +++ b/pkg/microservice/picket/client/policy/rolebinding.go @@ -0,0 +1,27 @@ +package policy + +import ( + "net/http" + "net/url" + + "github.com/koderover/zadig/pkg/tool/httpclient" +) + +type RoleBinding struct { + Name string `json:"name"` + UID string `json:"uid"` + Role string `json:"role"` + Public bool `json:"public"` +} + +func (c *Client) ListRoleBindings(header http.Header, qs url.Values) ([]*RoleBinding, error) { + url := "/rolebindings" + + res := make([]*RoleBinding, 0) + _, err := c.Get(url, httpclient.SetHeadersFromHTTPHeader(header), httpclient.SetQueryParamsFromValues(qs), httpclient.SetResult(&res)) + if err != nil { + return nil, err + } + + return res, nil +} diff --git a/pkg/microservice/picket/core/evaluation/service/evaluate.go b/pkg/microservice/picket/core/evaluation/service/evaluate.go index 4de488cb897f076a535e9313b69d66a494139beb..867e059e682b60cf40eb7a6660224b0e6a7e9783 100644 --- a/pkg/microservice/picket/core/evaluation/service/evaluate.go +++ b/pkg/microservice/picket/core/evaluation/service/evaluate.go @@ -17,66 +17,36 @@ limitations under the License. package service import ( - "encoding/json" "net/http" "strings" "go.uber.org/zap" "github.com/koderover/zadig/pkg/microservice/picket/client/opa" + "github.com/koderover/zadig/pkg/setting" ) -type input struct { - ParsedQuery parseQuery `json:"parsed_query"` - ParsedPath []string `json:"parsed_path"` - Attributes attributes `json:"attributes"` -} -type parseQuery struct { - ProjectName []string `json:"projectName"` -} - -type attributes struct { - Request request `json:"request"` -} - -type request struct { - Http HTTP `json:"http"` -} - -type HTTP struct { - Method string `json:"method"` - Headers map[string]string `json:"headers"` -} - -type opaRes struct { +type evaluateResult struct { Result bool `json:"result"` } func Evaluate(header http.Header, projectName string, grantsReq []GrantReq, logger *zap.SugaredLogger) ([]GrantRes, error) { - // 拼接参数,请求opa - authorization := header.Get("authorization") - opaHeaders := map[string]string{} - opaHeaders["authorization"] = authorization var grantsRes []GrantRes opaClient := opa.NewDefault() // 对于每一个action+endpoint 都去请求opa for _, v := range grantsReq { parsedPath := strings.Split(strings.Trim(v.EndPoint, "/"), "/") - input := generateOPAInput(projectName, parsedPath, v.Method, opaHeaders) - res, err := opaClient.Evaluate("rbac.allow", input) + res := &evaluateResult{} + err := opaClient.Evaluate( + "rbac.allow", res, + func() (*opa.Input, error) { return generateOPAInput(header, projectName, v.Method, parsedPath), nil }) if err != nil { logger.Errorf("opa evaluate endpoint: %v method: %v err: %s", v.EndPoint, v.Method, err) grantsRes = append(grantsRes, GrantRes{v, false}) continue } - var opaR opaRes - if err := json.Unmarshal(res, &opaR); err != nil { - logger.Errorf("opa res Unmarshal err %s", err) - grantsRes = append(grantsRes, GrantRes{v, false}) - continue - } - grantsRes = append(grantsRes, GrantRes{v, opaR.Result}) + grantsRes = append(grantsRes, GrantRes{v, res.Result}) } return grantsRes, nil } @@ -91,16 +61,20 @@ type GrantRes struct { Allow bool `json:"allow"` } -func generateOPAInput(projectName string, parsedPath []string, method string, head map[string]string) input { - return input{ - ParsedQuery: parseQuery{ +func generateOPAInput(header http.Header, projectName, method string, parsedPath []string) *opa.Input { + authorization := header.Get(strings.ToLower(setting.AuthorizationHeader)) + headers := map[string]string{} + headers[strings.ToLower(setting.AuthorizationHeader)] = authorization + + return &opa.Input{ + ParsedQuery: &opa.ParseQuery{ ProjectName: []string{projectName}, }, ParsedPath: parsedPath, - Attributes: attributes{ - Request: request{Http: HTTP{ + Attributes: &opa.Attributes{ + Request: &opa.Request{HTTP: &opa.HTTPSpec{ Method: method, - Headers: head, + Headers: headers, }}, }, } diff --git a/pkg/microservice/picket/core/filter/handler/codehost.go b/pkg/microservice/picket/core/filter/handler/codehost.go new file mode 100644 index 0000000000000000000000000000000000000000..a7a2fec88addf2a9a9fe4f197b538155fbad73d2 --- /dev/null +++ b/pkg/microservice/picket/core/filter/handler/codehost.go @@ -0,0 +1,15 @@ +package handler + +import ( + "github.com/gin-gonic/gin" + + "github.com/koderover/zadig/pkg/microservice/picket/core/filter/service" + internalhandler "github.com/koderover/zadig/pkg/shared/handler" +) + +func ListCodeHost(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + ctx.Resp, ctx.Err = service.ListCodeHost(ctx.Logger) +} diff --git a/pkg/microservice/picket/core/filter/handler/project.go b/pkg/microservice/picket/core/filter/handler/project.go new file mode 100644 index 0000000000000000000000000000000000000000..c52600547b6c2490bbb3211f060bd31f155f3df5 --- /dev/null +++ b/pkg/microservice/picket/core/filter/handler/project.go @@ -0,0 +1,65 @@ +package handler + +import ( + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" + + "github.com/koderover/zadig/pkg/microservice/picket/core/filter/service" + internalhandler "github.com/koderover/zadig/pkg/shared/handler" + e "github.com/koderover/zadig/pkg/tool/errors" +) + +func ListProjects(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + ctx.Resp, ctx.Err = service.ListProjects(c.Request.Header, c.Request.URL.Query(), ctx.Logger) +} + +func CreateProject(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + args := &service.CreateProjectArgs{} + if err := c.ShouldBindBodyWith(args, binding.JSON); err != nil { + ctx.Err = e.ErrInvalidParam.AddErr(err).AddDesc("invalid CreateProjectReq") + return + } + body := getReqBody(c) + + ctx.Resp, ctx.Err = service.CreateProject(c.Request.Header, body, c.Request.URL.Query(), args, ctx.Logger) +} + +func getReqBody(c *gin.Context) (body []byte) { + if cb, ok := c.Get(gin.BodyBytesKey); ok { + if cbb, ok := cb.([]byte); ok { + body = cbb + } + } + return body +} + +type UpdateProjectReq struct { + Public bool `json:"public"` + ProductName string `json:"product_name"` +} + +func UpdateProject(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + args := new(UpdateProjectReq) + if err := c.ShouldBindBodyWith(args, binding.JSON); err != nil { + ctx.Err = e.ErrInvalidParam.AddErr(err).AddDesc("invalid UpdateProject") + return + } + body := getReqBody(c) + ctx.Resp, ctx.Err = service.UpdateProject(c.Request.Header, c.Request.URL.Query(), body, args.ProductName, args.Public, ctx.Logger) +} + +func DeleteProject(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + ctx.Resp, ctx.Err = service.DeleteProject(c.Request.Header, c.Request.URL.Query(), c.Param("name"), ctx.Logger) +} diff --git a/pkg/microservice/picket/core/filter/handler/rolebinding.go b/pkg/microservice/picket/core/filter/handler/rolebinding.go new file mode 100644 index 0000000000000000000000000000000000000000..9a69939c43eecbc395cb7fffd776edfe7feb3419 --- /dev/null +++ b/pkg/microservice/picket/core/filter/handler/rolebinding.go @@ -0,0 +1,22 @@ +package handler + +import ( + "github.com/gin-gonic/gin" + + "github.com/koderover/zadig/pkg/microservice/picket/core/filter/service" + internalhandler "github.com/koderover/zadig/pkg/shared/handler" + e "github.com/koderover/zadig/pkg/tool/errors" +) + +func ListRoleBindings(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + projectName := c.Query("projectName") + if projectName == "" { + ctx.Err = e.ErrInvalidParam.AddDesc("projectName is empty") + return + } + + ctx.Resp, ctx.Err = service.ListRoleBindings(c.Request.Header, c.Request.URL.Query(), ctx.Logger) +} diff --git a/pkg/microservice/aslan/core/common/handler/token.go b/pkg/microservice/picket/core/filter/handler/router.go similarity index 53% rename from pkg/microservice/aslan/core/common/handler/token.go rename to pkg/microservice/picket/core/filter/handler/router.go index 7fee3260bcfccd4c8de0c7e981b1dab902d0c452..421fdc1a5faa0d1ce24e2cc54756a146c5677e4d 100644 --- a/pkg/microservice/aslan/core/common/handler/token.go +++ b/pkg/microservice/picket/core/filter/handler/router.go @@ -17,26 +17,31 @@ limitations under the License. package handler import ( - "net/http" - "strings" - "github.com/gin-gonic/gin" - - "github.com/koderover/zadig/pkg/setting" ) -func GetToken(c *gin.Context) { - authorization := c.Request.Header.Get(setting.AuthorizationHeader) - if authorization != "" { - if strings.HasPrefix(authorization, setting.UserAPIKey+" ") { - token := strings.Split(authorization, " ")[1] - c.JSON(http.StatusOK, gin.H{"token": token}) - return - } - } else if token, err := c.Cookie("TOKEN"); err == nil { - c.JSON(http.StatusOK, gin.H{"token": token}) - return +type Router struct{} + +func (*Router) Inject(router *gin.RouterGroup) { + projects := router.Group("projects") + { + projects.DELETE("/:name", DeleteProject) + projects.GET("", ListProjects) + projects.POST("", CreateProject) + projects.PUT("/:name", UpdateProject) } - c.JSON(http.StatusBadRequest, gin.H{"message": "illegal request"}) + workflows := router.Group("workflows") + { + workflows.GET("testName/:testName", ListTestWorkflows) + } + + rolebindings := router.Group("rolebindings") + { + rolebindings.GET("", ListRoleBindings) + } + codehosts := router.Group("codehosts") + { + codehosts.GET("", ListCodeHost) + } } diff --git a/pkg/microservice/picket/core/filter/handler/workflow.go b/pkg/microservice/picket/core/filter/handler/workflow.go new file mode 100644 index 0000000000000000000000000000000000000000..2a93f97747b951a05d6377c194caf2ab6502bf3b --- /dev/null +++ b/pkg/microservice/picket/core/filter/handler/workflow.go @@ -0,0 +1,15 @@ +package handler + +import ( + "github.com/gin-gonic/gin" + + "github.com/koderover/zadig/pkg/microservice/picket/core/filter/service" + internalhandler "github.com/koderover/zadig/pkg/shared/handler" +) + +func ListTestWorkflows(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + testName := c.Param("testName") + ctx.Resp, ctx.Err = service.ListTestWorkflows(testName, c.Request.Header, c.Request.URL.Query(), ctx.Logger) +} diff --git a/pkg/microservice/picket/core/filter/service/codehost.go b/pkg/microservice/picket/core/filter/service/codehost.go new file mode 100644 index 0000000000000000000000000000000000000000..7ea6998f684c78b70c2ea87f0a5bb67d42101c0e --- /dev/null +++ b/pkg/microservice/picket/core/filter/service/codehost.go @@ -0,0 +1,20 @@ +package service + +import ( + "go.uber.org/zap" + + "github.com/koderover/zadig/pkg/shared/client/systemconfig" +) + +func ListCodeHost(_ *zap.SugaredLogger) ([]*systemconfig.CodeHost, error) { + list, err := systemconfig.New().ListCodeHosts() + if err != nil { + return nil, err + } + for k, _ := range list { + list[k].AccessKey = "***" + list[k].SecretKey = "***" + list[k].AccessToken = "***" + } + return list, nil +} diff --git a/pkg/microservice/picket/core/filter/service/project.go b/pkg/microservice/picket/core/filter/service/project.go new file mode 100644 index 0000000000000000000000000000000000000000..fded8d7b13333aad2caa4beeaeccd5857aafb075 --- /dev/null +++ b/pkg/microservice/picket/core/filter/service/project.go @@ -0,0 +1,162 @@ +package service + +import ( + "fmt" + "net/http" + "net/url" + "strings" + + "go.uber.org/zap" + + "github.com/koderover/zadig/pkg/microservice/picket/client/aslan" + "github.com/koderover/zadig/pkg/microservice/picket/client/opa" + "github.com/koderover/zadig/pkg/setting" + "github.com/koderover/zadig/pkg/shared/client/policy" + "github.com/koderover/zadig/pkg/tool/log" +) + +type CreateProjectArgs struct { + Public bool `json:"public"` + ProductName string `json:"product_name"` + Admins []string `json:"admins"` +} + +type allowedProjectsData struct { + Result []string `json:"result"` +} + +func CreateProject(header http.Header, body []byte, qs url.Values, args *CreateProjectArgs, logger *zap.SugaredLogger) ([]byte, error) { + var rbs []*policy.RoleBinding + for _, uid := range args.Admins { + roleBindingName := fmt.Sprintf(setting.RoleBindingNameFmt, uid, setting.Admin, args.ProductName) + rbs = append(rbs, &policy.RoleBinding{ + Name: roleBindingName, + UID: uid, + Role: string(setting.Admin), + Public: true, + }) + } + + if args.Public { + roleBindingName := fmt.Sprintf(setting.RoleBindingNameFmt, "*", setting.ReadOnly, args.ProductName) + rbs = append(rbs, &policy.RoleBinding{ + Name: roleBindingName, + UID: "*", + Role: string(setting.ReadOnly), + Public: true, + }) + } + + policyClient := policy.NewDefault() + for _, rb := range rbs { + if err := policyClient.CreateOrUpdateRoleBinding(args.ProductName, rb); err != nil { + logger.Errorf("Failed to create rolebinding %s, err: %s", rb.Name, err) + return nil, err + } + } + + res, err := aslan.New().CreateProject(header, qs, body) + if err != nil { + logger.Errorf("Failed to create project %s, err: %s", args.ProductName, err) + for _, rb := range rbs { + if err1 := policyClient.DeleteRoleBinding(rb.Name, args.ProductName); err1 != nil { + logger.Errorf("Failed to create rolebinding %s, err: %s", rb.Name, err1) + } + } + + return nil, err + } + + return res, nil +} + +func UpdateProject(header http.Header, qs url.Values, body []byte, projectName string, public bool, logger *zap.SugaredLogger) ([]byte, error) { + // role binding + roleBindingName := fmt.Sprintf(setting.RoleBindingNameFmt, "*", setting.ReadOnly, projectName) + if !public { + if err := policy.NewDefault().DeleteRoleBinding(roleBindingName, projectName); err != nil { + logger.Errorf("Failed to delete role binding, err: %s", err) + return nil, err + } + } else { + if err := policy.NewDefault().CreateOrUpdateRoleBinding(projectName, &policy.RoleBinding{ + Name: roleBindingName, + UID: "*", + Role: string(setting.ReadOnly), + Public: true, + }); err != nil { + logger.Errorf("Failed to create role binding, err: %s", err) + return nil, err + } + } + + res, err := aslan.New().UpdateProject(header, qs, body) + if err != nil { + logger.Errorf("Failed to create project %s, err: %s", projectName, err) + return nil, err + } + + return res, nil +} + +func ListProjects(header http.Header, qs url.Values, logger *zap.SugaredLogger) ([]byte, error) { + names, err := getVisibleProjects(header, logger) + if err != nil { + logger.Errorf("Failed to get allowed project names, err: %s", err) + return nil, err + } + + if len(names) == 0 { + return []byte("[]"), nil + } + + if !(len(names) == 1 && names[0] == "*") { + for _, name := range names { + qs.Add("names", name) + } + } + + aslanClient := aslan.New() + + return aslanClient.ListProjects(header, qs) +} + +func DeleteProject(header http.Header, qs url.Values, productName string, logger *zap.SugaredLogger) ([]byte, error) { + // delete roles and rolebindings + if err := policy.NewDefault().DeleteRoleBindings([]string{"*"}, productName); err != nil { + log.Errorf("delete rolebindings err:%s", err) + } + if err := policy.NewDefault().DeleteRoles([]string{"*"}, productName); err != nil { + log.Errorf("delete roles err:%s", err) + } + return aslan.New().DeleteProject(header, qs, productName) +} + +func getVisibleProjects(headers http.Header, logger *zap.SugaredLogger) ([]string, error) { + res := &allowedProjectsData{} + opaClient := opa.NewDefault() + err := opaClient.Evaluate("rbac.user_visible_projects", res, func() (*opa.Input, error) { return generateOPAInput(headers, "", ""), nil }) + if err != nil { + logger.Errorf("opa evaluation failed, err: %s", err) + return nil, err + } + + return res.Result, nil +} + +func generateOPAInput(header http.Header, method string, endpoint string) *opa.Input { + authorization := header.Get(strings.ToLower(setting.AuthorizationHeader)) + headers := map[string]string{} + parsedPath := strings.Split(strings.Trim(endpoint, "/"), "/") + headers[strings.ToLower(setting.AuthorizationHeader)] = authorization + + return &opa.Input{ + Attributes: &opa.Attributes{ + Request: &opa.Request{HTTP: &opa.HTTPSpec{ + Headers: headers, + Method: method, + }}, + }, + ParsedPath: parsedPath, + } +} diff --git a/pkg/microservice/picket/core/filter/service/rolebinding.go b/pkg/microservice/picket/core/filter/service/rolebinding.go new file mode 100644 index 0000000000000000000000000000000000000000..9ec4293d669c3ef20b652660db519dab44b03973 --- /dev/null +++ b/pkg/microservice/picket/core/filter/service/rolebinding.go @@ -0,0 +1,66 @@ +package service + +import ( + "net/http" + "net/url" + + "go.uber.org/zap" + + "github.com/koderover/zadig/pkg/microservice/picket/client/policy" + "github.com/koderover/zadig/pkg/shared/client/user" +) + +const allUsers = "*" + +type roleBinding struct { + *policy.RoleBinding + Username string `json:"username"` + Email string `json:"email"` + Phone string `json:"phone"` + IdentityType string `json:"identity_type"` + Account string `json:"account"` +} + +func ListRoleBindings(header http.Header, qs url.Values, logger *zap.SugaredLogger) ([]*roleBinding, error) { + rbs, err := policy.New().ListRoleBindings(header, qs) + if err != nil { + logger.Errorf("Failed to list rolebindings, err: %s", err) + return nil, err + } + + var uids []string + uidToRoleBinding := make(map[string][]*roleBinding) + for _, rb := range rbs { + if rb.UID != allUsers { + uids = append(uids, rb.UID) + } + uidToRoleBinding[rb.UID] = append(uidToRoleBinding[rb.UID], &roleBinding{RoleBinding: rb}) + } + + users, err := user.New().ListUsers(&user.SearchArgs{UIDs: uids}) + if err != nil { + logger.Errorf("Failed to list users, err: %s", err) + return nil, err + } + + var res []*roleBinding + for _, u := range users { + if rb, ok := uidToRoleBinding[u.UID]; ok { + for _, r := range rb { + r.Username = u.Name + r.Email = u.Email + r.Phone = u.Phone + r.IdentityType = u.IdentityType + r.Account = u.Account + + res = append(res, r) + } + + } + } + + // add all 'allUsers' roles + res = append(res, uidToRoleBinding[allUsers]...) + + return res, nil +} diff --git a/pkg/microservice/picket/core/filter/service/workflow.go b/pkg/microservice/picket/core/filter/service/workflow.go new file mode 100644 index 0000000000000000000000000000000000000000..d2550025d3248da2973f2fc69b7ce95723afa00d --- /dev/null +++ b/pkg/microservice/picket/core/filter/service/workflow.go @@ -0,0 +1,67 @@ +package service + +import ( + "net/http" + "net/url" + + "go.uber.org/zap" + "k8s.io/apimachinery/pkg/util/sets" + + "github.com/koderover/zadig/pkg/microservice/picket/client/aslan" + "github.com/koderover/zadig/pkg/microservice/picket/client/opa" +) + +func ListTestWorkflows(testName string, header http.Header, qs url.Values, logger *zap.SugaredLogger) ([]byte, error) { + rules := []*rule{{ + method: "/api/aslan/workflow/workflow", + endpoint: "PUT", + }} + names, err := getAllowedProjectsWithUpdateWorkflowsPermission(header, rules, logger) + if err != nil { + logger.Errorf("Failed to get allowed project names, err: %s", err) + return nil, err + } + if len(names) == 0 { + return nil, nil + } + if !(len(names) == 1 && names[0] == "*") { + for _, name := range names { + qs.Add("projects", name) + } + } + return aslan.New().ListTestWorkflows(testName, header, qs) +} + +type rule struct { + method string + endpoint string +} + +func getAllowedProjectsWithUpdateWorkflowsPermission(headers http.Header, rules []*rule, logger *zap.SugaredLogger) (projects []string, err error) { + resps := [][]string{} + for _, v := range rules { + res := &allowedProjectsData{} + opaClient := opa.NewDefault() + err := opaClient.Evaluate("rbac.user_allowed_projects", res, func() (*opa.Input, error) { + return generateOPAInput(headers, v.method, v.endpoint), nil + }) + if err != nil { + logger.Errorf("opa evaluation failed, err: %s", err) + return nil, err + } + resps = append(resps, res.Result) + } + return intersect(resps), nil +} + +func intersect(s [][]string) []string { + if len(s) == 0 { + return nil + } + tmp := sets.NewString(s[0]...) + for _, v := range s[1:] { + t := sets.NewString(v...) + tmp = t.Intersection(tmp) + } + return tmp.List() +} diff --git a/pkg/microservice/picket/core/public/handler/public.go b/pkg/microservice/picket/core/public/handler/public.go new file mode 100644 index 0000000000000000000000000000000000000000..5a868e42dce016270518a8be536d34f6ee4d7d13 --- /dev/null +++ b/pkg/microservice/picket/core/public/handler/public.go @@ -0,0 +1,109 @@ +package handler + +import ( + "encoding/json" + "net/http" + + "github.com/gin-gonic/gin" + + "github.com/koderover/zadig/pkg/microservice/picket/core/public/service" + internalhandler "github.com/koderover/zadig/pkg/shared/handler" +) + +func CreateWorkflowTask(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + body, _ := c.GetRawData() + res, err := service.CreateWorkflowTask(c.Request.Header, c.Request.URL.Query(), body, ctx.Logger) + if err != nil { + ctx.Err = err + return + } + // to avoid customer feel confused ,return workflow_name instead of pipline_name + var resp *CreateWorkflowTaskResp + err = json.Unmarshal(res, &resp) + if err != nil { + ctx.Err = err + return + } + resp.WorkflowName = resp.PipelineName + resp.PipelineName = "" + ctx.Resp = resp +} + +type CreateWorkflowTaskResp struct { + PipelineName string `json:"pipeline_name,omitempty"` + WorkflowName string `json:"workflow_name"` + TaskID int64 `json:"task_id"` +} + +type EndpointResponse struct { + ResultCode int `json:"resultCode"` + ErrorMsg string `json:"errorMsg"` +} + +func CancelWorkflowTask(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + id := c.Param("id") + name := c.Param("name") + statusCode, _ := service.CancelWorkflowTask(c.Request.Header, c.Request.URL.Query(), id, name, ctx.Logger) + var code int + var errorMsg string + if statusCode == http.StatusOK { + code = 0 + errorMsg = "success" + } else if statusCode == http.StatusForbidden { + code = statusCode + errorMsg = "forbidden" + } else { + code = statusCode + errorMsg = "fail" + } + ctx.Resp = EndpointResponse{ + ResultCode: code, + ErrorMsg: errorMsg, + } +} + +func RestartWorkflowTask(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + id := c.Param("id") + name := c.Param("name") + statusCode, _ := service.RestartWorkflowTask(c.Request.Header, c.Request.URL.Query(), id, name, ctx.Logger) + var code int + var errorMsg string + if statusCode == http.StatusOK { + code = 0 + errorMsg = "success" + } else if statusCode == http.StatusForbidden { + code = statusCode + errorMsg = "forbidden" + } else { + code = statusCode + errorMsg = "fail" + } + ctx.Resp = EndpointResponse{ + ResultCode: code, + ErrorMsg: errorMsg, + } +} + +func ListWorkflowTask(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + commitId := c.Query("commitId") + ctx.Resp, ctx.Err = service.ListWorkflowTask(c.Request.Header, c.Request.URL.Query(), commitId, ctx.Logger) +} + +func ListDelivery(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + productName := c.Query("projectName") + workflowName := c.Query("workflowName") + taskIDStr := c.Query("taskId") + perPageStr := c.Query("perPage") + pageStr := c.Query("page") + ctx.Resp, ctx.Err = service.ListDelivery(c.Request.Header, c.Request.URL.Query(), productName, workflowName, taskIDStr, perPageStr, pageStr, ctx.Logger) +} diff --git a/pkg/microservice/picket/core/public/handler/router.go b/pkg/microservice/picket/core/public/handler/router.go new file mode 100644 index 0000000000000000000000000000000000000000..7ae9cf8a777e1ba8ee2c3541fac4fff2f6336321 --- /dev/null +++ b/pkg/microservice/picket/core/public/handler/router.go @@ -0,0 +1,19 @@ +package handler + +import ( + "github.com/gin-gonic/gin" +) + +type Router struct{} + +func (*Router) Inject(router *gin.RouterGroup) { + + dev := router.Group("") + { + dev.POST("/workflowTask/create", CreateWorkflowTask) + dev.DELETE("workflowTask/id/:id/pipelines/:name/cancel", CancelWorkflowTask) + dev.POST("/workflowTask/id/:id/pipelines/:name/restart", RestartWorkflowTask) + dev.GET("/workflowTask", ListWorkflowTask) + dev.GET("/dc/releases", ListDelivery) + } +} diff --git a/pkg/microservice/picket/core/public/service/public.go b/pkg/microservice/picket/core/public/service/public.go new file mode 100644 index 0000000000000000000000000000000000000000..787ac43bb8801a8866768dbe01899713c9d7536e --- /dev/null +++ b/pkg/microservice/picket/core/public/service/public.go @@ -0,0 +1,30 @@ +package service + +import ( + "net/http" + "net/url" + + "go.uber.org/zap" + + "github.com/koderover/zadig/pkg/microservice/picket/client/aslan" +) + +func CreateWorkflowTask(header http.Header, qs url.Values, body []byte, _ *zap.SugaredLogger) ([]byte, error) { + return aslan.New().CreateWorkflowTask(header, qs, body) +} + +func CancelWorkflowTask(header http.Header, qs url.Values, id string, name string, _ *zap.SugaredLogger) (int, error) { + return aslan.New().CancelWorkflowTask(header, qs, id, name) +} + +func RestartWorkflowTask(header http.Header, qs url.Values, id string, name string, _ *zap.SugaredLogger) (int, error) { + return aslan.New().RestartWorkflowTask(header, qs, id, name) +} + +func ListWorkflowTask(header http.Header, qs url.Values, commitId string, _ *zap.SugaredLogger) ([]byte, error) { + return aslan.New().ListWorkflowTask(header, qs, commitId) +} + +func ListDelivery(header http.Header, qs url.Values, productName string, workflowName string, taskId string, perPage string, page string, _ *zap.SugaredLogger) ([]byte, error) { + return aslan.New().ListDelivery(header, qs, productName, workflowName, taskId, perPage, page) +} diff --git a/pkg/microservice/picket/server/rest/router.go b/pkg/microservice/picket/server/rest/router.go index 6eece402f47de25364911b27309f55b1d4201b67..ba02b80ebc35067d01babe4f13a73d399f466361 100644 --- a/pkg/microservice/picket/server/rest/router.go +++ b/pkg/microservice/picket/server/rest/router.go @@ -20,14 +20,24 @@ import ( "github.com/gin-gonic/gin" evaluationhandler "github.com/koderover/zadig/pkg/microservice/picket/core/evaluation/handler" + filterhandler "github.com/koderover/zadig/pkg/microservice/picket/core/filter/handler" + publichandler "github.com/koderover/zadig/pkg/microservice/picket/core/public/handler" ) func (s *engine) injectRouterGroup(router *gin.RouterGroup) { for _, r := range []injector{ new(evaluationhandler.Router), + new(filterhandler.Router), } { r.Inject(router.Group("/api/v1")) } + + for _, r := range []injector{ + new(publichandler.Router), + } { + r.Inject(router.Group("/public-api/v1")) + } + } type injector interface { diff --git a/pkg/microservice/podexec/config/config.go b/pkg/microservice/podexec/config/config.go index c75b077e0a22a39e8093a2624e474044a5849546..782d8b451e31106324cf989b153bf76be786736f 100644 --- a/pkg/microservice/podexec/config/config.go +++ b/pkg/microservice/podexec/config/config.go @@ -17,16 +17,9 @@ limitations under the License. package config import ( - "github.com/spf13/viper" - configbase "github.com/koderover/zadig/pkg/config" - "github.com/koderover/zadig/pkg/setting" ) -func PoetryAPIRootKey() string { - return viper.GetString(setting.ENVPoetryAPIRootKey) -} - func HubServerAddr() string { return configbase.HubServerServiceAddress() } diff --git a/pkg/microservice/podexec/core/service/auth.go b/pkg/microservice/podexec/core/service/auth.go deleted file mode 100644 index e45b87fef8870eea3dc1971f01cd11295f967ab4..0000000000000000000000000000000000000000 --- a/pkg/microservice/podexec/core/service/auth.go +++ /dev/null @@ -1,150 +0,0 @@ -/* -Copyright 2021 The KodeRover 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 service - -import ( - "encoding/json" - "net/http" - "strconv" - "strings" - - "github.com/gorilla/mux" - "go.uber.org/zap" - "k8s.io/apimachinery/pkg/util/sets" - - configbase "github.com/koderover/zadig/pkg/config" - "github.com/koderover/zadig/pkg/microservice/podexec/config" - "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/poetry" - "github.com/koderover/zadig/pkg/tool/log" - "github.com/koderover/zadig/pkg/types/permission" -) - -func AuthMiddleware(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - url := r.URL.Path - if strings.Contains("/api/health/", url) { - next.ServeHTTP(w, r) - return - } - - authorization := r.Header.Get(setting.AuthorizationHeader) - if authorization != "" { - if strings.Contains(authorization, setting.RootAPIKey) { - token := strings.Split(authorization, " ") - if len(token) == 2 && token[1] == config.PoetryAPIRootKey() { - next.ServeHTTP(w, r) - } - return - } - - if strings.Contains(authorization, setting.UserAPIKey) { - token := strings.Split(authorization, " ") - if len(token) == 2 { - //根据token获取用户 - userInfo, err := poetry.GetUserDetailByToken(configbase.PoetryServiceAddress(), token[1]) - if err != nil { - w.WriteHeader(http.StatusUnauthorized) - _ = json.NewEncoder(w).Encode(&EndpointResponse{ResultCode: http.StatusUnauthorized, ErrorMsg: "auth failed"}) - return - } - - r.Header.Set("userId", strconv.Itoa(userInfo.ID)) - r.Header.Set("isSuperUser", strconv.FormatBool(userInfo.IsSuperUser)) - next.ServeHTTP(w, r) - } - return - } - } else if token, err := r.Cookie("TOKEN"); err == nil { - userInfo, err := poetry.GetUserDetailByToken(configbase.PoetryServiceAddress(), token.Value) - if err != nil { - log.Errorf("PoetryRequest err:%v", err) - w.WriteHeader(http.StatusUnauthorized) - _ = json.NewEncoder(w).Encode(&EndpointResponse{ResultCode: http.StatusUnauthorized, ErrorMsg: "auth failed"}) - return - } - - r.Header.Set("userId", strconv.Itoa(userInfo.ID)) - r.Header.Set("isSuperUser", strconv.FormatBool(userInfo.IsSuperUser)) - next.ServeHTTP(w, r) - } - }) -} - -func PermissionMiddleware(next http.Handler) http.Handler { - logger := log.SugaredLogger() - - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - url := r.URL.Path - if strings.Contains("/api/health/", url) { - next.ServeHTTP(w, r) - return - } - pathParams := mux.Vars(r) - productName := pathParams["productName"] - userIDStr := r.Header.Get("userId") - isSuperUserStr := r.Header.Get("isSuperUser") - isSuperUser, parseErr := strconv.ParseBool(isSuperUserStr) - if isSuperUser { - next.ServeHTTP(w, r) - return - } - userID, atoiErr := strconv.Atoi(userIDStr) - if parseErr != nil || atoiErr != nil { - w.WriteHeader(http.StatusForbidden) - _ = json.NewEncoder(w).Encode(&EndpointResponse{ResultCode: http.StatusForbidden, ErrorMsg: "forbidden!"}) - return - } - - queryList := r.URL.Query() - clusterID := queryList.Get("clusterId") - if clusterID == "" { - isHaveTestEnvManagePermission := PoetryRequestPermission(userID, permission.TestEnvManageUUID, productName, logger) - if isHaveTestEnvManagePermission { - next.ServeHTTP(w, r) - return - } - } else { - isHaveProdEnvManagePermission := PoetryRequestPermission(userID, permission.ProdEnvManageUUID, productName, logger) - if isHaveProdEnvManagePermission { - next.ServeHTTP(w, r) - return - } - } - - w.WriteHeader(http.StatusForbidden) - _ = json.NewEncoder(w).Encode(&EndpointResponse{ResultCode: http.StatusForbidden, ErrorMsg: "forbidden!"}) - }) -} - -func PoetryRequestPermission(userID int, permissionUUID, productName string, logger *zap.SugaredLogger) bool { - poetryClient := poetry.New(configbase.PoetryServiceAddress(), config.PoetryAPIRootKey()) - if poetryClient.HasOperatePermission(productName, permissionUUID, userID, false, logger) { - return true - } - - uuids, err := poetryClient.GetUserPermissionUUIDs(setting.RoleUserID, "", logger) - if err != nil { - log.Errorf("GetUserPermissionUUIDs error: %v", err) - return false - } - if sets.NewString(uuids...).Has(permissionUUID) { - return true - } - - return false -} diff --git a/pkg/microservice/podexec/server/server.go b/pkg/microservice/podexec/server/server.go index 55f12b9299af14bb3bfb515604ccda115c5015d2..09eb0fdad45ba8ebbcaf354108b1292ca67832ea 100644 --- a/pkg/microservice/podexec/server/server.go +++ b/pkg/microservice/podexec/server/server.go @@ -43,8 +43,6 @@ func Serve(ctx context.Context) error { _ = json.NewEncoder(w).Encode(map[string]string{"message": "success"}) }) router.HandleFunc("/api/{productName}/{namespace}/{podName}/{containerName}/podExec", service.ServeWs) - router.Use(service.AuthMiddleware) - router.Use(service.PermissionMiddleware) server := &http.Server{ Addr: "0.0.0.0:27000", diff --git a/pkg/microservice/policy/core/handler/policy_registration.go b/pkg/microservice/policy/core/handler/policy_registration.go new file mode 100644 index 0000000000000000000000000000000000000000..c8983244f851cc3c73b4b5b192ed041e5ba6c8c3 --- /dev/null +++ b/pkg/microservice/policy/core/handler/policy_registration.go @@ -0,0 +1,29 @@ +package handler + +import ( + "github.com/gin-gonic/gin" + + "github.com/koderover/zadig/pkg/microservice/policy/core/service" + internalhandler "github.com/koderover/zadig/pkg/shared/handler" +) + +func CreateOrUpdatePolicyRegistration(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + args := &service.Policy{} + if err := c.ShouldBindJSON(args); err != nil { + ctx.Err = err + return + } + args.Resource = c.Param("resourceName") + + ctx.Err = service.CreateOrUpdatePolicyRegistration(args, ctx.Logger) +} + +func GetPolicyRegistrationDefinitions(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + ctx.Resp, ctx.Err = service.GetPolicyRegistrationDefinitions(ctx.Logger) +} diff --git a/pkg/microservice/policy/core/handler/role.go b/pkg/microservice/policy/core/handler/role.go index 25d51344095e67c556f08c8f9a20d50d5e488a0a..e9db13389fc26307f46c804fed8c4c4ca25eb9f4 100644 --- a/pkg/microservice/policy/core/handler/role.go +++ b/pkg/microservice/policy/core/handler/role.go @@ -24,6 +24,10 @@ import ( e "github.com/koderover/zadig/pkg/tool/errors" ) +type deleteRolesArgs struct { + Names []string `json:"names"` +} + func CreateRole(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() @@ -43,7 +47,102 @@ func CreateRole(c *gin.Context) { ctx.Err = service.CreateRole(projectName, args, ctx.Logger) } -func CreateGlobalRole(c *gin.Context) { +func UpdateRole(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + args := &service.Role{} + if err := c.ShouldBindJSON(args); err != nil { + ctx.Err = err + return + } + + projectName := c.Query("projectName") + if projectName == "" { + ctx.Err = e.ErrInvalidParam.AddDesc("projectName is empty") + return + } + name := c.Param("name") + args.Name = name + + ctx.Err = service.UpdateRole(projectName, args, ctx.Logger) +} + +func UpdateOrCreateRole(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + args := &service.Role{} + if err := c.ShouldBindJSON(args); err != nil { + ctx.Err = err + return + } + + projectName := c.Query("projectName") + if projectName == "" { + ctx.Err = e.ErrInvalidParam.AddDesc("projectName is empty") + return + } + args.Name = c.Param("name") + + ctx.Err = service.UpdateOrCreateRole(projectName, args, ctx.Logger) +} + +func UpdatePublicRole(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + args := &service.Role{} + if err := c.ShouldBindJSON(args); err != nil { + ctx.Err = err + return + } + name := c.Param("name") + args.Name = name + ctx.Err = service.UpdateRole("", args, ctx.Logger) +} + +func UpdateOrCreatePublicRole(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + args := &service.Role{} + if err := c.ShouldBindJSON(args); err != nil { + ctx.Err = err + return + } + name := c.Param("name") + args.Name = name + ctx.Err = service.UpdateOrCreateRole("", args, ctx.Logger) +} + +func ListRoles(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + projectName := c.Query("projectName") + if projectName == "" { + ctx.Err = e.ErrInvalidParam.AddDesc("args projectName can't be empty") + return + } + + ctx.Resp, ctx.Err = service.ListRoles(projectName, ctx.Logger) +} + +func GetRole(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + projectName := c.Query("projectName") + if projectName == "" { + ctx.Err = e.ErrInvalidParam.AddDesc("args projectName can't be empty") + return + } + + ctx.Resp, ctx.Err = service.GetRole(projectName, c.Param("name"), ctx.Logger) +} + +func CreatePublicRole(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() @@ -55,3 +154,102 @@ func CreateGlobalRole(c *gin.Context) { ctx.Err = service.CreateRole("", args, ctx.Logger) } + +func ListPublicRoles(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + ctx.Resp, ctx.Err = service.ListRoles("", ctx.Logger) + return +} + +func GetPublicRole(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + ctx.Resp, ctx.Err = service.GetRole("", c.Param("name"), ctx.Logger) +} + +func DeleteRole(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + name := c.Param("name") + projectName := c.Query("projectName") + if projectName == "" { + ctx.Err = e.ErrInvalidParam.AddDesc("args projectName can't be empty") + return + } + + ctx.Err = service.DeleteRole(name, projectName, ctx.Logger) +} + +func DeleteRoles(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + projectName := c.Query("projectName") + if projectName == "" { + ctx.Err = e.ErrInvalidParam.AddDesc("args projectName can't be empty") + return + } + + args := &deleteRolesArgs{} + if err := c.ShouldBindJSON(args); err != nil { + ctx.Err = err + return + } + + ctx.Err = service.DeleteRoles(args.Names, projectName, ctx.Logger) +} + +func DeletePublicRole(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + name := c.Param("name") + ctx.Err = service.DeleteRole(name, "", ctx.Logger) + return +} + +func CreateSystemRole(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + args := &service.Role{} + if err := c.ShouldBindJSON(args); err != nil { + ctx.Err = err + return + } + + ctx.Err = service.CreateRole("*", args, ctx.Logger) +} + +func UpdateOrCreateSystemRole(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + args := &service.Role{} + if err := c.ShouldBindJSON(args); err != nil { + ctx.Err = err + return + } + name := c.Param("name") + args.Name = name + ctx.Err = service.UpdateOrCreateRole("*", args, ctx.Logger) +} + +func ListSystemRoles(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + ctx.Resp, ctx.Err = service.ListRoles("*", ctx.Logger) + return +} + +func DeleteSystemRole(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + name := c.Param("name") + ctx.Err = service.DeleteRole(name, "*", ctx.Logger) + return +} diff --git a/pkg/microservice/policy/core/handler/role_binding.go b/pkg/microservice/policy/core/handler/role_binding.go index 33b73e8fcda57f83287a2a9c4145eee63387fa20..d33d7b8fe61b2c0df0209f686adc1ec3e8d865f1 100644 --- a/pkg/microservice/policy/core/handler/role_binding.go +++ b/pkg/microservice/policy/core/handler/role_binding.go @@ -24,6 +24,26 @@ import ( e "github.com/koderover/zadig/pkg/tool/errors" ) +type deleteRoleBindingsArgs struct { + Names []string `json:"names"` +} + +func UpdateRoleBinding(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + projectName := c.Query("projectName") + if projectName == "" { + ctx.Err = e.ErrInvalidParam.AddDesc("projectName is empty") + return + } + args := &service.RoleBinding{} + if err := c.ShouldBindJSON(&args); err != nil { + ctx.Err = e.ErrInvalidParam.AddDesc("bind json fail %s") + } + ctx.Err = service.UpdateOrCreateRoleBinding(projectName, args, ctx.Logger) +} + func CreateRoleBinding(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() @@ -34,11 +54,128 @@ func CreateRoleBinding(c *gin.Context) { return } + args := make([]*service.RoleBinding, 0) + if c.Query("bulk") == "true" { + if err := c.ShouldBindJSON(&args); err != nil { + ctx.Err = err + return + } + } else { + rb := &service.RoleBinding{} + if err := c.ShouldBindJSON(rb); err != nil { + ctx.Err = err + return + } + args = append(args, rb) + } + + ctx.Err = service.CreateRoleBindings(projectName, args, ctx.Logger) +} + +func ListRoleBindings(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + projectName := c.Query("projectName") + if projectName == "" { + ctx.Err = e.ErrInvalidParam.AddDesc("projectName is empty") + return + } + + ctx.Resp, ctx.Err = service.ListRoleBindings(projectName, "", ctx.Logger) +} + +func DeleteRoleBinding(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + name := c.Param("name") + projectName := c.Query("projectName") + if projectName == "" { + ctx.Err = e.ErrInvalidParam.AddDesc("projectName is empty") + return + } + + ctx.Err = service.DeleteRoleBinding(name, projectName, ctx.Logger) +} + +func DeleteRoleBindings(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + projectName := c.Query("projectName") + if projectName == "" { + ctx.Err = e.ErrInvalidParam.AddDesc("args projectName can't be empty") + return + } + + args := &deleteRoleBindingsArgs{} + if err := c.ShouldBindJSON(args); err != nil { + ctx.Err = err + return + } + + ctx.Err = service.DeleteRoleBindings(args.Names, projectName, ctx.Logger) +} + +func DeleteSystemRoleBinding(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + name := c.Param("name") + ctx.Err = service.DeleteRoleBinding(name, service.SystemScope, ctx.Logger) +} + +func CreateSystemRoleBinding(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + args := &service.RoleBinding{} + if err := c.ShouldBindJSON(args); err != nil { + ctx.Err = err + return + } + + args.Public = false + + ctx.Err = service.CreateRoleBindings(service.SystemScope, []*service.RoleBinding{args}, ctx.Logger) +} + +func CreateOrUpdateSystemRoleBinding(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + args := &service.RoleBinding{} if err := c.ShouldBindJSON(args); err != nil { ctx.Err = err return } - ctx.Err = service.CreateRoleBinding(projectName, args, ctx.Logger) + args.Public = false + + ctx.Err = service.CreateOrUpdateSystemRoleBinding(service.SystemScope, args, ctx.Logger) +} + +func ListSystemRoleBindings(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + ctx.Resp, ctx.Err = service.ListRoleBindings(service.SystemScope, "", ctx.Logger) +} + +func ListUserBindings(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + uid := c.Query("uid") + if uid == "" { + ctx.Err = e.ErrInvalidParam.AddDesc("uid is empty") + return + } + projectName := c.Query("projectName") + if projectName == "" { + projectName = service.SystemScope + } + + ctx.Resp, ctx.Err = service.ListRoleBindings(projectName, uid, ctx.Logger) } diff --git a/pkg/microservice/policy/core/handler/router.go b/pkg/microservice/policy/core/handler/router.go index 32cd3db6c5496cc00e4eb7750356cf22a171f126..69da8b61982362dddadfee21187b78648572d5ee 100644 --- a/pkg/microservice/policy/core/handler/router.go +++ b/pkg/microservice/policy/core/handler/router.go @@ -26,20 +26,67 @@ func (*Router) Inject(router *gin.RouterGroup) { roles := router.Group("roles") { roles.POST("", CreateRole) + roles.POST("/bulk-delete", DeleteRoles) + roles.PATCH("/:name", UpdateRole) + roles.PUT("/:name", UpdateOrCreateRole) + roles.GET("", ListRoles) + roles.GET("/:name", GetRole) + roles.DELETE("/:name", DeleteRole) } - globalRoles := router.Group("global-roles") + publicRoles := router.Group("public-roles") { - globalRoles.POST("", CreateGlobalRole) + publicRoles.POST("", CreatePublicRole) + publicRoles.GET("", ListPublicRoles) + publicRoles.GET("/:name", GetPublicRole) + publicRoles.PATCH("/:name", UpdatePublicRole) + publicRoles.PUT("/:name", UpdateOrCreatePublicRole) + publicRoles.DELETE("/:name", DeletePublicRole) + } + + systemRoles := router.Group("system-roles") + { + systemRoles.POST("", CreateSystemRole) + systemRoles.PUT("/:name", UpdateOrCreateSystemRole) + systemRoles.GET("", ListSystemRoles) + systemRoles.DELETE("/:name", DeleteSystemRole) } roleBindings := router.Group("rolebindings") { roleBindings.POST("", CreateRoleBinding) + roleBindings.PUT("/:name", UpdateRoleBinding) + roleBindings.GET("", ListRoleBindings) + roleBindings.DELETE("/:name", DeleteRoleBinding) + roleBindings.POST("/bulk-delete", DeleteRoleBindings) + } + + systemRoleBindings := router.Group("system-rolebindings") + { + systemRoleBindings.POST("", CreateSystemRoleBinding) + systemRoleBindings.GET("", ListSystemRoleBindings) + systemRoleBindings.DELETE("/:name", DeleteSystemRoleBinding) + systemRoleBindings.PUT("/:name", CreateOrUpdateSystemRoleBinding) + } + + userBindings := router.Group("userbindings") + { + userBindings.GET("", ListUserBindings) } bundles := router.Group("bundles") { bundles.GET("/:name", DownloadBundle) } + + policyRegistrations := router.Group("policies") + { + policyRegistrations.PUT("/:resourceName", CreateOrUpdatePolicyRegistration) + } + + policyDefinitions := router.Group("policy-definitions") + { + policyDefinitions.GET("", GetPolicyRegistrationDefinitions) + } + } diff --git a/pkg/microservice/policy/core/repository/models/policy.go b/pkg/microservice/policy/core/repository/models/policy.go new file mode 100644 index 0000000000000000000000000000000000000000..6797f8feca511344f1fdd2b2ef92ba9321cf105b --- /dev/null +++ b/pkg/microservice/policy/core/repository/models/policy.go @@ -0,0 +1,40 @@ +/* +Copyright 2021 The KodeRover 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 + +type Policy struct { + Resource string `bson:"resource" json:"resource"` + Alias string `bson:"alias" json:"alias"` + Description string `bson:"description" json:"description"` + Rules []*PolicyRule `bson:"rules" json:"rules"` +} + +type PolicyRule struct { + Action string `bson:"action" json:"action"` + Alias string `bson:"alias" json:"alias"` + Description string `bson:"description" json:"description"` + Rules []*ActionRule `bson:"rules" json:"rules"` +} + +type ActionRule struct { + Method string `bson:"method" json:"method"` + Endpoint string `bson:"endpoint" json:"endpoint"` +} + +func (Policy) TableName() string { + return "policy" +} diff --git a/pkg/microservice/policy/core/repository/models/role.go b/pkg/microservice/policy/core/repository/models/role.go index a49233a163fb9fa8a2acb4abdc672d81743610a9..63c51034655ac121a92022091fc337fac3cbd848 100644 --- a/pkg/microservice/policy/core/repository/models/role.go +++ b/pkg/microservice/policy/core/repository/models/role.go @@ -24,23 +24,23 @@ const ( // Role is a namespaced or cluster scoped, logical grouping of PolicyRules that can be referenced as a unit by a RoleBinding. // for a cluster scoped Role, namespace is empty. type Role struct { - Name string `bson:"name" json:"name"` - Namespace string `bson:"namespace" json:"namespace"` - Rules []*PolicyRule `bson:"rules" json:"rules"` - Kind string `bson:"kind" json:"kind"` + Name string `bson:"name" json:"name"` + Namespace string `bson:"namespace" json:"namespace"` + Rules []*Rule `bson:"rules" json:"rules"` } -// PolicyRule holds information that describes a policy rule, but does not contain information +// Rule holds information that describes a policy rule, but does not contain information // about whom the rule applies to. // If Kind is "resource", verbs are resource actions, while resources are resource names -type PolicyRule struct { +type Rule struct { // Verbs is a list of http methods or resource actions that apply to ALL the Resources contained in this rule. '*' represents all methods. - Verbs []string `bson:"verbs" json:"verbs"` + Verbs []string `bson:"verbs" json:"verbs"` // Resources is a list of resources this rule applies to. '*' represents all resources. Resources []string `bson:"resources" json:"resources"` + Kind string `bson:"kind" json:"kind"` } func (Role) TableName() string { - return "policy_role" + return "role" } diff --git a/pkg/microservice/policy/core/repository/models/role_binding.go b/pkg/microservice/policy/core/repository/models/role_binding.go index 956b1b1b7f3bbf4d4c59dee56e243ace7055318f..64d24dca363eb71e5a8d741d4277eeb9e5ebd04c 100644 --- a/pkg/microservice/policy/core/repository/models/role_binding.go +++ b/pkg/microservice/policy/core/repository/models/role_binding.go @@ -41,8 +41,8 @@ type RoleBinding struct { type Subject struct { // Kind of object being referenced. allowed values are "User", "Group". Kind SubjectKind `bson:"kind" json:"kind"` - // Name of the object being referenced. - Name string `bson:"name" json:"name"` + // unique identifier of the object being referenced. + UID string `bson:"uid" json:"uid"` } // RoleRef contains information that points to the role being used diff --git a/pkg/microservice/policy/core/repository/mongodb/policy_registration.go b/pkg/microservice/policy/core/repository/mongodb/policy_registration.go new file mode 100644 index 0000000000000000000000000000000000000000..344486d06477c555bb66268aa3d2669f724de44f --- /dev/null +++ b/pkg/microservice/policy/core/repository/mongodb/policy_registration.go @@ -0,0 +1,88 @@ +/* +Copyright 2021 The KodeRover 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 mongodb + +import ( + "context" + "fmt" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + + "github.com/koderover/zadig/pkg/config" + "github.com/koderover/zadig/pkg/microservice/policy/core/repository/models" + mongotool "github.com/koderover/zadig/pkg/tool/mongo" +) + +type PolicyColl struct { + *mongo.Collection + + coll string +} + +func NewPolicyColl() *PolicyColl { + name := models.Policy{}.TableName() + return &PolicyColl{ + Collection: mongotool.Database(config.MongoDatabase()).Collection(name), + coll: name, + } +} + +func (c *PolicyColl) GetCollectionName() string { + return c.coll +} + +func (c *PolicyColl) EnsureIndex(ctx context.Context) error { + mod := mongo.IndexModel{ + Keys: bson.M{"resource": 1}, + Options: options.Index().SetUnique(true), + } + + _, err := c.Indexes().CreateOne(ctx, mod) + + return err +} + +func (c *PolicyColl) List() ([]*models.Policy, error) { + var res []*models.Policy + + ctx := context.Background() + cursor, err := c.Collection.Find(ctx, bson.M{}) + if err != nil { + return nil, err + } + + err = cursor.All(ctx, &res) + if err != nil { + return nil, err + } + + return res, nil +} + +func (c *PolicyColl) UpdateOrCreate(obj *models.Policy) error { + if obj == nil { + return fmt.Errorf("nil object") + } + + query := bson.M{"resource": obj.Resource} + opts := options.Replace().SetUpsert(true) + _, err := c.ReplaceOne(context.TODO(), query, obj, opts) + + return err +} diff --git a/pkg/microservice/policy/core/repository/mongodb/role.go b/pkg/microservice/policy/core/repository/mongodb/role.go index da8595c9ca1b659413de613bb364264558ff55b6..ff13c67fd5f6a8b9ad9a07804af7b12510b4fd16 100644 --- a/pkg/microservice/policy/core/repository/mongodb/role.go +++ b/pkg/microservice/policy/core/repository/mongodb/role.go @@ -18,6 +18,7 @@ package mongodb import ( "context" + "errors" "fmt" "go.mongodb.org/mongo-driver/bson" @@ -81,6 +82,7 @@ func (c *RoleColl) List() ([]*models.Role, error) { var res []*models.Role ctx := context.Background() + cursor, err := c.Collection.Find(ctx, bson.M{}) if err != nil { return nil, err @@ -90,7 +92,24 @@ func (c *RoleColl) List() ([]*models.Role, error) { if err != nil { return nil, err } + return res, nil +} + +func (c *RoleColl) ListBy(projectName string) ([]*models.Role, error) { + var res []*models.Role + + ctx := context.Background() + query := bson.M{"namespace": projectName} + + cursor, err := c.Collection.Find(ctx, query) + if err != nil { + return nil, err + } + err = cursor.All(ctx, &res) + if err != nil { + return nil, err + } return res, nil } @@ -103,3 +122,44 @@ func (c *RoleColl) Create(obj *models.Role) error { return err } + +func (c *RoleColl) Delete(name string, projectName string) error { + query := bson.M{"name": name, "namespace": projectName} + _, err := c.DeleteOne(context.TODO(), query) + return err +} + +func (c *RoleColl) DeleteMany(names []string, projectName string) error { + query := bson.M{"namespace": projectName} + if len(names) > 0 { + query["name"] = bson.M{"$in": names} + } + _, err := c.Collection.DeleteMany(context.TODO(), query) + return err +} + +func (c *RoleColl) UpdateRole(obj *models.Role) error { + // avoid panic issue + if obj == nil { + return errors.New("nil Role") + } + + query := bson.M{"name": obj.Name, "namespace": obj.Namespace} + change := bson.M{"$set": bson.M{ + "rules": obj.Rules, + }} + _, err := c.UpdateOne(context.TODO(), query, change) + return err +} + +func (c *RoleColl) UpdateOrCreate(obj *models.Role) error { + if obj == nil { + return fmt.Errorf("nil object") + } + + query := bson.M{"name": obj.Name, "namespace": obj.Namespace} + opts := options.Replace().SetUpsert(true) + _, err := c.ReplaceOne(context.TODO(), query, obj, opts) + + return err +} diff --git a/pkg/microservice/policy/core/repository/mongodb/role_binding.go b/pkg/microservice/policy/core/repository/mongodb/role_binding.go index 570d53f6b338fe2a0da461be1300f40af78c5517..b3fae0bbbcf023ac72d1b8fa37846b1ca1b1653a 100644 --- a/pkg/microservice/policy/core/repository/mongodb/role_binding.go +++ b/pkg/microservice/policy/core/repository/mongodb/role_binding.go @@ -29,6 +29,10 @@ import ( mongotool "github.com/koderover/zadig/pkg/tool/mongo" ) +type ListOptions struct { + RoleName, RoleNamespace string +} + type RoleBindingColl struct { *mongo.Collection @@ -61,11 +65,20 @@ func (c *RoleBindingColl) EnsureIndex(ctx context.Context) error { return err } -func (c *RoleBindingColl) List() ([]*models.RoleBinding, error) { +func (c *RoleBindingColl) List(opts ...*ListOptions) ([]*models.RoleBinding, error) { var res []*models.RoleBinding ctx := context.Background() - cursor, err := c.Collection.Find(ctx, bson.M{}) + query := bson.M{} + if len(opts) > 0 { + opt := opts[0] + if opt.RoleName != "" { + query["role_ref.name"] = opt.RoleName + query["role_ref.namespace"] = opt.RoleNamespace + } + } + + cursor, err := c.Collection.Find(ctx, query) if err != nil { return nil, err } @@ -78,6 +91,70 @@ func (c *RoleBindingColl) List() ([]*models.RoleBinding, error) { return res, nil } +func (c *RoleBindingColl) ListBy(projectName, uid string) ([]*models.RoleBinding, error) { + var res []*models.RoleBinding + + ctx := context.Background() + query := bson.M{"namespace": projectName} + if uid != "" { + query["subjects.uid"] = uid + query["subjects.kind"] = models.UserKind + } + + cursor, err := c.Collection.Find(ctx, query) + if err != nil { + return nil, err + } + + err = cursor.All(ctx, &res) + if err != nil { + return nil, err + } + + return res, nil +} + +func (c *RoleBindingColl) Delete(name string, projectName string) error { + query := bson.M{"name": name, "namespace": projectName} + _, err := c.DeleteOne(context.TODO(), query) + return err +} + +func (c *RoleBindingColl) DeleteMany(names []string, projectName string) error { + query := bson.M{"namespace": projectName} + if len(names) > 0 { + query["name"] = bson.M{"$in": names} + } + _, err := c.Collection.DeleteMany(context.TODO(), query) + + return err +} + +func (c *RoleBindingColl) DeleteByRole(roleName string, projectName string) error { + query := bson.M{"role_ref.name": roleName, "role_ref.namespace": projectName} + // if projectName == "", delete all rolebindings in all namespaces + if projectName != "" { + query["namespace"] = projectName + } + _, err := c.Collection.DeleteMany(context.TODO(), query) + + return err +} + +func (c *RoleBindingColl) DeleteByRoles(roleNames []string, projectName string) error { + if projectName == "" { + return fmt.Errorf("projectName is empty") + } + if len(roleNames) == 0 { + return nil + } + + query := bson.M{"role_ref.name": bson.M{"$in": roleNames}, "role_ref.namespace": projectName, "namespace": projectName} + _, err := c.Collection.DeleteMany(context.TODO(), query) + + return err +} + func (c *RoleBindingColl) Create(obj *models.RoleBinding) error { if obj == nil { return fmt.Errorf("nil object") @@ -87,3 +164,30 @@ func (c *RoleBindingColl) Create(obj *models.RoleBinding) error { return err } + +func (c *RoleBindingColl) BulkCreate(objs []*models.RoleBinding) error { + if len(objs) == 0 { + return nil + } + + var ois []interface{} + for _, obj := range objs { + ois = append(ois, obj) + } + + _, err := c.InsertMany(context.TODO(), ois) + + return err +} + +func (c *RoleBindingColl) UpdateOrCreate(obj *models.RoleBinding) error { + if obj == nil { + return fmt.Errorf("nil object") + } + + query := bson.M{"name": obj.Name, "namespace": obj.Namespace} + opts := options.Replace().SetUpsert(true) + _, err := c.ReplaceOne(context.TODO(), query, obj, opts) + + return err +} diff --git a/pkg/microservice/policy/core/service.go b/pkg/microservice/policy/core/service.go index 4fc79dce8435eb915386b38dc6824997784caad7..3576ee08a54504df3374d53240dec8de4f046ba4 100644 --- a/pkg/microservice/policy/core/service.go +++ b/pkg/microservice/policy/core/service.go @@ -90,6 +90,7 @@ func initDatabase(ctx context.Context) { for _, r := range []indexer{ mongodb.NewRoleColl(), mongodb.NewRoleBindingColl(), + mongodb.NewPolicyColl(), } { wg.Add(1) go func(r indexer) { diff --git a/pkg/microservice/policy/core/service/bundle/exemption_urls.go b/pkg/microservice/policy/core/service/bundle/exemption_urls.go index 62d041a4892f3d1bfa3c710257168cd0753b5b3f..9c56543b3f5d74e9c1d9a36c56f8166c098a115e 100644 --- a/pkg/microservice/policy/core/service/bundle/exemption_urls.go +++ b/pkg/microservice/policy/core/service/bundle/exemption_urls.go @@ -1,9 +1,13 @@ package bundle +// TODO: Policy Service should not care about the policy details of a certain service, instead, a service which wants +// to be managed by the Policy Service should register its rules to the Policy Service so that the Policy Service knows +// how to make a decision without being aware of the detailed rules. + type exemptionURLs struct { - Global rules `json:"global"` // global urls are only controlled by AuthN, and it is visible for all users - Namespaced rules `json:"namespaced"` // global urls are only controlled by AuthN, and it is visible for users under certain projects Public rules `json:"public"` // public urls are not controlled by AuthN and AuthZ + Privileged rules `json:"privileged"` // privileged urls can only be visited by system admins + Registered rules `json:"registered"` // registered urls are the entire list of urls which are controlled by AuthZ, which means that if an url is not in this list, it is not controlled by AuthZ } type policyRule struct { @@ -11,35 +15,287 @@ type policyRule struct { Endpoints []string `json:"endpoints"` } -var globalURLs = []*policyRule{ +var publicURLs = []*policyRule{ + { + Methods: []string{"GET"}, + Endpoints: []string{"api/aslan/health"}, + }, + { + Methods: []string{"POST"}, + Endpoints: []string{"api/aslan/webhook"}, + }, + { + Methods: []string{"GET"}, + Endpoints: []string{"api/hub/connect"}, + }, + { + Methods: []string{"GET"}, + Endpoints: []string{"api/aslan/testing/report"}, + }, + { + Methods: []string{"GET"}, + Endpoints: []string{"api/aslan/cluster/agent/?*/agent.yaml"}, + }, + { + Methods: []string{"GET"}, + Endpoints: []string{"api/podexec/health"}, + }, + { + Methods: []string{"GET", "POST"}, + Endpoints: []string{"api/v1/login", "api/v1/signup", "api/v1/retrieve", "api/v1/login-enabled"}, + }, + { + Methods: []string{"GET"}, + Endpoints: []string{"api/v1/codehosts/?*/auth", "api/v1/codehosts/callback"}, + }, { Methods: []string{"*"}, - Endpoints: []string{"api/v1/version"}, + Endpoints: []string{"api/v1/callback"}, + }, + { + Methods: []string{"*"}, + Endpoints: []string{"dex/**"}, + }, + { + Methods: []string{"GET"}, + Endpoints: []string{"", "signin", "setup", "static/**", "v1/**", "mobile/**", "productpipelines/**", "favicon.ico"}, + }, + { + Methods: []string{"GET"}, + Endpoints: []string{"api/directory/codehostss/?*/auth", "api/directory/codehosts/callback"}, }, } -var namespacedURLs = []*policyRule{ +// actions which are allowed for system admins only. +var systemAdminURLs = []*policyRule{ { - Methods: []string{"*"}, - Endpoints: []string{"api/v1/version1"}, + Methods: []string{"POST"}, + Endpoints: []string{"api/aslan/project/products"}, + }, + { + Methods: []string{"POST"}, + Endpoints: []string{"api/v1/picket/projects"}, + }, + { + Methods: []string{"POST"}, + Endpoints: []string{"api/aslan/cluster/clusters"}, + }, + { + Methods: []string{"PUT", "DELETE"}, + Endpoints: []string{"api/aslan/cluster/clusters/?*"}, + }, + { + Methods: []string{"PUT"}, + Endpoints: []string{"api/aslan/cluster/clusters/?*/disconnect"}, + }, + { + Methods: []string{"PUT"}, + Endpoints: []string{"api/aslan/cluster/clusters/?*/reconnect"}, + }, + { + Methods: []string{"POST", "PUT"}, + Endpoints: []string{"api/aslan/system/install"}, + }, + { + Methods: []string{"PUT"}, + Endpoints: []string{"api/aslan/system/install/delete"}, + }, + { + Methods: []string{"POST"}, + Endpoints: []string{"api/aslan/system/proxyManage"}, + }, + { + Methods: []string{"PUT", "DELETE"}, + Endpoints: []string{"api/aslan/system/proxyManage/?*"}, + }, + { + Methods: []string{"GET", "POST"}, + Endpoints: []string{"api/aslan/system/registry/namespaces"}, + }, + { + Methods: []string{"PUT", "DELETE"}, + Endpoints: []string{"api/aslan/system/registry/namespaces/?*"}, + }, + { + Methods: []string{"POST"}, + Endpoints: []string{"api/aslan/system/s3storage"}, + }, + { + Methods: []string{"PUT", "DELETE"}, + Endpoints: []string{"api/aslan/system/s3storage/?*"}, + }, + { + Methods: []string{"POST"}, + Endpoints: []string{"api/aslan/system/githubApp"}, + }, + { + Methods: []string{"DELETE"}, + Endpoints: []string{"api/aslan/system/githubApp/?*"}, + }, + { + Methods: []string{"POST"}, + Endpoints: []string{"api/aslan/system/jenkins/integration"}, + }, + { + Methods: []string{"PUT", "DELETE"}, + Endpoints: []string{"api/aslan/system/jenkins/integration/?*"}, + }, + { + Methods: []string{"POST"}, + Endpoints: []string{"api/aslan/system/jenkins/integration/user/connection"}, + }, + { + Methods: []string{"POST"}, + Endpoints: []string{"api/aslan/system/basicImages"}, + }, + { + Methods: []string{"PUT", "DELETE"}, + Endpoints: []string{"api/aslan/system/basicImages/?*"}, + }, + { + Methods: []string{"POST"}, + Endpoints: []string{"api/aslan/system/helm"}, + }, + { + Methods: []string{"PUT", "DELETE"}, + Endpoints: []string{"api/aslan/system/helm/?*"}, + }, + { + Methods: []string{"POST"}, + Endpoints: []string{"api/aslan/system/privateKey"}, + }, + { + Methods: []string{"PUT", "DELETE"}, + Endpoints: []string{"api/aslan/system/privateKey/?*"}, + }, + { + Methods: []string{"POST"}, + Endpoints: []string{"api/aslan/system/announcement"}, + }, + { + Methods: []string{"PUT"}, + Endpoints: []string{"api/aslan/system/announcement/update"}, + }, + { + Methods: []string{"GET"}, + Endpoints: []string{"api/aslan/system/announcement/all"}, + }, + { + Methods: []string{"DELETE"}, + Endpoints: []string{"api/aslan/system/announcement/?*"}, + }, + { + Methods: []string{"GET", "POST"}, + Endpoints: []string{"api/aslan/system/operation"}, + }, + { + Methods: []string{"PUT"}, + Endpoints: []string{"api/aslan/system/operation/?*"}, + }, + { + Methods: []string{"GET"}, + Endpoints: []string{"api/aslan/system/proxy/config"}, + }, + { + Methods: []string{"GET", "PUT", "PATCH", "DELETE"}, + Endpoints: []string{"api/v1/users/?*"}, + }, + { + Methods: []string{"POST"}, + Endpoints: []string{"api/v1/users"}, + }, + { + Methods: []string{"POST"}, + Endpoints: []string{"api/v1/public-roles"}, + }, + { + Methods: []string{"PUT", "DELETE"}, + Endpoints: []string{"api/v1/public-roles/?*"}, + }, + { + Methods: []string{"GET", "POST"}, + Endpoints: []string{"api/v1/system-roles"}, + }, + { + Methods: []string{"DELETE"}, + Endpoints: []string{"api/v1/system-roles/?*"}, + }, + { + Methods: []string{"GET", "POST"}, + Endpoints: []string{"api/v1/system-rolebindings"}, + }, + { + Methods: []string{"DELETE"}, + Endpoints: []string{"api/v1/system-rolebindings/?*"}, }, } -var publicURLs = []*policyRule{ +// actions which are allowed for project admins. +var projectAdminURLs = []*policyRule{ + { + Methods: []string{"PUT"}, + Endpoints: []string{"api/aslan/project/products"}, + }, + { + Methods: []string{"PUT", "DELETE"}, + Endpoints: []string{"api/v1/picket/projects/?*"}, + }, + { + Methods: []string{"DELETE"}, + Endpoints: []string{"api/aslan/project/products/?*"}, + }, { Methods: []string{"GET"}, - Endpoints: []string{"api/aslan/health"}, + Endpoints: []string{"api/v1/users"}, }, { Methods: []string{"POST"}, - Endpoints: []string{"api/aslan/webhook"}, + Endpoints: []string{"api/v1/users/search"}, }, { Methods: []string{"GET"}, - Endpoints: []string{"api/hub/connect"}, + Endpoints: []string{"api/v1/roles"}, }, { Methods: []string{"GET"}, - Endpoints: []string{"api/aslan/kodespace/downloadUrl"}, + Endpoints: []string{"api/v1/roles/?*"}, + }, + { + Methods: []string{"POST"}, + Endpoints: []string{"api/v1/roles"}, + }, + { + Methods: []string{"PUT", "DELETE"}, + Endpoints: []string{"api/v1/roles/?*"}, + }, + { + Methods: []string{"POST"}, + Endpoints: []string{"api/v1/roles/bulk-delete"}, + }, + { + Methods: []string{"GET"}, + Endpoints: []string{"api/v1/public-roles"}, + }, + { + Methods: []string{"GET"}, + Endpoints: []string{"api/v1/public-roles/?*"}, + }, + { + Methods: []string{"GET", "POST"}, + Endpoints: []string{"api/v1/rolebindings"}, + }, + { + Methods: []string{"GET"}, + Endpoints: []string{"api/v1/picket/rolebindings"}, + }, + { + Methods: []string{"DELETE"}, + Endpoints: []string{"api/v1/rolebindings/?*"}, + }, + { + Methods: []string{"POST"}, + Endpoints: []string{"api/v1/rolebindings/bulk-delete"}, }, } + +var adminURLs = append(systemAdminURLs, projectAdminURLs...) diff --git a/pkg/microservice/policy/core/service/bundle/opa_bundle.go b/pkg/microservice/policy/core/service/bundle/opa_bundle.go index ca22f71f9e9949a30530fc9fc510ebfedca30186..84cdf4dbe56f16328b56c355c5df61a3578f6885 100644 --- a/pkg/microservice/policy/core/service/bundle/opa_bundle.go +++ b/pkg/microservice/policy/core/service/bundle/opa_bundle.go @@ -41,24 +41,14 @@ const ( ) const ( - MethodView = "VIEW" - MethodGet = http.MethodGet - MethodPost = http.MethodPost - MethodPut = http.MethodPut - MethodPatch = http.MethodPatch - MethodDelete = http.MethodDelete - ActionCreate = "create" - ActionDelete = "delete" - ActionDeleteCollection = "deletecollection" - ActionGet = "get" - ActionList = "list" - ActionPatch = "patch" - ActionUpdate = "update" - ActionWatch = "watch" + MethodGet = http.MethodGet + MethodPost = http.MethodPost + MethodPut = http.MethodPut + MethodPatch = http.MethodPatch + MethodDelete = http.MethodDelete ) var AllMethods = []string{MethodGet, MethodPost, MethodPut, MethodPatch, MethodDelete} -var AllActions = []string{ActionCreate, ActionDelete, ActionDeleteCollection, ActionGet, ActionList, ActionPatch, ActionUpdate, ActionWatch} var cacheFS afero.Fs @@ -87,8 +77,13 @@ type rule struct { } type roleBinding struct { - User string `json:"user"` - RoleRefs roleRefs `json:"role_refs"` + UID string `json:"uid"` + Bindings bindings `json:"bindings"` +} + +type binding struct { + Namespace string `json:"namespace"` + RoleRefs roleRefs `json:"role_refs"` } type roleRef struct { @@ -164,6 +159,14 @@ func (o roles) Less(i, j int) bool { return o[i].Namespace < o[j].Namespace } +type bindings []*binding + +func (o bindings) Len() int { return len(o) } +func (o bindings) Swap(i, j int) { o[i], o[j] = o[j], o[i] } +func (o bindings) Less(i, j int) bool { + return o[i].Namespace < o[j].Namespace +} + type roleRefs []*roleRef func (o roleRefs) Len() int { return len(o) } @@ -180,62 +183,21 @@ type roleBindings []*roleBinding func (o roleBindings) Len() int { return len(o) } func (o roleBindings) Swap(i, j int) { o[i], o[j] = o[j], o[i] } func (o roleBindings) Less(i, j int) bool { - return o[i].User < o[j].User + return o[i].UID < o[j].UID } -func generateOPAResourceRoles(roles []*models.Role) *opaRoles { +func generateOPARoles(roles []*models.Role, policies []*models.Policy) *opaRoles { data := &opaRoles{} + resourceMappings := getResourceActionMappings(policies) for _, ro := range roles { opaRole := &role{Name: ro.Name, Namespace: ro.Namespace} for _, r := range ro.Rules { - if len(r.Verbs) == 1 && r.Verbs[0] == models.MethodAll { - r.Verbs = AllActions - } - for _, res := range r.Resources { - if mapping, ok := mappings[res]; !ok { - continue - } else { - for _, v := range r.Verbs { - opaRole.Rules = append(opaRole.Rules, mapping[v]...) - } - } - - } - } - - sort.Sort(opaRole.Rules) - data.Roles = append(data.Roles, opaRole) - } - - sort.Sort(data.Roles) - - return data -} - -func generateOPARoles(roles []*models.Role) *opaRoles { - data := &opaRoles{} - - for _, ro := range roles { - opaRole := &role{Name: ro.Name, Namespace: ro.Namespace} - if ro.Kind == models.KindResource { - for _, r := range ro.Rules { - if len(r.Verbs) == 1 && r.Verbs[0] == models.MethodAll { - r.Verbs = AllActions - } + if r.Kind == models.KindResource { for _, res := range r.Resources { - if mapping, ok := mappings[res]; !ok { - continue - } else { - for _, v := range r.Verbs { - opaRole.Rules = append(opaRole.Rules, mapping[v]...) - } - } - + opaRole.Rules = append(opaRole.Rules, resourceMappings.GetRules(res, r.Verbs)...) } - } - } else { - for _, r := range ro.Rules { + } else { if len(r.Verbs) == 1 && r.Verbs[0] == models.MethodAll { r.Verbs = AllMethods } @@ -245,6 +207,7 @@ func generateOPARoles(roles []*models.Role) *opaRoles { } } } + } sort.Sort(opaRole.Rules) @@ -256,22 +219,30 @@ func generateOPARoles(roles []*models.Role) *opaRoles { return data } -func generateOPARoleBindings(bindings []*models.RoleBinding) *opaRoleBindings { +func generateOPARoleBindings(rbs []*models.RoleBinding) *opaRoleBindings { data := &opaRoleBindings{} - userRoleMap := make(map[string][]*roleRef) + userRoleMap := make(map[string]map[string][]*roleRef) - for _, rb := range bindings { + for _, rb := range rbs { for _, s := range rb.Subjects { if s.Kind == models.UserKind { - userRoleMap[s.Name] = append(userRoleMap[s.Name], &roleRef{Name: rb.RoleRef.Name, Namespace: rb.RoleRef.Namespace}) + if _, ok := userRoleMap[s.UID]; !ok { + userRoleMap[s.UID] = make(map[string][]*roleRef) + } + userRoleMap[s.UID][rb.Namespace] = append(userRoleMap[s.UID][rb.Namespace], &roleRef{Name: rb.RoleRef.Name, Namespace: rb.RoleRef.Namespace}) } } } - for k, v := range userRoleMap { - sort.Sort(roleRefs(v)) - data.RoleBindings = append(data.RoleBindings, &roleBinding{User: k, RoleRefs: v}) + for u, nb := range userRoleMap { + var bindingsData []*binding + for n, b := range nb { + sort.Sort(roleRefs(b)) + bindingsData = append(bindingsData, &binding{Namespace: n, RoleRefs: b}) + } + sort.Sort(bindings(bindingsData)) + data.RoleBindings = append(data.RoleBindings, &roleBinding{UID: u, Bindings: bindingsData}) } sort.Sort(data.RoleBindings) @@ -279,46 +250,53 @@ func generateOPARoleBindings(bindings []*models.RoleBinding) *opaRoleBindings { return data } -func generateOPAExemptionURLs() *exemptionURLs { +func generateOPAExemptionURLs(policies []*models.Policy) *exemptionURLs { data := &exemptionURLs{} - for _, r := range globalURLs { + for _, r := range publicURLs { if len(r.Methods) == 1 && r.Methods[0] == models.MethodAll { r.Methods = AllMethods } for _, method := range r.Methods { for _, endpoint := range r.Endpoints { - data.Global = append(data.Global, &rule{Method: method, Endpoint: endpoint}) + data.Public = append(data.Public, &rule{Method: method, Endpoint: endpoint}) } } } - sort.Sort(data.Global) + sort.Sort(data.Public) - for _, r := range namespacedURLs { + for _, r := range systemAdminURLs { if len(r.Methods) == 1 && r.Methods[0] == models.MethodAll { r.Methods = AllMethods } for _, method := range r.Methods { for _, endpoint := range r.Endpoints { - data.Namespaced = append(data.Namespaced, &rule{Method: method, Endpoint: endpoint}) + data.Privileged = append(data.Privileged, &rule{Method: method, Endpoint: endpoint}) } } } + sort.Sort(data.Privileged) - sort.Sort(data.Namespaced) - - for _, r := range publicURLs { + resourceMappings := getResourceActionMappings(policies) + for _, resourceMappings := range resourceMappings { + for _, rs := range resourceMappings { + for _, r := range rs { + data.Registered = append(data.Registered, r) + } + } + } + for _, r := range adminURLs { if len(r.Methods) == 1 && r.Methods[0] == models.MethodAll { r.Methods = AllMethods } for _, method := range r.Methods { for _, endpoint := range r.Endpoints { - data.Public = append(data.Public, &rule{Method: method, Endpoint: endpoint}) + data.Registered = append(data.Registered, &rule{Method: method, Endpoint: endpoint}) } } } - sort.Sort(data.Public) + sort.Sort(data.Registered) return data } @@ -338,21 +316,25 @@ func GenerateOPABundle() error { log.Info("Generating OPA bundle") defer log.Info("OPA bundle is generated") - roles, err := mongodb.NewRoleColl().List() + rs, err := mongodb.NewRoleColl().List() if err != nil { log.Errorf("Failed to list roles, err: %s", err) } - bindings, err := mongodb.NewRoleBindingColl().List() + bs, err := mongodb.NewRoleBindingColl().List() if err != nil { log.Errorf("Failed to list roleBindings, err: %s", err) } + ps, err := mongodb.NewPolicyColl().List() + if err != nil { + log.Errorf("Failed to list policies, err: %s", err) + } data := &opaData{ {data: generateOPAManifest(), path: manifestPath}, {data: generateOPAPolicy(), path: policyPath}, - {data: generateOPARoles(roles), path: rolesPath}, - {data: generateOPARoleBindings(bindings), path: rolebindingsPath}, - {data: generateOPAExemptionURLs(), path: exemptionPath}, + {data: generateOPARoles(rs, ps), path: rolesPath}, + {data: generateOPARoleBindings(bs), path: rolebindingsPath}, + {data: generateOPAExemptionURLs(ps), path: exemptionPath}, } return data.save() diff --git a/pkg/microservice/policy/core/service/bundle/opa_bundle_test.go b/pkg/microservice/policy/core/service/bundle/opa_bundle_test.go index 62a5e86f07d60c5aea65cc35751fa8a3f12159c2..80c131c6760de5cd81ae1364f25afea7eec21e02 100644 --- a/pkg/microservice/policy/core/service/bundle/opa_bundle_test.go +++ b/pkg/microservice/policy/core/service/bundle/opa_bundle_test.go @@ -59,11 +59,11 @@ var testBinding1 = ` "subjects": [ { "kind": "user", - "name": "alice" + "uid": "alice" }, { "kind": "user", - "name": "bob" + "uid": "bob" } ], "roleRef": { @@ -80,7 +80,7 @@ var testBinding2 = ` "subjects": [ { "kind": "user", - "name": "alice" + "uid": "alice" } ], "roleRef": { @@ -149,7 +149,7 @@ var expectOPARoleBindings = ` { "role_bindings": [ { - "user": "alice", + "uid": "alice", "role_refs": [ { "name": "author", @@ -162,7 +162,7 @@ var expectOPARoleBindings = ` ] }, { - "user": "bob", + "uid": "bob", "role_refs": [ { "name": "superuser", @@ -193,7 +193,7 @@ var _ = Describe("Testing generate OPA roles and bindings", func() { }) It("should work as expected", func() { - data := generateOPARoles(testRoles) + data := generateOPARoles(testRoles, nil) actual, err := json.MarshalIndent(data, "", " ") Expect(err).ShouldNot(HaveOccurred()) Expect(string(actual)).To(Equal(strings.TrimSpace(expectOPARoles))) diff --git a/pkg/microservice/policy/core/service/bundle/opa_policy.go b/pkg/microservice/policy/core/service/bundle/opa_policy.go index 33af2e180401a7197cf463171a20e0c515cf87b1..8b1cd4e3c94d6b207fc0a4c02a67f683de76af59 100644 --- a/pkg/microservice/policy/core/service/bundle/opa_policy.go +++ b/pkg/microservice/policy/core/service/bundle/opa_policy.go @@ -18,8 +18,6 @@ package bundle import ( _ "embed" - - _ "github.com/koderover/zadig/pkg/util/testing" ) //go:embed rego/authz.rego diff --git a/pkg/microservice/policy/core/service/bundle/rego/authz.rego b/pkg/microservice/policy/core/service/bundle/rego/authz.rego index b3119d416e8d984e8d9d58adeac3ec34b3d5f933..b3c0997d8d46ec570770dbc44a845e6fe816df31 100644 --- a/pkg/microservice/policy/core/service/bundle/rego/authz.rego +++ b/pkg/microservice/policy/core/service/bundle/rego/authz.rego @@ -2,6 +2,36 @@ package rbac import input.attributes.request.http as http_request +# Policy rule definitions in rbac style, which is consumed by OPA server. +# you can use it to: +# 1. decide if a request is allowed by querying: rbac.allow +# 2. decide if a request is allowed and get the status code by querying: rbac.response +# 3. get all visible projects for an authenticated user by querying: rbac.user_visible_projects +# 4. get all allowed projects for a certain action(method+endpoint) for an authenticated user by querying: rbac.user_allowed_projects +# 5. check if a user is system admin by querying: rbac.user_is_admin +# 6. check if a user is project admin by querying: rbac.user_is_project_admin + +default response = { + "allowed": false, + "http_status": 403 +} + +response = r { + not is_authenticated + not url_is_public + r := { + "allowed": false, + "http_status": 401 + } +} + +response = r { + allow + r := { + "allowed": true, + } +} + # By default, deny requests. default allow = false @@ -10,24 +40,32 @@ allow { url_is_public } -# Allow all valid users to visit exempted urls. allow { + is_authenticated + access_is_granted + +} + +# Allow all valid users to visit exempted urls. +access_is_granted { url_is_exempted - claims.name != "" } # Allow admins to do anything. -allow { +access_is_granted { user_is_admin } # Allow project admins to do anything under the given project. -allow { +access_is_granted { + not url_is_privileged user_is_project_admin } # Allow the action if the user is granted permission to perform the action. -allow { +access_is_granted { + not url_is_privileged + some grant user_is_granted[grant] @@ -35,63 +73,125 @@ allow { glob.match(trim(grant.endpoint, "/"), ["/"], concat("/", input.parsed_path)) } +# Temporarily skip this endpoint, it will be fixed in 1.7.1 +access_is_granted { + concat("/", input.parsed_path) == "api/aslan/workflow/workflow" + http_request.method == "GET" + project_name == "" +} + user_is_admin { some role - allewed_roles[role] + all_roles[role] role.name == "admin" - role.namespace == "" + role.namespace == "*" } user_is_project_admin { some role - allewed_roles[role] + allowed_roles[role] - role.name == "admin" - role.namespace == projcet_name + role.name == "project-admin" + #role.namespace == project_name } +# public urls are visible for all users url_is_public { - data.exemptions.public[_].method == http_request.method - glob.match(trim(data.exemptions.public[_].endpoint, "/"), ["/"], concat("/", input.parsed_path)) + some i + data.exemptions.public[i].method == http_request.method + glob.match(trim(data.exemptions.public[i].endpoint, "/"), ["/"], concat("/", input.parsed_path)) } +# exempted urls are visible for all authenticated users url_is_exempted { - data.exemptions.global[_].method == http_request.method - glob.match(trim(data.exemptions.global[_].endpoint, "/"), ["/"], concat("/", input.parsed_path)) + not url_is_registered } -url_is_exempted { - data.exemptions.namespaced[_].method == http_request.method - glob.match(trim(data.exemptions.namespaced[_].endpoint, "/"), ["/"], concat("/", input.parsed_path)) - user_projects[_] == projcet_name +url_is_registered { + some i + data.exemptions.registered[i].method == http_request.method + glob.match(trim(data.exemptions.registered[i].endpoint, "/"), ["/"], concat("/", input.parsed_path)) } -projcet_name := pn { +# privileged urls are visible for system admins only +url_is_privileged { + some i + data.exemptions.privileged[i].method == http_request.method + glob.match(trim(data.exemptions.privileged[i].endpoint, "/"), ["/"], concat("/", input.parsed_path)) +} + +project_name := pn { pn := input.parsed_query.projectName[0] } -roles[role] { +# get all projects which are visible by current user +user_projects[project] { + some i + data.bindings.role_bindings[i].uid == claims.uid + project := data.bindings.role_bindings[i].bindings[_].namespace +} + +# get all projects which are visible by all users (the user name is "*") +user_projects[project] { + some i + data.bindings.role_bindings[i].uid == "*" + project := data.bindings.role_bindings[i].bindings[_].namespace +} + +# all projects which are allowed by current user +user_allowed_projects[project] { + some project + user_projects[project] + not user_is_admin + allow with project_name as project +} + +# if user is system admin, return all projects +user_allowed_projects[project] { + project := "*" + user_is_admin +} + +# all projects which are visible by current user +user_visible_projects[project] { + some project + user_projects[project] + not user_is_admin +} + +# if user is system admin, return all projects +user_visible_projects[project] { + project := "*" + user_is_admin +} + + +all_roles[role_ref] { some i - data.bindings.role_bindings[i].user == claims.name - role_refs := data.bindings.role_bindings[i].role_refs - role := role_refs[_] + data.bindings.role_bindings[i].uid == claims.uid + role_ref := data.bindings.role_bindings[i].bindings[j].role_refs[_] } -# only global roles and roles under the given project are allowed. -allewed_roles[role_ref] { - role_ref := roles[_] - role_ref.namespace == "" +# only roles under the given project are allowed +allowed_roles[role_ref] { + some i + data.bindings.role_bindings[i].uid == claims.uid + data.bindings.role_bindings[i].bindings[j].namespace == project_name + role_ref := data.bindings.role_bindings[i].bindings[j].role_refs[_] } -allewed_roles[role_ref] { - role_ref := roles[_] - role_ref.namespace == projcet_name +# if the proejct is visible by all users (the user name is "*"), the bound roles are also allowed +allowed_roles[role_ref] { + some i + data.bindings.role_bindings[i].uid == "*" + data.bindings.role_bindings[i].bindings[_].namespace == project_name + role_ref := data.bindings.role_bindings[i].bindings[j].role_refs[_] } user_is_granted[grant] { some role_ref - allewed_roles[role_ref] + allowed_roles[role_ref] some i data.roles.roles[i].name == role_ref.name @@ -99,18 +199,12 @@ user_is_granted[grant] { grant := data.roles.roles[i].rules[_] } -# get all projects which are visible by current user -user_projects[project] { - project := roles[_].namespace - project != "" -} - claims := payload { - # TODO: Verify the signature on the Bearer token. The certificate can be + # Verify the signature on the Bearer token. The certificate can be # hardcoded into the policy, and it could also be loaded via data or # an environment variable. Environment variables can be accessed using # the `opa.runtime()` built-in function. - # io.jwt.verify_rs256(bearer_token, certificate) + io.jwt.verify_hs256(bearer_token, secret) # This statement invokes the built-in function `io.jwt.decode` passing the # parsed bearer_token as a parameter. The `io.jwt.decode` function returns an @@ -121,9 +215,15 @@ claims := payload { # In Rego, you can pattern match values using the `=` and `:=` operators. This # example pattern matches on the result to obtain the JWT payload. [_, payload, _] := io.jwt.decode(bearer_token) + + # it is not working, don't know why + # [valid, _, payload] := io.jwt.decode_verify(bearer_token, { + # "secret": secret, + # "alg": "alg", + # }) } -bearer_token := t { +bearer_token_in_header := t { # Bearer tokens are contained inside of the HTTP Authorization header. This rule # parses the header and extracts the Bearer token value. If no Bearer token is # provided, the `bearer_token` value is undefined. @@ -131,3 +231,26 @@ bearer_token := t { startswith(v, "Bearer ") t := substring(v, count("Bearer "), -1) } + +bearer_token = t { + t := bearer_token_in_header +} + +bearer_token = t { + not bearer_token_in_header + t := input.parsed_query.token[0] +} + +is_authenticated { + claims + claims.uid != "" + claims.exp > time.now_ns()/1000000000 +} + +envs := env { + env := opa.runtime()["env"] +} + +secret := s { + s := envs["SECRET_KEY"] +} diff --git a/pkg/microservice/policy/core/service/bundle/rego/test_data/bindings/data.json b/pkg/microservice/policy/core/service/bundle/rego/test_data/bindings/data.json index 0512dd84ff2fe92b545750d03ba5f88c52b22c3c..9344d9cb1f90baa3f08b308a04fa6b4008f775b0 100644 --- a/pkg/microservice/policy/core/service/bundle/rego/test_data/bindings/data.json +++ b/pkg/microservice/policy/core/service/bundle/rego/test_data/bindings/data.json @@ -1,25 +1,81 @@ { "role_bindings": [ { - "user": "alice", - "role_refs": [ + "uid": "2e6c5200-358f-11ec-981f-de2269351a1e", + "bindings": [ { - "name": "reader1", - "namespace": "project1" + "namespace": "project1", + "role_refs": [ + { + "name": "reader1", + "namespace": "project1" + }, + { + "name": "reader2", + "namespace": "" + } + ] }, { - "name": "reader", - "namespace": "project2" + "namespace": "project2", + "role_refs": [ + { + "name": "reader", + "namespace": "project2" + }, + { + "name": "reader3", + "namespace": "project2" + } + ] + } + ] + }, + { + "uid": "*", + "bindings": [ + { + "namespace": "project3", + "role_refs": [ + { + "name": "view", + "namespace": "" + } + ] }, { - "name": "reader3", - "namespace": "project2" + "namespace": "project1", + "role_refs": [ + { + "name": "view", + "namespace": "" + } + ] + } + ] + }, + { + "uid": "bob", + "bindings": [ + { + "namespace": "project4", + "role_refs": [ + { + "name": "view", + "namespace": "" + } + ] }, { - "name": "reader2", - "namespace": "" + "namespace": "project5", + "role_refs": [ + { + "name": "view", + "namespace": "" + } + ] } ] } ] -} \ No newline at end of file +} diff --git a/pkg/microservice/policy/core/service/bundle/rego/test_data/exemptions/data.json b/pkg/microservice/policy/core/service/bundle/rego/test_data/exemptions/data.json index 866aa979773828988d7fb19f1a18b21a8d520c50..271edede6045a294bf8a0369b34cda59b5f6a3ee 100644 --- a/pkg/microservice/policy/core/service/bundle/rego/test_data/exemptions/data.json +++ b/pkg/microservice/policy/core/service/bundle/rego/test_data/exemptions/data.json @@ -16,5 +16,11 @@ "method": "POST", "endpoint": "/api/aslan/webhook" } + ], + "registered": [ + { + "method": "GET", + "endpoint": "/api/articles" + } ] } diff --git a/pkg/microservice/policy/core/service/bundle/rego/test_data/roles/data.json b/pkg/microservice/policy/core/service/bundle/rego/test_data/roles/data.json index 68ce3d2fb15fce9d2ea39f2a57fe2344d20b0584..d86936b5ebdff25d960828bcff0c99782ffeafbf 100644 --- a/pkg/microservice/policy/core/service/bundle/rego/test_data/roles/data.json +++ b/pkg/microservice/policy/core/service/bundle/rego/test_data/roles/data.json @@ -70,6 +70,16 @@ } ] }, + { + "name": "view", + "namespace": "project3", + "rules": [ + { + "method": "GET", + "endpoint": "/api/articles" + } + ] + }, { "name": "reader2", "namespace": "project1", diff --git a/pkg/microservice/policy/core/service/bundle/rego/test_input.json b/pkg/microservice/policy/core/service/bundle/rego/test_input.json index d6aad2a2669ffd0d8264c2000c9f31ef8bdb124b..9647fc86a2cdad52829194398a9c638a5fb4a4b5 100644 --- a/pkg/microservice/policy/core/service/bundle/rego/test_input.json +++ b/pkg/microservice/policy/core/service/bundle/rego/test_input.json @@ -19,7 +19,7 @@ "accept": "*/*", "accept-encoding": "gzip, deflate", "accept-language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2", - "authorization": "Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImFmMGNlZTQxOGY0NjJkNWMzMjYyNGRiY2FlN2NjM2E2MjFmMDlkMjMifQ.eyJpc3MiOiJodHRwOi8vZGV4LnRlc3QuOHNsYW4uY29tL2RleCIsInN1YiI6IkNpVXhNak0wTlRZM09EQXRaR0k0T0MwMFlqY3pMVGt3WVRrdE0yTmtNVFkyTVdZMU5EWTJFZ1ZzYjJOaGJBIiwiYXVkIjoiZXhhbXBsZS1hcHAiLCJleHAiOjE2MzM3ODQ2NTgsImlhdCI6MTYzMzY5ODI1OCwiYXRfaGFzaCI6IkhzV0trWFhucDAzZFh1aGxOc00ycUEiLCJjX2hhc2giOiJISjllRUhhMnNBTHY5elBVaERERDd3IiwiZW1haWwiOiJsb3V0ZXN0QGV4YW1wbGUuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsIm5hbWUiOiJhbGljZSJ9.cAphZs4fv_ZxTNZpIziPi4btm50eYpSvXJGrmNP7TQilGKqkaIF6oroCHsdxuBm3pwIOI8dE4nws7Eogxdtx1AH6EQ3vWv8OoIW1TpCDQit4cX5MsLnEyzuS3r30QQXxi1x2veabsfQungudPivFr4_1xQcjho9G1Y3AGxEDU9zA0-r3U7g9M3lrcF4domaF1xzR1FT2TP0V2QVPCxOocPUl65P-Oxu7oRxpnv44d5ORvAuTuU5IrulZMs5NyaY145qzpBZSTU_x3xQAl4BE35XYh_w1wBqqSEpNbAum9VlpX9kaNrHc8B-jHw2cBRuEIyJU6CPC4g1wcYlxoCrCDg", + "authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiYWRtaW4xIiwiZW1haWwiOiJhZG1pbjFAa29kZXJvdmVyLmNvbSIsInVpZCI6IjJlNmM1MjAwLTM1OGYtMTFlYy05ODFmLWRlMjI2OTM1MWExZSIsImZlZGVyYXRlZF9jbGFpbXMiOnsiY29ubmVjdG9yX2lkIjoiIiwidXNlcl9pZCI6IiJ9LCJhdWQiOiJ6YWRpZyIsImV4cCI6MTYzNTI1MTQxOH0.7GAndkOICyk7QucBaUiGmd7ZJstWJfoNDw5JKZjz4TY", "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:92.0) Gecko/20100101 Firefox/92.0", "x-forwarded-proto": "http", "x-request-id": "14404686-7a28-48a6-9be6-bdd6e119f81a" diff --git a/pkg/microservice/policy/core/service/bundle/resource_endpoint_mapping.go b/pkg/microservice/policy/core/service/bundle/resource_endpoint_mapping.go index 2b328dd4623a676e163c07326f977b526ed42225..def928aa01bc96d8e9c78b2aa01cc4bf4e6f9940 100644 --- a/pkg/microservice/policy/core/service/bundle/resource_endpoint_mapping.go +++ b/pkg/microservice/policy/core/service/bundle/resource_endpoint_mapping.go @@ -1,16 +1,62 @@ package bundle -var mappings = map[string]map[string][]*rule{ - "Workflow": workflowMapping, +import ( + "k8s.io/apimachinery/pkg/util/sets" + + "github.com/koderover/zadig/pkg/microservice/policy/core/repository/models" +) + +type resourceActionMappings map[string]map[string][]*rule + +func (m resourceActionMappings) GetRules(resource string, actions []string) []*rule { + mappings, ok := m[resource] + if !ok { + return nil + } + + all := false + if len(actions) == 1 && actions[0] == models.MethodAll { + all = true + } + actionSet := sets.NewString(actions...) + var res []*rule + for action, r := range mappings { + if all || actionSet.Has(action) { + res = append(res, r...) + } + } + + return res } -var workflowMapping = map[string][]*rule{ - ActionCreate: { - {Method: MethodPost, Endpoint: "/api/aslan/workflow/workflow"}, - {Method: MethodPost, Endpoint: "/api/aslan/workflow/v2/pipelines"}, - }, - ActionDelete: { - {Method: MethodPost, Endpoint: "/api/aslan/workflow/workflow/?*"}, - {Method: MethodPost, Endpoint: "/api/aslan/workflow/v2/pipelines/?*"}, - }, +//var resourceActionMappings = map[string]map[string][]*rule{ +// "Workflow": workflowMapping, +//} +// +//var workflowMapping = map[string][]*rule{ +// ActionCreate: { +// {Method: MethodPost, Endpoint: "/api/aslan/workflow/workflow"}, +// {Method: MethodPost, Endpoint: "/api/aslan/workflow/v2/pipelines"}, +// }, +// ActionDelete: { +// {Method: MethodPost, Endpoint: "/api/aslan/workflow/workflow/?*"}, +// {Method: MethodPost, Endpoint: "/api/aslan/workflow/v2/pipelines/?*"}, +// }, +//} + +func getResourceActionMappings(policies []*models.Policy) resourceActionMappings { + data := make(resourceActionMappings) + for _, p := range policies { + if _, ok := data[p.Resource]; !ok { + data[p.Resource] = make(map[string][]*rule) + } + + for _, r := range p.Rules { + for _, ar := range r.Rules { + data[p.Resource][r.Action] = append(data[p.Resource][r.Action], &rule{Method: ar.Method, Endpoint: ar.Endpoint}) + } + } + } + + return data } diff --git a/pkg/microservice/policy/core/service/policy_registration.go b/pkg/microservice/policy/core/service/policy_registration.go new file mode 100644 index 0000000000000000000000000000000000000000..f940b1154307f050e148f78822e1c2c04ad4dec1 --- /dev/null +++ b/pkg/microservice/policy/core/service/policy_registration.go @@ -0,0 +1,89 @@ +package service + +import ( + "go.uber.org/zap" + + "github.com/koderover/zadig/pkg/microservice/policy/core/repository/models" + "github.com/koderover/zadig/pkg/microservice/policy/core/repository/mongodb" +) + +type Policy struct { + Resource string `json:"resource"` + Alias string `json:"alias"` + Description string `json:"description"` + Rules []*PolicyRule `json:"rules"` +} + +type PolicyRule struct { + Action string `json:"action"` + Alias string `json:"alias"` + Description string `json:"description"` + Rules []*ActionRule `json:"rules"` +} + +type ActionRule struct { + Method string `json:"method"` + Endpoint string `json:"endpoint"` +} + +type PolicyDefinition struct { + Resource string `json:"resource"` + Alias string `json:"alias"` + Description string `json:"description"` + Rules []*PolicyRuleDefinition `json:"rules"` +} + +type PolicyRuleDefinition struct { + Action string `json:"action"` + Alias string `json:"alias"` + Description string `json:"description"` +} + +func CreateOrUpdatePolicyRegistration(p *Policy, _ *zap.SugaredLogger) error { + obj := &models.Policy{ + Resource: p.Resource, + Alias: p.Alias, + Description: p.Description, + } + + for _, r := range p.Rules { + rule := &models.PolicyRule{ + Action: r.Action, + Alias: r.Alias, + Description: r.Description, + } + for _, ar := range r.Rules { + rule.Rules = append(rule.Rules, &models.ActionRule{Method: ar.Method, Endpoint: ar.Endpoint}) + } + obj.Rules = append(obj.Rules, rule) + } + + return mongodb.NewPolicyColl().UpdateOrCreate(obj) +} + +func GetPolicyRegistrationDefinitions(_ *zap.SugaredLogger) ([]*PolicyDefinition, error) { + policies, err := mongodb.NewPolicyColl().List() + if err != nil { + return nil, err + } + + var res []*PolicyDefinition + for _, p := range policies { + pd := &PolicyDefinition{ + Resource: p.Resource, + Alias: p.Alias, + Description: p.Description, + } + for _, r := range p.Rules { + pd.Rules = append(pd.Rules, &PolicyRuleDefinition{ + Action: r.Action, + Alias: r.Alias, + Description: r.Description, + }) + } + + res = append(res, pd) + } + + return res, nil +} diff --git a/pkg/microservice/policy/core/service/role.go b/pkg/microservice/policy/core/service/role.go index 2e330ebe4df7ddaf610215087cca58cbc4e41d6e..c8179e6259d604683832d52a5406fe01f3a6d9af 100644 --- a/pkg/microservice/policy/core/service/role.go +++ b/pkg/microservice/policy/core/service/role.go @@ -17,20 +17,24 @@ limitations under the License. package service import ( + "fmt" + "go.uber.org/zap" "github.com/koderover/zadig/pkg/microservice/policy/core/repository/models" "github.com/koderover/zadig/pkg/microservice/policy/core/repository/mongodb" + "github.com/koderover/zadig/pkg/setting" ) type Role struct { - Name string `json:"name"` - Rules []*PolicyRule `json:"rules"` + Name string `json:"name"` + Rules []*Rule `json:"rules,omitempty"` } -type PolicyRule struct { +type Rule struct { Verbs []string `json:"verbs"` Resources []string `json:"resources"` + Kind string `json:"kind"` } func CreateRole(ns string, role *Role, _ *zap.SugaredLogger) error { @@ -40,11 +44,115 @@ func CreateRole(ns string, role *Role, _ *zap.SugaredLogger) error { } for _, r := range role.Rules { - obj.Rules = append(obj.Rules, &models.PolicyRule{ + obj.Rules = append(obj.Rules, &models.Rule{ Verbs: r.Verbs, + Kind: r.Kind, Resources: r.Resources, }) } return mongodb.NewRoleColl().Create(obj) } + +func UpdateRole(ns string, role *Role, _ *zap.SugaredLogger) error { + obj := &models.Role{ + Name: role.Name, + Namespace: ns, + } + + for _, r := range role.Rules { + obj.Rules = append(obj.Rules, &models.Rule{ + Verbs: r.Verbs, + Kind: r.Kind, + Resources: r.Resources, + }) + } + return mongodb.NewRoleColl().UpdateRole(obj) +} + +func UpdateOrCreateRole(ns string, role *Role, _ *zap.SugaredLogger) error { + obj := &models.Role{ + Name: role.Name, + Namespace: ns, + } + + for _, r := range role.Rules { + obj.Rules = append(obj.Rules, &models.Rule{ + Verbs: r.Verbs, + Kind: r.Kind, + Resources: r.Resources, + }) + } + return mongodb.NewRoleColl().UpdateOrCreate(obj) +} + +func ListRoles(projectName string, _ *zap.SugaredLogger) ([]*Role, error) { + var roles []*Role + projectRoles, err := mongodb.NewRoleColl().ListBy(projectName) + if err != nil { + return nil, err + } + for _, v := range projectRoles { + // frontend doesn't need to see contributor role + if v.Name == string(setting.Contributor) { + continue + } + roles = append(roles, &Role{ + Name: v.Name, + }) + } + return roles, nil +} + +func GetRole(ns, name string, _ *zap.SugaredLogger) (*Role, error) { + r, found, err := mongodb.NewRoleColl().Get(ns, name) + if err != nil { + return nil, err + } else if !found { + return nil, fmt.Errorf("role %s not found", name) + } + + res := &Role{ + Name: r.Name, + } + for _, ru := range r.Rules { + res.Rules = append(res.Rules, &Rule{ + Verbs: ru.Verbs, + Kind: ru.Kind, + Resources: ru.Resources, + }) + } + + return res, nil +} + +func DeleteRole(name string, projectName string, logger *zap.SugaredLogger) error { + err := mongodb.NewRoleColl().Delete(name, projectName) + if err != nil { + logger.Errorf("Failed to delete role %s in project %s, err: %s", name, projectName, err) + return err + } + + return mongodb.NewRoleBindingColl().DeleteByRole(name, projectName) +} + +func DeleteRoles(names []string, projectName string, logger *zap.SugaredLogger) error { + if len(names) == 0 { + return nil + } + if projectName == "" { + return fmt.Errorf("projectName is empty") + } + + if names[0] == "*" { + names = []string{} + } + + err := mongodb.NewRoleColl().DeleteMany(names, projectName) + if err != nil { + logger.Errorf("Failed to delete roles %s in project %s, err: %s", names, projectName, err) + return err + } + + return mongodb.NewRoleBindingColl().DeleteByRoles(names, projectName) +} diff --git a/pkg/microservice/policy/core/service/role_binding.go b/pkg/microservice/policy/core/service/role_binding.go index 8300729c59e44164d10df0d2ee64ddc46a5c9f6c..44606ea1098c1c1855070f2418733dd082df112c 100644 --- a/pkg/microservice/policy/core/service/role_binding.go +++ b/pkg/microservice/policy/core/service/role_binding.go @@ -27,39 +27,124 @@ import ( type RoleBinding struct { Name string `json:"name"` - User string `json:"user"` + UID string `json:"uid"` Role string `json:"role"` - Global bool `json:"global"` + Public bool `json:"public"` } -func CreateRoleBinding(ns string, rb *RoleBinding, logger *zap.SugaredLogger) error { - if ns == "" { - logger.Errorf("Namespace is empty") - return fmt.Errorf("empty namespace") +const SystemScope = "*" + +func CreateRoleBindings(ns string, rbs []*RoleBinding, logger *zap.SugaredLogger) error { + var objs []*models.RoleBinding + for _, rb := range rbs { + obj, err := createRoleBindingObject(ns, rb, logger) + if err != nil { + return err + } + + objs = append(objs, obj) + } + + return mongodb.NewRoleBindingColl().BulkCreate(objs) +} + +func CreateOrUpdateSystemRoleBinding(ns string, rb *RoleBinding, logger *zap.SugaredLogger) error { + + obj, err := createRoleBindingObject(ns, rb, logger) + if err != nil { + return err + } + return mongodb.NewRoleBindingColl().UpdateOrCreate(obj) +} + +func UpdateOrCreateRoleBinding(ns string, rb *RoleBinding, logger *zap.SugaredLogger) error { + obj, err := createRoleBindingObject(ns, rb, logger) + if err != nil { + return err + } + return mongodb.NewRoleBindingColl().UpdateOrCreate(obj) +} + +func ListRoleBindings(ns, uid string, _ *zap.SugaredLogger) ([]*RoleBinding, error) { + var roleBindings []*RoleBinding + modelRoleBindings, err := mongodb.NewRoleBindingColl().ListBy(ns, uid) + if err != nil { + return nil, err + } + + for _, v := range modelRoleBindings { + roleBindings = append(roleBindings, &RoleBinding{ + Name: v.Name, + Role: v.RoleRef.Name, + UID: v.Subjects[0].UID, + Public: v.RoleRef.Namespace == "", + }) + } + + return roleBindings, nil +} + +func ListRoleBindingsByRole(ns, roleName string, publicRole bool, _ *zap.SugaredLogger) ([]*RoleBinding, error) { + var roleBindings []*RoleBinding + + roleNamespace := ns + if publicRole { + roleNamespace = "" + } + modelRoleBindings, err := mongodb.NewRoleBindingColl().List(&mongodb.ListOptions{RoleName: roleName, RoleNamespace: roleNamespace}) + if err != nil { + return nil, err } + for _, v := range modelRoleBindings { + roleBindings = append(roleBindings, &RoleBinding{ + Name: v.Name, + Role: v.RoleRef.Name, + UID: v.Subjects[0].UID, + Public: v.RoleRef.Namespace == "", + }) + } + + return roleBindings, nil +} + +func DeleteRoleBinding(name string, projectName string, _ *zap.SugaredLogger) error { + return mongodb.NewRoleBindingColl().Delete(name, projectName) +} + +func DeleteRoleBindings(names []string, projectName string, _ *zap.SugaredLogger) error { + if len(names) == 0 { + return nil + } + + if names[0] == "*" { + names = []string{} + } + + return mongodb.NewRoleBindingColl().DeleteMany(names, projectName) +} + +func createRoleBindingObject(ns string, rb *RoleBinding, logger *zap.SugaredLogger) (*models.RoleBinding, error) { nsRole := ns - if rb.Global { + if rb.Public { nsRole = "" } role, found, err := mongodb.NewRoleColl().Get(nsRole, rb.Role) if err != nil { logger.Errorf("Failed to get role %s in namespace %s, err: %s", rb.Role, nsRole, err) - return err + return nil, err } else if !found { logger.Errorf("Role %s is not found in namespace %s", rb.Role, nsRole) - return fmt.Errorf("role %s not found", rb.Role) + return nil, fmt.Errorf("role %s not found", rb.Role) } - obj := &models.RoleBinding{ + return &models.RoleBinding{ Name: rb.Name, Namespace: ns, - Subjects: []*models.Subject{{Kind: models.UserKind, Name: rb.User}}, + Subjects: []*models.Subject{{Kind: models.UserKind, UID: rb.UID}}, RoleRef: &models.RoleRef{ Name: role.Name, Namespace: role.Namespace, }, - } - - return mongodb.NewRoleBindingColl().Create(obj) + }, nil } diff --git a/pkg/microservice/policy/server/rest/router.go b/pkg/microservice/policy/server/rest/router.go index 2115e654f22c2d7327b3e3e99f71697a7c53250c..d9fb530c969990ddb861607c44d41575fdd25106 100644 --- a/pkg/microservice/policy/server/rest/router.go +++ b/pkg/microservice/policy/server/rest/router.go @@ -23,10 +23,10 @@ import ( ) func (s *engine) injectRouterGroup(router *gin.RouterGroup) { - for name, r := range map[string]injector{ - "/api/v1": new(handler.Router), + for _, r := range []injector{ + new(handler.Router), } { - r.Inject(router.Group(name)) + r.Inject(router.Group("/api/v1")) } } diff --git a/pkg/microservice/reaper/core/service/client/dockerfile.go b/pkg/microservice/reaper/core/service/client/dockerfile.go index 299d6b879355abdbd759932bfb0f3af6e4159639..211f5edb70731cf96f841a3d830cc28841d8e77b 100644 --- a/pkg/microservice/reaper/core/service/client/dockerfile.go +++ b/pkg/microservice/reaper/core/service/client/dockerfile.go @@ -8,7 +8,6 @@ import ( "github.com/pkg/errors" - "github.com/koderover/zadig/pkg/setting" "github.com/koderover/zadig/pkg/tool/log" ) @@ -28,7 +27,6 @@ func (c *Client) GetDockerfile(id string) (*Dockerfile, error) { log.Errorf("new http request error: %v", err) return nil, err } - request.Header.Set(setting.AuthorizationHeader, fmt.Sprintf("%s %s", setting.RootAPIKey, c.Token)) // No auth required var ret *http.Response if ret, err = c.Conn.Do(request); err == nil { diff --git a/pkg/microservice/systemconfig/config/config.go b/pkg/microservice/systemconfig/config/config.go new file mode 100644 index 0000000000000000000000000000000000000000..2430e9b9626ea047dc468b57f3a42aca2f41ff18 --- /dev/null +++ b/pkg/microservice/systemconfig/config/config.go @@ -0,0 +1,24 @@ +package config + +import ( + "github.com/spf13/viper" + + _ "github.com/koderover/zadig/pkg/config" + configbase "github.com/koderover/zadig/pkg/config" +) + +func MysqlDexDB() string { + return viper.GetString(ENVMysqlDexDB) +} + +func Features() string { + return viper.GetString(FeatureFlag) +} + +func MongoURI() string { + return configbase.MongoURI() +} + +func MongoDatabase() string { + return configbase.MongoDatabase() +} diff --git a/pkg/microservice/systemconfig/config/consts.go b/pkg/microservice/systemconfig/config/consts.go new file mode 100644 index 0000000000000000000000000000000000000000..27f698e5976cc3e07efc5ac6363603bc45bb24f1 --- /dev/null +++ b/pkg/microservice/systemconfig/config/consts.go @@ -0,0 +1,6 @@ +package config + +const ( + ENVMysqlDexDB = "MYSQL_DEX_DB" + FeatureFlag = "feature-gates" +) diff --git a/pkg/microservice/systemconfig/core/codehost/handler/codehost.go b/pkg/microservice/systemconfig/core/codehost/handler/codehost.go new file mode 100644 index 0000000000000000000000000000000000000000..2364b5a0af2a9bb38960a822cc3faac640f77f34 --- /dev/null +++ b/pkg/microservice/systemconfig/core/codehost/handler/codehost.go @@ -0,0 +1,219 @@ +package handler + +import ( + "context" + "fmt" + "net/http" + "net/url" + "strconv" + "strings" + + "github.com/gin-gonic/gin" + "golang.org/x/oauth2" + + "github.com/koderover/zadig/pkg/microservice/systemconfig/core/codehost/repository/models" + "github.com/koderover/zadig/pkg/microservice/systemconfig/core/codehost/service" + internalhandler "github.com/koderover/zadig/pkg/shared/handler" +) + +func CreateCodeHost(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + rep := new(models.CodeHost) + if err := c.ShouldBindJSON(rep); err != nil { + ctx.Err = err + return + } + ctx.Resp, ctx.Err = service.CreateCodeHost(rep, ctx.Logger) +} + +func ListCodeHost(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + ctx.Resp, ctx.Err = service.List(c.Query("address"), c.Query("owner"), c.Query("source"), ctx.Logger) +} + +func DeleteCodeHost(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + idParam := c.Param("id") + id, err := strconv.Atoi(idParam) + if err != nil { + ctx.Err = err + return + } + ctx.Err = service.DeleteCodeHost(id, ctx.Logger) +} + +func GetCodeHost(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + idParam := c.Param("id") + id, err := strconv.Atoi(idParam) + if err != nil { + ctx.Err = err + return + } + ctx.Resp, ctx.Err = service.GetCodeHost(id, ctx.Logger) +} + +func AuthCodeHost(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + provider := c.Query("provider") + redirect := c.Query("redirect") + redirectHost, err := url.Parse(redirect) + if err != nil { + ctx.Err = err + return + } + id := c.Param("id") + idInt, err := strconv.Atoi(id) + if err != nil { + ctx.Err = err + return + } + authStateString := fmt.Sprintf("%s%s%s%s%s", redirect, "&codeHostId=", id, "&provider=", provider) + codeHost, err := service.GetCodeHost(idInt, ctx.Logger) + if err != nil { + ctx.Err = err + return + } + callBackUrl := fmt.Sprintf("%s://%s%s", redirectHost.Scheme, redirectHost.Host, "/api/directory/codehosts/callback") + + var authUrl string + var tokenUrl string + var scopes []string + if provider == "gitlab" { + scopes = []string{"api", "read_user"} + authUrl = codeHost.Address + "/oauth/authorize" + tokenUrl = codeHost.Address + "/oauth/token" + } else if provider == "github" { + scopes = []string{"repo", "user"} + authUrl = codeHost.Address + "/login/oauth/authorize" + tokenUrl = codeHost.Address + "/login/oauth/access_token" + } + authConfig := &oauth2.Config{ + ClientID: codeHost.ApplicationId, + ClientSecret: codeHost.ClientSecret, + RedirectURL: callBackUrl, + Endpoint: oauth2.Endpoint{ + AuthURL: authUrl, + TokenURL: tokenUrl, + }, + Scopes: scopes, + } + redirectURL := authConfig.AuthCodeURL(authStateString) + c.Redirect(http.StatusFound, redirectURL) +} + +func Callback(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + state := c.Query("state") + urlArray := strings.Split(state, "&codeHostId=") + frontEndUrl := urlArray[0] + if strings.Contains(frontEndUrl, "errCode") { + frontEndUrl = strings.Split(frontEndUrl, "?errCode")[0] + } + + gitlabError := c.Query("error") + if gitlabError != "" { + ctx.Logger.Warnf("code_host_get_call_back_gitlab user denied err: %s", gitlabError) + url := fmt.Sprintf("%s%s%s", frontEndUrl, "?", "&errMessage=access_denied") + c.Redirect(http.StatusFound, url) + return + } + stateURL, err := url.Parse(state) + if err != nil { + url := fmt.Sprintf("%s%s%s", frontEndUrl, "?", "&errMessage=failed_to_parse_redirect_url") + http.Redirect(c.Writer, c.Request, url, http.StatusFound) + return + } + codeHostArray := strings.Split(urlArray[1], "&provider=") + codeHostID, err := strconv.Atoi(codeHostArray[0]) + if err != nil { + ctx.Logger.Errorf("code_host_get_call_back_gitlab codeHostID convert err : %s", err) + url := fmt.Sprintf("%s%s%s", frontEndUrl, "?", "&errMessage=codeHostID convert failed") + c.Redirect(http.StatusFound, url) + return + } + code := c.Query("code") + iCodehost, err := service.GetCodeHost(codeHostID, ctx.Logger) + if err != nil { + ctx.Logger.Errorf("code_host_get_call_back_gitlab GetCodeHostByID err: %s", err) + url := fmt.Sprintf("%s%s%s", frontEndUrl, "?", "&errMessage=get codehost failed") + c.Redirect(http.StatusFound, url) + return + } + + callBackUrl := fmt.Sprintf("%s://%s%s", stateURL.Scheme, stateURL.Host, "/api/directory/codehosts/callback") + authConfig := &oauth2.Config{ + ClientID: iCodehost.ApplicationId, + ClientSecret: iCodehost.ClientSecret, + RedirectURL: callBackUrl, + //RedirectURL: "http://localhost:34001/directory/codehosts/callback", + } + if codeHostArray[1] == "gitlab" { + authConfig.Scopes = []string{"api", "read_user"} + authConfig.Endpoint = oauth2.Endpoint{ + AuthURL: fmt.Sprintf("%s%s", iCodehost.Address, "/oauth/authorize"), + TokenURL: fmt.Sprintf("%s%s", iCodehost.Address, "/oauth/token"), + } + } else if codeHostArray[1] == "github" { + authConfig.Scopes = []string{"repo", "user"} + authConfig.Endpoint = oauth2.Endpoint{ + AuthURL: fmt.Sprintf("%s%s", iCodehost.Address, "/login/oauth/authorize"), + TokenURL: fmt.Sprintf("%s%s", iCodehost.Address, "/login/oauth/access_token"), + } + } + dc := http.DefaultClient + ctxx := context.WithValue(context.Background(), oauth2.HTTPClient, dc) + token, err := authConfig.Exchange(ctxx, code) + if err != nil { + ctx.Logger.Errorf("code_host_get_call_back_gitlab Exchange err: %s", err) + url := fmt.Sprintf("%s%s%s", frontEndUrl, "?", "&errMessage=exchange failed") + c.Redirect(http.StatusFound, url) + return + } + + iCodehost.AccessToken = token.AccessToken + iCodehost.RefreshToken = token.RefreshToken + ctx.Logger.Infof("%+v", iCodehost) + _, err = service.UpdateCodeHostByToken(iCodehost, ctx.Logger) + if err != nil { + ctx.Logger.Errorf("UpdateCodeHostByToken err: %s", err) + url := fmt.Sprintf("%s%s%s", frontEndUrl, "?", "&errMessage=update codehost failed") + c.Redirect(http.StatusFound, url) + return + } + + //redirect to front end + redirectURL := "" + if strings.Contains(frontEndUrl, "?succeed") { + redirectURL = fmt.Sprintf("%s%s", strings.Split(frontEndUrl, "?succeed")[0], "?succeed=true") + } else { + redirectURL = fmt.Sprintf("%s%s", frontEndUrl, "?succeed=true") + } + c.Redirect(http.StatusFound, redirectURL) + +} + +func UpdateCodeHost(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + idParam := c.Param("id") + id, err := strconv.Atoi(idParam) + if err != nil { + ctx.Err = err + return + } + req := &models.CodeHost{} + if err := c.ShouldBindJSON(req); err != nil { + ctx.Err = err + return + } + req.ID = id + ctx.Resp, ctx.Err = service.UpdateCodeHost(req, ctx.Logger) +} diff --git a/pkg/microservice/systemconfig/core/codehost/handler/router.go b/pkg/microservice/systemconfig/core/codehost/handler/router.go new file mode 100644 index 0000000000000000000000000000000000000000..ddfff52a51555fb5666b737aeb27a0405a916b5e --- /dev/null +++ b/pkg/microservice/systemconfig/core/codehost/handler/router.go @@ -0,0 +1,20 @@ +package handler + +import ( + "github.com/gin-gonic/gin" +) + +type Router struct{} + +func (*Router) Inject(router *gin.RouterGroup) { + codehost := router.Group("codehosts") + { + codehost.GET("/callback", Callback) + codehost.GET("", ListCodeHost) + codehost.DELETE("/:id", DeleteCodeHost) + codehost.POST("", CreateCodeHost) + codehost.PATCH("/:id", UpdateCodeHost) + codehost.GET("/:id", GetCodeHost) + codehost.GET("/:id/auth", AuthCodeHost) + } +} diff --git a/pkg/microservice/systemconfig/core/codehost/repository/models/codehost.go b/pkg/microservice/systemconfig/core/codehost/repository/models/codehost.go new file mode 100644 index 0000000000000000000000000000000000000000..bbbed219daae5dd5a53ae45dfa32eeda03dc4a32 --- /dev/null +++ b/pkg/microservice/systemconfig/core/codehost/repository/models/codehost.go @@ -0,0 +1,23 @@ +package models + +type CodeHost struct { + ID int `bson:"id" json:"id"` + Type string `bson:"type" json:"type"` + Address string `bson:"address" json:"address"` + IsReady string `bson:"is_ready" json:"ready"` + AccessToken string `bson:"access_token" json:"accessToken"` + RefreshToken string `bson:"refresh_token" json:"refreshToken"` + Namespace string `bson:"namespace" json:"namespace"` + ApplicationId string `bson:"application_id" json:"applicationId"` + Region string `bson:"region" json:"region,omitempty"` + Username string `bson:"username" json:"username,omitempty"` + Password string `bson:"password" json:"password,omitempty"` + ClientSecret string `bson:"client_secret" json:"clientSecret"` + CreatedAt int64 `bson:"created_at" json:"created_at"` + UpdatedAt int64 `bson:"updated_at" json:"updated_at"` + DeletedAt int64 `bson:"deleted_at" json:"deleted_at"` +} + +func (CodeHost) TableName() string { + return "code_host" +} diff --git a/pkg/microservice/systemconfig/core/codehost/repository/mongodb/codehost.go b/pkg/microservice/systemconfig/core/codehost/repository/mongodb/codehost.go new file mode 100644 index 0000000000000000000000000000000000000000..5287ecf6d9853c496e49bb410fec59f2ec4fdbef --- /dev/null +++ b/pkg/microservice/systemconfig/core/codehost/repository/mongodb/codehost.go @@ -0,0 +1,154 @@ +package mongodb + +import ( + "context" + "time" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + + "github.com/koderover/zadig/pkg/microservice/systemconfig/config" + "github.com/koderover/zadig/pkg/microservice/systemconfig/core/codehost/repository/models" + "github.com/koderover/zadig/pkg/tool/log" + mongotool "github.com/koderover/zadig/pkg/tool/mongo" +) + +type CodehostColl struct { + *mongo.Collection + + coll string +} + +type ListArgs struct { + Owner string + Address string + Source string +} + +func NewCodehostColl() *CodehostColl { + name := models.CodeHost{}.TableName() + coll := &CodehostColl{Collection: mongotool.Database(config.MongoDatabase()).Collection(name), coll: name} + + return coll +} + +func (c *CodehostColl) GetCollectionName() string { + return c.coll +} +func (c *CodehostColl) EnsureIndex(ctx context.Context) error { + return nil +} + +func (c *CodehostColl) AddCodeHost(iCodeHost *models.CodeHost) (*models.CodeHost, error) { + + _, err := c.Collection.InsertOne(context.TODO(), iCodeHost) + if err != nil { + log.Error("repository AddCodeHost err : %v", err) + return nil, err + } + return iCodeHost, nil +} + +func (c *CodehostColl) DeleteCodeHost() error { + query := bson.M{"deleted_at": 0} + change := bson.M{"$set": bson.M{ + "deleted_at": time.Now().Unix(), + }} + + _, err := c.Collection.UpdateOne(context.TODO(), query, change) + if err != nil { + log.Error("repository DeleteCodeHostByID err : %v", err) + return err + } + return nil +} + +func (c *CodehostColl) GetCodeHostByID(ID int) (*models.CodeHost, error) { + + codehost := new(models.CodeHost) + query := bson.M{"id": ID, "deleted_at": 0} + if err := c.Collection.FindOne(context.TODO(), query).Decode(codehost); err != nil { + return nil, err + } + return codehost, nil +} + +func (c *CodehostColl) List(args *ListArgs) ([]*models.CodeHost, error) { + codeHosts := make([]*models.CodeHost, 0) + query := bson.M{"deleted_at": 0} + if args.Address != "" { + query["address"] = args.Address + } + if args.Owner != "" { + query["namespace"] = args.Owner + } + if args.Source != "" { + query["type"] = args.Source + } + + cursor, err := c.Collection.Find(context.TODO(), query) + if err != nil { + return nil, err + } + err = cursor.All(context.TODO(), &codeHosts) + if err != nil { + return nil, err + } + return codeHosts, nil +} + +func (c *CodehostColl) CodeHostList() ([]*models.CodeHost, error) { + codeHosts := make([]*models.CodeHost, 0) + + cursor, err := c.Collection.Find(context.TODO(), bson.M{}) + if err != nil { + return nil, err + } + err = cursor.All(context.TODO(), &codeHosts) + if err != nil { + return nil, err + } + return codeHosts, nil +} + +func (c *CodehostColl) DeleteCodeHostByID(ID int) error { + query := bson.M{"id": ID, "deleted_at": 0} + change := bson.M{"$set": bson.M{ + "deleted_at": time.Now().Unix(), + }} + _, err := c.Collection.UpdateOne(context.TODO(), query, change) + if err != nil { + log.Errorf("repository update fail,err:%s", err) + return err + } + return nil +} + +func (c *CodehostColl) UpdateCodeHost(host *models.CodeHost) (*models.CodeHost, error) { + query := bson.M{"id": host.ID, "deleted_at": 0} + change := bson.M{"$set": bson.M{ + "type": host.Type, + "address": host.Address, + "namespace": host.Namespace, + "application_id": host.ApplicationId, + "client_secret": host.ClientSecret, + "region": host.Region, + "username": host.Username, + "password": host.Password, + "updated_at": time.Now().Unix(), + }} + _, err := c.Collection.UpdateOne(context.TODO(), query, change) + return host, err +} + +func (c *CodehostColl) UpdateCodeHostByToken(host *models.CodeHost) (*models.CodeHost, error) { + query := bson.M{"id": host.ID, "deleted_at": 0} + change := bson.M{"$set": bson.M{ + "is_ready": "2", + "access_token": host.AccessToken, + "updated_at": time.Now().Unix(), + "refresh_token": host.RefreshToken, + }} + _, err := c.Collection.UpdateOne(context.TODO(), query, change) + return host, err +} diff --git a/pkg/microservice/systemconfig/core/codehost/service/codehost.go b/pkg/microservice/systemconfig/core/codehost/service/codehost.go new file mode 100644 index 0000000000000000000000000000000000000000..864ddda17cb2e7a3696ad8df01206e3be79b4993 --- /dev/null +++ b/pkg/microservice/systemconfig/core/codehost/service/codehost.go @@ -0,0 +1,55 @@ +package service + +import ( + "encoding/base64" + "fmt" + "time" + + "go.uber.org/zap" + + "github.com/koderover/zadig/pkg/microservice/systemconfig/core/codehost/repository/models" + "github.com/koderover/zadig/pkg/microservice/systemconfig/core/codehost/repository/mongodb" +) + +func CreateCodeHost(codehost *models.CodeHost, _ *zap.SugaredLogger) (*models.CodeHost, error) { + if codehost.Type == "codehub" { + codehost.IsReady = "2" + } + if codehost.Type == "gerrit" { + codehost.IsReady = "2" + codehost.AccessToken = base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", codehost.Username, codehost.Password))) + } + codehost.CreatedAt = time.Now().Unix() + codehost.UpdatedAt = time.Now().Unix() + + list, err := mongodb.NewCodehostColl().CodeHostList() + if err != nil { + return nil, err + } + codehost.ID = len(list) + 1 + return mongodb.NewCodehostColl().AddCodeHost(codehost) +} + +func List(address, owner, source string, _ *zap.SugaredLogger) ([]*models.CodeHost, error) { + return mongodb.NewCodehostColl().List(&mongodb.ListArgs{ + Address: address, + Owner: owner, + Source: source, + }) +} + +func DeleteCodeHost(id int, _ *zap.SugaredLogger) error { + return mongodb.NewCodehostColl().DeleteCodeHostByID(id) +} + +func UpdateCodeHost(host *models.CodeHost, _ *zap.SugaredLogger) (*models.CodeHost, error) { + return mongodb.NewCodehostColl().UpdateCodeHost(host) +} + +func UpdateCodeHostByToken(host *models.CodeHost, _ *zap.SugaredLogger) (*models.CodeHost, error) { + return mongodb.NewCodehostColl().UpdateCodeHostByToken(host) +} + +func GetCodeHost(id int, _ *zap.SugaredLogger) (*models.CodeHost, error) { + return mongodb.NewCodehostColl().GetCodeHostByID(id) +} diff --git a/pkg/microservice/systemconfig/core/email/handler/email.go b/pkg/microservice/systemconfig/core/email/handler/email.go new file mode 100644 index 0000000000000000000000000000000000000000..fbb3432ca292ffb5d6196188078b9f3792bdc1cf --- /dev/null +++ b/pkg/microservice/systemconfig/core/email/handler/email.go @@ -0,0 +1,83 @@ +package handler + +import ( + "github.com/gin-gonic/gin" + + "github.com/koderover/zadig/pkg/microservice/systemconfig/core/email/repository/models" + "github.com/koderover/zadig/pkg/microservice/systemconfig/core/email/service" + internalhandler "github.com/koderover/zadig/pkg/shared/handler" +) + +func GetEmailHost(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + ctx.Resp, ctx.Err = service.GetEmailHost(ctx.Logger) +} + +func InternalGetEmailHost(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + ctx.Resp, ctx.Err = service.InternalGetEmailHost(ctx.Logger) +} + +func CreateEmailHost(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + req := new(models.EmailHost) + if err := c.ShouldBindJSON(req); err != nil { + ctx.Err = err + return + } + ctx.Resp, ctx.Err = service.CreateEmailHost(req, ctx.Logger) +} + +func UpdateEmailHost(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + req := new(models.EmailHost) + if err := c.ShouldBindJSON(req); err != nil { + ctx.Err = err + return + } + ctx.Resp, ctx.Err = service.UpdateEmailHost(req, ctx.Logger) +} + +func DeleteEmailHost(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + ctx.Err = service.DeleteEmailHost(ctx.Logger) +} + +func GetEmailService(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + ctx.Resp, ctx.Err = service.GetEmailService(ctx.Logger) +} + +func CreateEmailService(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + req := new(models.EmailService) + if err := c.ShouldBindJSON(req); err != nil { + ctx.Err = err + return + } + ctx.Resp, ctx.Err = service.CreateEmailService(req, ctx.Logger) +} + +func UpdateEmailService(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + req := new(models.EmailService) + if err := c.ShouldBindJSON(req); err != nil { + ctx.Err = err + return + } + ctx.Resp, ctx.Err = service.UpdateEmailService(req, ctx.Logger) +} + +func DeleteEmailService(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + ctx.Err = service.DeleteEmailService(ctx.Logger) +} diff --git a/pkg/microservice/systemconfig/core/email/handler/router.go b/pkg/microservice/systemconfig/core/email/handler/router.go new file mode 100644 index 0000000000000000000000000000000000000000..f8e2a8ec18c6e7f8a206b31814451e46539fc8c9 --- /dev/null +++ b/pkg/microservice/systemconfig/core/email/handler/router.go @@ -0,0 +1,24 @@ +package handler + +import ( + "github.com/gin-gonic/gin" +) + +type Router struct{} + +func (*Router) Inject(router *gin.RouterGroup) { + emails := router.Group("emails") + { + emails.GET("/host", GetEmailHost) + emails.POST("/host", CreateEmailHost) + emails.PATCH("/host", UpdateEmailHost) + emails.DELETE("/host", DeleteEmailHost) + + emails.GET("/internal/host", InternalGetEmailHost) + + emails.GET("/service", GetEmailService) + emails.POST("/service", CreateEmailService) + emails.PATCH("/service", UpdateEmailService) + emails.DELETE("/service", DeleteEmailService) + } +} diff --git a/pkg/microservice/systemconfig/core/email/repository/models/emailhost.go b/pkg/microservice/systemconfig/core/email/repository/models/emailhost.go new file mode 100644 index 0000000000000000000000000000000000000000..9dff9ad78262b3c458b851bf37a6f68ab2ffbdfc --- /dev/null +++ b/pkg/microservice/systemconfig/core/email/repository/models/emailhost.go @@ -0,0 +1,16 @@ +package models + +type EmailHost struct { + Name string `bson:"name" json:"name"` + Port int `bson:"port" json:"port"` + Username string `bson:"username" json:"username"` + Password string `bson:"password" json:"password"` + IsTLS bool `bson:"is_tls" json:"isTLS"` + CreatedAt int64 `bson:"created_at" json:"created_at"` + DeletedAt int64 `bson:"deleted_at" json:"deleted_at"` + UpdatedAt int64 `bson:"updated_at" json:"updated_at"` +} + +func (EmailHost) TableName() string { + return "email_host" +} diff --git a/pkg/microservice/systemconfig/core/email/repository/models/emailservice.go b/pkg/microservice/systemconfig/core/email/repository/models/emailservice.go new file mode 100644 index 0000000000000000000000000000000000000000..148d7af10fb0c40b1681ebe56dda7480147a010d --- /dev/null +++ b/pkg/microservice/systemconfig/core/email/repository/models/emailservice.go @@ -0,0 +1,15 @@ +package models + +type EmailService struct { + Name string `json:"name" bson:"name"` + Address string `json:"address" bson:"address"` + DisplayName string `json:"display_name" bson:"display_name"` + Theme string `json:"theme" bson:"theme"` + CreatedAt int64 `json:"created_at" bson:"created_at"` + UpdatedAt int64 `json:"updated_at" bson:"updated_at"` + DeletedAt int64 `json:"deleted_at" bson:"deleted_at"` +} + +func (EmailService) TableName() string { + return "email_service" +} diff --git a/pkg/microservice/systemconfig/core/email/repository/mongodb/emailhost.go b/pkg/microservice/systemconfig/core/email/repository/mongodb/emailhost.go new file mode 100644 index 0000000000000000000000000000000000000000..9d16d343767d0c92f5e4b1b6fff2d2a9948d79f0 --- /dev/null +++ b/pkg/microservice/systemconfig/core/email/repository/mongodb/emailhost.go @@ -0,0 +1,105 @@ +package mongodb + +import ( + "context" + "errors" + "time" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + + "github.com/koderover/zadig/pkg/microservice/systemconfig/config" + "github.com/koderover/zadig/pkg/microservice/systemconfig/core/email/repository/models" + "github.com/koderover/zadig/pkg/tool/log" + mongotool "github.com/koderover/zadig/pkg/tool/mongo" +) + +type EmailHostColl struct { + *mongo.Collection + + coll string +} + +func NewEmailHostColl() *EmailHostColl { + name := models.EmailHost{}.TableName() + coll := &EmailHostColl{Collection: mongotool.Database(config.MongoDatabase()).Collection(name), coll: name} + + return coll +} + +func (c *EmailHostColl) GetCollectionName() string { + return c.coll +} +func (c *EmailHostColl) EnsureIndex(ctx context.Context) error { + return nil +} + +func (c *EmailHostColl) Find() (*models.EmailHost, error) { + emailHost := new(models.EmailHost) + query := bson.M{"deleted_at": 0} + + ctx := context.Background() + + err := c.Collection.FindOne(ctx, query).Decode(emailHost) + if err != nil { + return nil, nil + } + return emailHost, nil +} + +func (c *EmailHostColl) Update(emailHost *models.EmailHost) (*models.EmailHost, error) { + query := bson.M{"deleted_at": 0} + change := bson.M{"$set": bson.M{ + "name": emailHost.Name, + "port": emailHost.Port, + "username": emailHost.Username, + "password": emailHost.Password, + "is_tls": emailHost.IsTLS, + "updated_at": time.Now().Unix(), + }} + + _, err := c.Collection.UpdateOne(context.TODO(), query, change) + if err != nil { + log.Error("repository Update EmailHostColl err : %v", err) + return nil, err + } + return emailHost, nil +} + +func (c *EmailHostColl) Delete() error { + query := bson.M{"deleted_at": 0} + change := bson.M{"$set": bson.M{ + "deleted_at": time.Now().Unix(), + }} + + _, err := c.Collection.UpdateOne(context.TODO(), query, change) + if err != nil { + log.Error("repository Delete EmailHostColl err : %v", err) + return err + } + return nil +} + +func (c *EmailHostColl) Add(emailHost *models.EmailHost) (*models.EmailHost, error) { + // TODO: tmp solution to avoid bug + var res []*models.EmailHost + query := bson.M{"deleted_at": 0} + cur, err := c.Collection.Find(context.TODO(), query) + if err != nil { + return nil, err + } + err = cur.All(context.TODO(), &res) + if err != nil { + return nil, err + } + if len(res) >= 1 { + return nil, errors.New("cant add more than one emailhost") + } + + _, err = c.Collection.InsertOne(context.TODO(), emailHost) + if err != nil { + log.Error("repository AddEmailHost err : %v", err) + return nil, err + } + return emailHost, nil +} diff --git a/pkg/microservice/systemconfig/core/email/repository/mongodb/emailservice.go b/pkg/microservice/systemconfig/core/email/repository/mongodb/emailservice.go new file mode 100644 index 0000000000000000000000000000000000000000..7ded08a24a74dc5ca76517f4dba6489d2b6dd320 --- /dev/null +++ b/pkg/microservice/systemconfig/core/email/repository/mongodb/emailservice.go @@ -0,0 +1,100 @@ +package mongodb + +import ( + "context" + "errors" + "time" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + + "github.com/koderover/zadig/pkg/microservice/systemconfig/config" + "github.com/koderover/zadig/pkg/microservice/systemconfig/core/email/repository/models" + "github.com/koderover/zadig/pkg/tool/log" + mongotool "github.com/koderover/zadig/pkg/tool/mongo" +) + +type EmailServiceColl struct { + *mongo.Collection + + coll string +} + +func NewEmailServiceColl() *EmailServiceColl { + name := models.EmailService{}.TableName() + coll := &EmailServiceColl{Collection: mongotool.Database(config.MongoDatabase()).Collection(name), coll: name} + + return coll +} + +func (c *EmailServiceColl) GetCollectionName() string { + return c.coll +} +func (c *EmailServiceColl) EnsureIndex(ctx context.Context) error { + return nil +} + +func (c *EmailServiceColl) AddEmailService(iEmailService *models.EmailService) (*models.EmailService, error) { + // TODO: tmp solution to avoid bug + var res []*models.EmailService + query := bson.M{"deleted_at": 0} + cur, err := c.Collection.Find(context.TODO(), query) + if err != nil { + return nil, err + } + err = cur.All(context.TODO(), &res) + if err != nil { + return nil, err + } + if len(res) >= 1 { + return nil, errors.New("cant add more than one emailservice") + } + + _, err = c.Collection.InsertOne(context.TODO(), iEmailService) + if err != nil { + log.Error("repository AddEmailService err : %v", err) + return nil, err + } + return iEmailService, nil +} + +func (c *EmailServiceColl) GetEmailService() (*models.EmailService, error) { + query := bson.M{"deleted_at": 0} + iEmailService := &models.EmailService{} + err := c.Collection.FindOne(context.TODO(), query).Decode(iEmailService) + if err != nil { + return nil, nil + } + return iEmailService, nil +} + +func (c *EmailServiceColl) UpdateEmailService(iEmailService *models.EmailService) (*models.EmailService, error) { + query := bson.M{"deleted_at": 0} + change := bson.M{"$set": bson.M{ + "name": iEmailService.Name, + "address": iEmailService.Address, + "display_name": iEmailService.DisplayName, + "theme": iEmailService.Theme, + "updated_at": time.Now().Unix(), + }} + + _, err := c.Collection.UpdateOne(context.TODO(), query, change) + if err != nil { + log.Error("repository UpdateEmailService err : %v", err) + return nil, err + } + return iEmailService, nil +} + +func (c *EmailServiceColl) DeleteEmailService() error { + query := bson.M{"deleted_at": 0} + change := bson.M{"$set": bson.M{ + "deleted_at": time.Now().Unix(), + }} + _, err := c.Collection.UpdateOne(context.TODO(), query, change) + if err != nil { + log.Error("repository DeleteEmailServiceByOrgID err : %v", err) + return err + } + return nil +} diff --git a/pkg/microservice/systemconfig/core/email/service/email.go b/pkg/microservice/systemconfig/core/email/service/email.go new file mode 100644 index 0000000000000000000000000000000000000000..4de7edc87d5215a443d6c7fc6456f7e6b6fca7ef --- /dev/null +++ b/pkg/microservice/systemconfig/core/email/service/email.go @@ -0,0 +1,56 @@ +package service + +import ( + "time" + + "go.uber.org/zap" + + "github.com/koderover/zadig/pkg/microservice/systemconfig/core/email/repository/models" + "github.com/koderover/zadig/pkg/microservice/systemconfig/core/email/repository/mongodb" +) + +func GetEmailHost(_ *zap.SugaredLogger) (*models.EmailHost, error) { + host, err := mongodb.NewEmailHostColl().Find() + if host != nil { + host.Password = "***" + } + return host, err +} + +func InternalGetEmailHost(_ *zap.SugaredLogger) (*models.EmailHost, error) { + return mongodb.NewEmailHostColl().Find() +} + +func CreateEmailHost(emailHost *models.EmailHost, _ *zap.SugaredLogger) (*models.EmailHost, error) { + emailHost.CreatedAt = time.Now().Unix() + emailHost.UpdatedAt = time.Now().Unix() + return mongodb.NewEmailHostColl().Add(emailHost) +} + +func UpdateEmailHost(emailHost *models.EmailHost, _ *zap.SugaredLogger) (*models.EmailHost, error) { + emailHost.UpdatedAt = time.Now().Unix() + return mongodb.NewEmailHostColl().Update(emailHost) +} + +func DeleteEmailHost(_ *zap.SugaredLogger) error { + return mongodb.NewEmailHostColl().Delete() +} + +func GetEmailService(_ *zap.SugaredLogger) (*models.EmailService, error) { + return mongodb.NewEmailServiceColl().GetEmailService() +} + +func CreateEmailService(emailService *models.EmailService, _ *zap.SugaredLogger) (*models.EmailService, error) { + emailService.CreatedAt = time.Now().Unix() + emailService.UpdatedAt = time.Now().Unix() + return mongodb.NewEmailServiceColl().AddEmailService(emailService) +} + +func UpdateEmailService(emailService *models.EmailService, _ *zap.SugaredLogger) (*models.EmailService, error) { + emailService.UpdatedAt = time.Now().Unix() + return mongodb.NewEmailServiceColl().UpdateEmailService(emailService) +} + +func DeleteEmailService(_ *zap.SugaredLogger) error { + return mongodb.NewEmailServiceColl().DeleteEmailService() +} diff --git a/pkg/microservice/systemconfig/core/handler/connector.go b/pkg/microservice/systemconfig/core/handler/connector.go new file mode 100644 index 0000000000000000000000000000000000000000..95e475db0bea74bd12d5ecaf8413346621646561 --- /dev/null +++ b/pkg/microservice/systemconfig/core/handler/connector.go @@ -0,0 +1,72 @@ +/* +Copyright 2021 The KodeRover 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 handler + +import ( + "github.com/gin-gonic/gin" + + "github.com/koderover/zadig/pkg/microservice/systemconfig/core/service" + internalhandler "github.com/koderover/zadig/pkg/shared/handler" +) + +func CreateConnector(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + args := &service.Connector{} + if err := c.ShouldBindJSON(args); err != nil { + ctx.Err = err + return + } + + ctx.Err = service.CreateConnector(args, ctx.Logger) +} + +func ListConnectors(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + ctx.Resp, ctx.Err = service.ListConnectors(ctx.Logger) +} + +func DeleteConnector(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + ctx.Err = service.DeleteConnector(c.Param("id"), ctx.Logger) +} + +func GetConnector(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + ctx.Resp, ctx.Err = service.GetConnector(c.Param("id"), ctx.Logger) +} + +func UpdateConnector(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + args := &service.Connector{} + if err := c.ShouldBindJSON(args); err != nil { + ctx.Err = err + return + } + args.ID = c.Param("id") + + ctx.Err = service.UpdateConnector(args, ctx.Logger) +} diff --git a/pkg/microservice/systemconfig/core/handler/features.go b/pkg/microservice/systemconfig/core/handler/features.go new file mode 100644 index 0000000000000000000000000000000000000000..18952e06960d6062dac48407f65e5511c2b1b705 --- /dev/null +++ b/pkg/microservice/systemconfig/core/handler/features.go @@ -0,0 +1,26 @@ +package handler + +import ( + "github.com/gin-gonic/gin" + + "github.com/koderover/zadig/pkg/microservice/systemconfig/core/service/featuregates" + internalhandler "github.com/koderover/zadig/pkg/shared/handler" +) + +type feature struct { + Name string `json:"name"` + Enabled bool `json:"enabled"` +} + +func GetFeature(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + name := c.Param("name") + enabled := featuregates.Features.FeatureEnabled(featuregates.Feature(name)) + + ctx.Resp = &feature{ + Name: c.Param("name"), + Enabled: enabled, + } +} diff --git a/pkg/microservice/systemconfig/core/handler/router.go b/pkg/microservice/systemconfig/core/handler/router.go new file mode 100644 index 0000000000000000000000000000000000000000..282f4cb1261c729f43e7f0d886ffe18eedc74250 --- /dev/null +++ b/pkg/microservice/systemconfig/core/handler/router.go @@ -0,0 +1,38 @@ +/* +Copyright 2021 The KodeRover 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 handler + +import ( + "github.com/gin-gonic/gin" +) + +type Router struct{} + +func (*Router) Inject(router *gin.RouterGroup) { + roles := router.Group("connectors") + { + roles.POST("", CreateConnector) + roles.GET("", ListConnectors) + roles.GET("/:id", GetConnector) + roles.PUT("/:id", UpdateConnector) + roles.DELETE("/:id", DeleteConnector) + } + features := router.Group("features") + { + features.GET("/:name", GetFeature) + } +} diff --git a/pkg/microservice/systemconfig/core/jira/handler/jira.go b/pkg/microservice/systemconfig/core/jira/handler/jira.go new file mode 100644 index 0000000000000000000000000000000000000000..4e8b64934f578dcb724d3655a0a61c5e0ffa1997 --- /dev/null +++ b/pkg/microservice/systemconfig/core/jira/handler/jira.go @@ -0,0 +1,43 @@ +package handler + +import ( + "github.com/gin-gonic/gin" + + "github.com/koderover/zadig/pkg/microservice/systemconfig/core/jira/repository/models" + "github.com/koderover/zadig/pkg/microservice/systemconfig/core/jira/service" + internalhandler "github.com/koderover/zadig/pkg/shared/handler" +) + +func DeleteJira(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + ctx.Err = service.DeleteJira(ctx.Logger) +} + +func GetJira(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + ctx.Resp, ctx.Err = service.GeJira(ctx.Logger) +} + +func CreateJira(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + req := new(models.Jira) + if err := c.ShouldBindJSON(req); err != nil { + ctx.Err = err + return + } + ctx.Resp, ctx.Err = service.CreateJira(req, ctx.Logger) +} + +func UpdateJira(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + req := new(models.Jira) + if err := c.ShouldBindJSON(req); err != nil { + ctx.Err = err + return + } + ctx.Resp, ctx.Err = service.UpdateJira(req, ctx.Logger) +} diff --git a/pkg/microservice/systemconfig/core/jira/handler/router.go b/pkg/microservice/systemconfig/core/jira/handler/router.go new file mode 100644 index 0000000000000000000000000000000000000000..b302096f7cec21102d062e3ca84b32062e135a4c --- /dev/null +++ b/pkg/microservice/systemconfig/core/jira/handler/router.go @@ -0,0 +1,18 @@ +package handler + +import ( + "github.com/gin-gonic/gin" +) + +type Router struct{} + +func (*Router) Inject(router *gin.RouterGroup) { + jira := router.Group("jira") + { + jira.GET("", GetJira) + jira.POST("", CreateJira) + jira.PATCH("", UpdateJira) + jira.DELETE("", DeleteJira) + } + +} diff --git a/pkg/microservice/systemconfig/core/jira/repository/models/jira.go b/pkg/microservice/systemconfig/core/jira/repository/models/jira.go new file mode 100644 index 0000000000000000000000000000000000000000..b432566950c1073094a3419f036b168495eea4b7 --- /dev/null +++ b/pkg/microservice/systemconfig/core/jira/repository/models/jira.go @@ -0,0 +1,14 @@ +package models + +type Jira struct { + Host string `bson:"host" json:"host"` + User string `bson:"user" json:"user"` + AccessToken string `bson:"access_token" json:"access_token"` + CreatedAt int64 `bson:"created_at" json:"created_at"` + UpdatedAt int64 `bson:"updated_at" json:"updated_at"` + DeletedAt int64 `bson:"deleted_at" json:"deleted_at"` +} + +func (Jira) TableName() string { + return "jira" +} diff --git a/pkg/microservice/systemconfig/core/jira/repository/mongodb/jira.go b/pkg/microservice/systemconfig/core/jira/repository/mongodb/jira.go new file mode 100644 index 0000000000000000000000000000000000000000..acefdbd4346b0438b487c2a8c937bb59c3a8387b --- /dev/null +++ b/pkg/microservice/systemconfig/core/jira/repository/mongodb/jira.go @@ -0,0 +1,87 @@ +package mongodb + +import ( + "context" + "time" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + + "github.com/koderover/zadig/pkg/microservice/systemconfig/config" + "github.com/koderover/zadig/pkg/microservice/systemconfig/core/jira/repository/models" + "github.com/koderover/zadig/pkg/tool/log" + mongotool "github.com/koderover/zadig/pkg/tool/mongo" +) + +type JiraColl struct { + *mongo.Collection + + coll string +} + +func NewJiraColl() *JiraColl { + name := models.Jira{}.TableName() + coll := &JiraColl{Collection: mongotool.Database(config.MongoDatabase()).Collection(name), coll: name} + + return coll +} + +func (c *JiraColl) GetCollectionName() string { + return c.coll +} +func (c *JiraColl) EnsureIndex(ctx context.Context) error { + return nil +} + +func (c *JiraColl) AddJira(iJira *models.Jira) (*models.Jira, error) { + _, err := c.Collection.InsertOne(context.TODO(), iJira) + if err != nil { + log.Error("repository AddJira err : %v", err) + return nil, err + } + return iJira, nil +} + +func (c *JiraColl) UpdateJira(iJira *models.Jira) (*models.Jira, error) { + + query := bson.M{"deleted_at": 0} + change := bson.M{"$set": bson.M{ + "host": iJira.Host, + "user": iJira.User, + "access_token": iJira.AccessToken, + "updated_at": time.Now().Unix(), + }} + + _, err := c.Collection.UpdateOne(context.TODO(), query, change) + if err != nil { + log.Error("repository UpdateJira err : %v", err) + return nil, err + } + return iJira, nil +} + +func (c *JiraColl) DeleteJira() error { + + query := bson.M{"deleted_at": 0} + change := bson.M{"$set": bson.M{ + "deleted_at": time.Now().Unix(), + }} + + _, err := c.Collection.UpdateOne(context.TODO(), query, change) + if err != nil { + log.Error("repository DeleteJira err : %v", err) + return err + } + return nil +} + +func (c *JiraColl) GetJira() (*models.Jira, error) { + jira := &models.Jira{} + query := bson.M{"deleted_at": 0} + + err := c.Collection.FindOne(context.TODO(), query).Decode(jira) + if err != nil { + return nil, nil + } + return jira, nil +} diff --git a/pkg/microservice/systemconfig/core/jira/service/jira.go b/pkg/microservice/systemconfig/core/jira/service/jira.go new file mode 100644 index 0000000000000000000000000000000000000000..0368497dc6b530d1f4710ee89e81f22ee90a4fb5 --- /dev/null +++ b/pkg/microservice/systemconfig/core/jira/service/jira.go @@ -0,0 +1,29 @@ +package service + +import ( + "time" + + "go.uber.org/zap" + + "github.com/koderover/zadig/pkg/microservice/systemconfig/core/jira/repository/models" + "github.com/koderover/zadig/pkg/microservice/systemconfig/core/jira/repository/mongodb" +) + +func GeJira(_ *zap.SugaredLogger) (*models.Jira, error) { + return mongodb.NewJiraColl().GetJira() +} + +func CreateJira(jira *models.Jira, _ *zap.SugaredLogger) (*models.Jira, error) { + jira.CreatedAt = time.Now().Unix() + jira.UpdatedAt = time.Now().Unix() + return mongodb.NewJiraColl().AddJira(jira) +} + +func UpdateJira(jira *models.Jira, _ *zap.SugaredLogger) (*models.Jira, error) { + jira.UpdatedAt = time.Now().Unix() + return mongodb.NewJiraColl().UpdateJira(jira) +} + +func DeleteJira(_ *zap.SugaredLogger) error { + return mongodb.NewJiraColl().DeleteJira() +} diff --git a/pkg/microservice/systemconfig/core/repository/models/connector.go b/pkg/microservice/systemconfig/core/repository/models/connector.go new file mode 100644 index 0000000000000000000000000000000000000000..42706039aada46e79989bc7588db1105b9eeae3f --- /dev/null +++ b/pkg/microservice/systemconfig/core/repository/models/connector.go @@ -0,0 +1,37 @@ +/* +Copyright 2021 The KodeRover 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 "strconv" + +type Connector struct { + ID string `json:"id"` + Type string `json:"type"` + Name string `json:"name"` + ResourceVersion string `json:"resource_version"` + Config string `json:"config"` +} + +func (m *Connector) IncreaseResourceVersion() { + rv, _ := strconv.Atoi(m.ResourceVersion) + m.ResourceVersion = strconv.Itoa(rv + 1) +} + +// TableName sets the insert table name for this struct type +func (Connector) TableName() string { + return "connector" +} diff --git a/pkg/microservice/systemconfig/core/repository/orm/connector.go b/pkg/microservice/systemconfig/core/repository/orm/connector.go new file mode 100644 index 0000000000000000000000000000000000000000..a13db56832ad960a299b8aa7de519b2811e8703f --- /dev/null +++ b/pkg/microservice/systemconfig/core/repository/orm/connector.go @@ -0,0 +1,83 @@ +/* +Copyright 2021 The KodeRover 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 orm + +import ( + "gorm.io/gorm" + + "github.com/koderover/zadig/pkg/microservice/systemconfig/config" + "github.com/koderover/zadig/pkg/microservice/systemconfig/core/repository/models" + gormtool "github.com/koderover/zadig/pkg/tool/gorm" +) + +type ConnectorColl struct { + *gorm.DB + + coll string +} + +func NewConnectorColl() *ConnectorColl { + name := models.Connector{}.TableName() + return &ConnectorColl{ + DB: gormtool.DB(config.MysqlDexDB()), + coll: name, + } +} + +func (c *ConnectorColl) GetCollectionName() string { + return c.coll +} + +func (c *ConnectorColl) List() ([]*models.Connector, error) { + var res []*models.Connector + result := c.Find(&res) + + return res, result.Error +} + +func (c *ConnectorColl) Get(id string) (*models.Connector, error) { + res := &models.Connector{} + result := c.First(&res, "id=?", id) + + return res, result.Error +} + +func (c *ConnectorColl) Create(obj *models.Connector) error { + obj.ResourceVersion = "1" + result := c.DB.Create(obj) + + return result.Error +} + +func (c *ConnectorColl) Update(obj *models.Connector) error { + current, err := c.Get(obj.ID) + if err != nil { + return err + } + + obj.ResourceVersion = current.ResourceVersion + obj.IncreaseResourceVersion() + result := c.DB.Save(obj) + + return result.Error +} + +func (c *ConnectorColl) Delete(id string) error { + result := c.DB.Delete(&models.Connector{ID: id}) + + return result.Error +} diff --git a/pkg/microservice/systemconfig/core/service.go b/pkg/microservice/systemconfig/core/service.go new file mode 100644 index 0000000000000000000000000000000000000000..c0aae5ba83a50cd6de62d2828f7981b62fa4301e --- /dev/null +++ b/pkg/microservice/systemconfig/core/service.go @@ -0,0 +1,90 @@ +/* +Copyright 2021 The KodeRover 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 core + +import ( + "context" + "fmt" + "sync" + "time" + + configbase "github.com/koderover/zadig/pkg/config" + "github.com/koderover/zadig/pkg/microservice/systemconfig/config" + "github.com/koderover/zadig/pkg/microservice/systemconfig/core/email/repository/mongodb" + "github.com/koderover/zadig/pkg/microservice/systemconfig/core/service/featuregates" + "github.com/koderover/zadig/pkg/setting" + gormtool "github.com/koderover/zadig/pkg/tool/gorm" + "github.com/koderover/zadig/pkg/tool/log" + mongotool "github.com/koderover/zadig/pkg/tool/mongo" +) + +func Start(_ context.Context) { + log.Init(&log.Config{ + Level: configbase.LogLevel(), + Filename: configbase.LogFile(), + SendToFile: configbase.SendLogToFile(), + Development: configbase.Mode() != setting.ReleaseMode, + }) + + initDatabase() + + featuregates.Features.MergeFeatureGates(featuregates.ToFeatureGates(config.Features())) +} + +func initDatabase() { + err := gormtool.Open(configbase.MysqlUser(), + configbase.MysqlPassword(), + configbase.MysqlHost(), + config.MysqlDexDB(), + ) + if err != nil { + log.Panicf("Failed to open database %s", config.MysqlDexDB()) + } + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + mongotool.Init(ctx, config.MongoURI()) + if err := mongotool.Ping(ctx); err != nil { + panic(fmt.Errorf("failed to connect to mongo, error: %s", err)) + } + idxCtx, idxCancel := context.WithTimeout(ctx, 10*time.Minute) + defer idxCancel() + var wg sync.WaitGroup + for _, r := range []indexer{ + mongodb.NewEmailHostColl(), + } { + + wg.Add(1) + go func(r indexer) { + defer wg.Done() + if err := r.EnsureIndex(idxCtx); err != nil { + panic(fmt.Errorf("failed to create index for %s, error: %s", r.GetCollectionName(), err)) + } + }(r) + } + wg.Wait() +} + +type indexer interface { + EnsureIndex(ctx context.Context) error + GetCollectionName() string +} + +func Stop(_ context.Context) { + gormtool.Close() +} diff --git a/pkg/microservice/systemconfig/core/service/connector.go b/pkg/microservice/systemconfig/core/service/connector.go new file mode 100644 index 0000000000000000000000000000000000000000..a60d39e01688c18da2943627b200a9b8c3ebf123 --- /dev/null +++ b/pkg/microservice/systemconfig/core/service/connector.go @@ -0,0 +1,117 @@ +/* +Copyright 2021 The KodeRover 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 service + +import ( + "encoding/json" + + "go.uber.org/zap" + + "github.com/koderover/zadig/pkg/microservice/systemconfig/core/repository/models" + "github.com/koderover/zadig/pkg/microservice/systemconfig/core/repository/orm" +) + +func ListConnectors(logger *zap.SugaredLogger) ([]*Connector, error) { + cs, err := orm.NewConnectorColl().List() + if err != nil { + logger.Errorf("Failed to list connectors, err: %s", err) + return nil, err + } + + var res []*Connector + for _, c := range cs { + cf := make(map[string]interface{}) + err = json.Unmarshal([]byte(c.Config), &cf) + if err != nil { + logger.Warnf("Failed to unmarshal config, err: %s", err) + continue + } + res = append(res, &Connector{ + ConnectorBase: ConnectorBase{ + Type: ConnectorType(c.Type), + }, + ID: c.ID, + Name: c.Name, + Config: cf, + }) + } + + return res, nil +} + +func GetConnector(id string, logger *zap.SugaredLogger) (*Connector, error) { + c, err := orm.NewConnectorColl().Get(id) + if err != nil { + logger.Errorf("Failed to get connector %s, err: %s", id, err) + return nil, err + } + + cf := make(map[string]interface{}) + err = json.Unmarshal([]byte(c.Config), &cf) + if err != nil { + logger.Warnf("Failed to unmarshal config, err: %s", err) + + } + + return &Connector{ + ConnectorBase: ConnectorBase{ + Type: ConnectorType(c.Type), + }, + ID: c.ID, + Name: c.Name, + Config: cf, + }, nil + +} + +func DeleteConnector(id string, _ *zap.SugaredLogger) error { + return orm.NewConnectorColl().Delete(id) +} + +func CreateConnector(ct *Connector, logger *zap.SugaredLogger) error { + cf, err := json.Marshal(ct.Config) + if err != nil { + logger.Errorf("Failed to marshal config, err: %s", err) + return err + } + + obj := &models.Connector{ + ID: ct.ID, + Name: ct.Name, + Type: string(ct.Type), + Config: string(cf), + } + + return orm.NewConnectorColl().Create(obj) +} + +func UpdateConnector(ct *Connector, logger *zap.SugaredLogger) error { + cf, err := json.Marshal(ct.Config) + if err != nil { + logger.Errorf("Failed to marshal config, err: %s", err) + return err + } + + obj := &models.Connector{ + ID: ct.ID, + Name: ct.Name, + Type: string(ct.Type), + Config: string(cf), + } + + return orm.NewConnectorColl().Update(obj) +} diff --git a/pkg/microservice/systemconfig/core/service/featuregates/feature.go b/pkg/microservice/systemconfig/core/service/featuregates/feature.go new file mode 100644 index 0000000000000000000000000000000000000000..13b5c7d925397677d179bd0d5d944e2654e14bbe --- /dev/null +++ b/pkg/microservice/systemconfig/core/service/featuregates/feature.go @@ -0,0 +1,55 @@ +package featuregates + +import "strings" + +type Feature string + +const ( + ModernWorkflow Feature = "ModernWorkflow" + CommunityProjectRepository Feature = "CommunityProjectRepository" +) + +var Features FeatureGates = map[Feature]bool{ + ModernWorkflow: false, + CommunityProjectRepository: false, +} + +type FeatureGates map[Feature]bool + +func (fg FeatureGates) EnabledFeatures() []Feature { + var res []Feature + + for k, v := range fg { + if v { + res = append(res, k) + } + } + + return res +} + +func (fg FeatureGates) FeatureEnabled(f Feature) bool { + return fg[f] +} + +func (fg FeatureGates) MergeFeatureGates(fs FeatureGates) { + for k, v := range fs { + fg[k] = v + } +} + +func ToFeatureGates(s string) FeatureGates { + res := make(FeatureGates) + + fs := strings.Split(s, ",") + for _, f := range fs { + kv := strings.Split(f, "=") + if len(kv) != 2 { + continue + } + + res[Feature(kv[0])] = kv[1] == "true" + } + + return res +} diff --git a/pkg/microservice/systemconfig/core/service/types.go b/pkg/microservice/systemconfig/core/service/types.go new file mode 100644 index 0000000000000000000000000000000000000000..90c22df8eb18d42a66a1faa39535743cf3592938 --- /dev/null +++ b/pkg/microservice/systemconfig/core/service/types.go @@ -0,0 +1,85 @@ +/* +Copyright 2021 The KodeRover 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 service + +import ( + "encoding/json" + + "github.com/dexidp/dex/connector/gitea" + "github.com/dexidp/dex/connector/github" + "github.com/dexidp/dex/connector/gitlab" + "github.com/dexidp/dex/connector/google" + "github.com/dexidp/dex/connector/ldap" + "github.com/dexidp/dex/connector/linkedin" + "github.com/dexidp/dex/connector/microsoft" + "github.com/dexidp/dex/connector/oidc" +) + +type ConnectorType string + +const ( + TypeLDAP ConnectorType = "ldap" + TypeGitHub ConnectorType = "github" + TypeGitlab ConnectorType = "gitlab" + TypeOIDC ConnectorType = "oidc" + TypeGitea ConnectorType = "gitea" + TypeGoogle ConnectorType = "google" + TypeLinkedIn ConnectorType = "linkedin" + TypeMicrosoft ConnectorType = "microsoft" +) + +type Connector struct { + ConnectorBase + + ID string `json:"id"` + Name string `json:"name"` + Config interface{} `json:"config"` +} + +type ConnectorBase struct { + Type ConnectorType `json:"type"` +} + +func (c *Connector) UnmarshalJSON(data []byte) error { + cb := &ConnectorBase{} + if err := json.Unmarshal(data, cb); err != nil { + return err + } + + switch cb.Type { + case TypeLDAP: + c.Config = &ldap.Config{} + case TypeGitHub: + c.Config = &github.Config{} + case TypeGitlab: + c.Config = &gitlab.Config{} + case TypeOIDC: + c.Config = &oidc.Config{} + case TypeGitea: + c.Config = &gitea.Config{} + case TypeGoogle: + c.Config = &google.Config{} + case TypeLinkedIn: + c.Config = &linkedin.Config{} + case TypeMicrosoft: + c.Config = µsoft.Config{} + } + + type tmp Connector + + return json.Unmarshal(data, (*tmp)(c)) +} diff --git a/pkg/microservice/systemconfig/server/rest/router.go b/pkg/microservice/systemconfig/server/rest/router.go new file mode 100644 index 0000000000000000000000000000000000000000..015f0c564cf0d283a2bb152f1ec92b1f8dd24f73 --- /dev/null +++ b/pkg/microservice/systemconfig/server/rest/router.go @@ -0,0 +1,41 @@ +/* +Copyright 2021 The KodeRover 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 rest + +import ( + "github.com/gin-gonic/gin" + + codehosthandler "github.com/koderover/zadig/pkg/microservice/systemconfig/core/codehost/handler" + emailHandler "github.com/koderover/zadig/pkg/microservice/systemconfig/core/email/handler" + "github.com/koderover/zadig/pkg/microservice/systemconfig/core/handler" + jiraHandler "github.com/koderover/zadig/pkg/microservice/systemconfig/core/jira/handler" +) + +func (s *engine) injectRouterGroup(router *gin.RouterGroup) { + for _, r := range []injector{ + new(handler.Router), + new(emailHandler.Router), + new(jiraHandler.Router), + new(codehosthandler.Router), + } { + r.Inject(router.Group("/api/v1")) + } +} + +type injector interface { + Inject(router *gin.RouterGroup) +} diff --git a/pkg/microservice/aslan/internal/cache/cache.go b/pkg/microservice/systemconfig/server/rest/server.go similarity index 35% rename from pkg/microservice/aslan/internal/cache/cache.go rename to pkg/microservice/systemconfig/server/rest/server.go index b62663558d549d013634c0dfcdc39b2f45e3811e..18843b0a5ead8f194d217a281527d5152e939795 100644 --- a/pkg/microservice/aslan/internal/cache/cache.go +++ b/pkg/microservice/systemconfig/server/rest/server.go @@ -14,38 +14,63 @@ See the License for the specific language governing permissions and limitations under the License. */ -package cache +package rest import ( - "sync" + "net/http" - "github.com/coocood/freecache" + "github.com/gin-gonic/gin" + + "github.com/koderover/zadig/pkg/config" + ginmiddleware "github.com/koderover/zadig/pkg/middleware/gin" + "github.com/koderover/zadig/pkg/tool/log" ) -const defaultSize = 1024 * 1024 * 10 // 10 Mi +type engine struct { + *gin.Engine + + mode string +} -var once sync.Once -var cache *freecache.Cache +func NewEngine() *engine { + s := &engine{mode: config.Mode()} -// Set sets a key, value and expiration for a cache entry and stores it in the cache. -// If the key is larger than 65535 or value is larger than 1/1024 of the cache size, -// the entry will not be written to the cache. expireSeconds <= 0 means no expire, -// but it can be evicted when cache is full. -func Set(key, value []byte, expireSeconds int) error { - once.Do(func() { - cache = initCache(0) - }) - return cache.Set(key, value, expireSeconds) + gin.SetMode(s.mode) + + s.injectMiddlewares() + s.injectRouters() + + return s } -// Get returns the value or not found error. -func Get(key []byte) ([]byte, error) { - once.Do(func() { - cache = initCache(defaultSize) - }) - return cache.Get(key) +func (s *engine) injectMiddlewares() { + g := gin.New() + defer func() { + s.Engine = g + }() + + if s.mode == gin.TestMode { + return + } + g.Use(ginmiddleware.Response()) + g.Use(ginmiddleware.RequestID()) + g.Use(ginmiddleware.RequestLog(log.NewFileLogger(config.RequestLogFile()))) + g.Use(gin.Recovery()) } -func initCache(size int) *freecache.Cache { - return freecache.NewCache(size) +func (s *engine) injectRouters() { + g := s.Engine + + g.NoRoute(func(c *gin.Context) { + c.String(http.StatusNotFound, "Invalid path: %s", c.Request.URL.Path) + }) + g.HandleMethodNotAllowed = true + g.NoMethod(func(c *gin.Context) { + c.String(http.StatusMethodNotAllowed, "Method not allowed: %s %s", c.Request.Method, c.Request.URL.Path) + }) + + apiRouters := g.Group("") + s.injectRouterGroup(apiRouters) + + s.Engine = g } diff --git a/pkg/microservice/systemconfig/server/server.go b/pkg/microservice/systemconfig/server/server.go new file mode 100644 index 0000000000000000000000000000000000000000..cd8efc7a548dcf0ab1648b15cec61c42a89dd0cc --- /dev/null +++ b/pkg/microservice/systemconfig/server/server.go @@ -0,0 +1,60 @@ +/* +Copyright 2021 The KodeRover 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 server + +import ( + "context" + "net/http" + "time" + + "github.com/koderover/zadig/pkg/microservice/systemconfig/core" + "github.com/koderover/zadig/pkg/microservice/systemconfig/server/rest" + "github.com/koderover/zadig/pkg/tool/log" +) + +func Serve(ctx context.Context) error { + core.Start(ctx) + defer core.Stop(ctx) + + log.Info("Start system config service") + + engine := rest.NewEngine() + server := &http.Server{Addr: ":80", Handler: engine} + + stopChan := make(chan struct{}) + go func() { + defer close(stopChan) + + <-ctx.Done() + + ctx, cancel := context.WithTimeout(context.TODO(), 5*time.Second) + defer cancel() + + if err := server.Shutdown(ctx); err != nil { + log.Errorf("Failed to stop server, error: %s", err) + } + }() + + if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { + log.Errorf("Failed to start http server, error: %s", err) + return err + } + + <-stopChan + + return nil +} diff --git a/pkg/microservice/cron/core/service/client/workflow_test.go b/pkg/microservice/user/config/config.go similarity index 47% rename from pkg/microservice/cron/core/service/client/workflow_test.go rename to pkg/microservice/user/config/config.go index 434dfc7a98e8f7dafafe0f435c643d9edd670388..3ca77a217f32256ddac6f7ce38304fe454aa6444 100644 --- a/pkg/microservice/cron/core/service/client/workflow_test.go +++ b/pkg/microservice/user/config/config.go @@ -14,29 +14,45 @@ See the License for the specific language governing permissions and limitations under the License. */ -package client +package config import ( - "fmt" - "testing" + "strings" - "github.com/stretchr/testify/assert" + "github.com/spf13/viper" + _ "github.com/koderover/zadig/pkg/config" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/tool/log" ) -const ( - testAPIHost = "os.koderover.com" - testAPIToken = "token" -) +func init() { + viper.SetDefault(setting.ENVUserPort, "80") +} + +func IssuerURL() string { + return viper.GetString(setting.ENVIssuerURL) +} + +func ClientID() string { + return viper.GetString(setting.ENVClientID) +} + +func ClientSecret() string { + return viper.GetString(setting.ENVClientSecret) +} + +func RedirectURI() string { + return viper.GetString(setting.ENVRedirectURI) +} + +func Scopes() []string { + return strings.Split(viper.GetString(setting.ENVScopes), ",") +} + +func MysqlUserDB() string { + return viper.GetString(setting.ENVMysqlUserDB) +} -func TestGenListWorkFlowReq(t *testing.T) { - client := NewAslanClient( - testAPIHost, - testAPIToken, - ) - req, _ := client.genListWorkFlowReq(log.NopSugaredLogger()) - assert.Equal(t, fmt.Sprintf("%s/workflow/workflow", testAPIHost), req.URL.Path) - assert.Equal(t, fmt.Sprintf("%s %s", setting.RootAPIKey, testAPIToken), req.Header.Get(setting.AuthorizationHeader)) +func TokenExpiresAt() int { + return viper.GetInt(setting.ENVTokenExpiresAt) } diff --git a/pkg/microservice/user/config/consts.go b/pkg/microservice/user/config/consts.go new file mode 100644 index 0000000000000000000000000000000000000000..96e4e9caa60d02a82c2a28c4da4c84fbf315f917 --- /dev/null +++ b/pkg/microservice/user/config/consts.go @@ -0,0 +1,33 @@ +/* +Copyright 2021 The KodeRover 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 config + +import ( + "github.com/koderover/zadig/pkg/setting" +) + +const ( + AppState = setting.ProductName + "user" + SystemIdentityType = "system" + FeiShuEmailHost = "smtp.feishu.cn" +) + +type LoginType int + +const ( + AccountLoginType LoginType = 0 +) diff --git a/pkg/microservice/user/core/handler/login/local.go b/pkg/microservice/user/core/handler/login/local.go new file mode 100644 index 0000000000000000000000000000000000000000..458b6051db87d3e7b93cf385731404397a62c739 --- /dev/null +++ b/pkg/microservice/user/core/handler/login/local.go @@ -0,0 +1,19 @@ +package login + +import ( + "github.com/gin-gonic/gin" + + "github.com/koderover/zadig/pkg/microservice/user/core/service/login" + internalhandler "github.com/koderover/zadig/pkg/shared/handler" +) + +func LocalLogin(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + args := &login.LoginArgs{} + if err := c.ShouldBindJSON(args); err != nil { + ctx.Err = err + return + } + ctx.Resp, ctx.Err = login.LocalLogin(args, ctx.Logger) +} diff --git a/pkg/microservice/user/core/handler/login/third_party.go b/pkg/microservice/user/core/handler/login/third_party.go new file mode 100644 index 0000000000000000000000000000000000000000..c4b555a78cb1a5b2be41576c4891063dc1ea63d9 --- /dev/null +++ b/pkg/microservice/user/core/handler/login/third_party.go @@ -0,0 +1,138 @@ +package login + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "net/http" + "net/url" + "time" + + "github.com/coreos/go-oidc/v3/oidc" + "github.com/gin-gonic/gin" + "golang.org/x/oauth2" + + "github.com/koderover/zadig/pkg/microservice/user/config" + "github.com/koderover/zadig/pkg/microservice/user/core/service/login" + "github.com/koderover/zadig/pkg/microservice/user/core/service/user" + internalhandler "github.com/koderover/zadig/pkg/shared/handler" + e "github.com/koderover/zadig/pkg/tool/errors" + "github.com/koderover/zadig/pkg/tool/log" +) + +func provider() *oidc.Provider { + ctx := oidc.ClientContext(context.Background(), http.DefaultClient) + provider, err := oidc.NewProvider(ctx, config.IssuerURL()) + if err != nil { + log.Panicf(fmt.Sprintf("init provider error:%s", err)) + } + return provider +} + +func Login(c *gin.Context) { + oauth2Config := &oauth2.Config{ + ClientID: config.ClientID(), + ClientSecret: config.ClientSecret(), + Endpoint: provider().Endpoint(), + Scopes: config.Scopes(), + RedirectURL: config.RedirectURI(), + } + authCodeURL := oauth2Config.AuthCodeURL(config.AppState, oauth2.AccessTypeOffline) + c.Redirect(http.StatusSeeOther, authCodeURL) +} + +func ThirdPartyLoginEnabled(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + ctx.Resp = login.ThirdPartyLoginEnabled() +} + +func verifyAndDecode(ctx context.Context, code string) (*login.Claims, error) { + oidcCtx := oidc.ClientContext(ctx, http.DefaultClient) + oauth2Config := &oauth2.Config{ + ClientID: config.ClientID(), + ClientSecret: config.ClientSecret(), + Endpoint: provider().Endpoint(), + Scopes: nil, + RedirectURL: config.RedirectURI(), + } + var token *oauth2.Token + token, err := oauth2Config.Exchange(oidcCtx, code) + if err != nil { + return nil, e.ErrCallBackUser.AddDesc(fmt.Sprintf("failed to get token: %v", err)) + } + rawIDToken, ok := token.Extra("id_token").(string) + if !ok { + return nil, e.ErrCallBackUser.AddDesc("no id_token in token response") + } + idToken, err := provider().Verifier(&oidc.Config{ClientID: config.ClientID()}).Verify(ctx, rawIDToken) + if err != nil { + return nil, e.ErrCallBackUser.AddDesc(fmt.Sprintf("failed to verify ID token: %v", err)) + } + var claimsRaw json.RawMessage + if err := idToken.Claims(&claimsRaw); err != nil { + return nil, e.ErrCallBackUser.AddDesc(fmt.Sprintf("error decoding ID token claims: %v", err)) + } + buff := new(bytes.Buffer) + if err := json.Indent(buff, claimsRaw, "", " "); err != nil { + return nil, e.ErrCallBackUser.AddDesc(fmt.Sprintf("error indenting ID token claims: %v", err)) + } + var claims login.Claims + err = json.Unmarshal(claimsRaw, &claims) + if err != nil { + return nil, err + } + if len(claims.Name) == 0 { + claims.Name = claims.PreferredUsername + } + return &claims, nil +} + +func Callback(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + // Authorization redirect callback from OAuth2 auth flow. + if errMsg := c.Query("error"); errMsg != "" { + ctx.Err = e.ErrCallBackUser.AddDesc(errMsg) + return + } + code := c.Query("code") + if code == "" { + ctx.Err = e.ErrCallBackUser.AddDesc(fmt.Sprintf("no code in request: %q", c.Request.Form)) + return + } + if state := c.Query("state"); state != config.AppState { + ctx.Err = e.ErrCallBackUser.AddDesc(fmt.Sprintf("expected state %q got %q", config.AppState, state)) + return + } + claims, err := verifyAndDecode(c.Request.Context(), code) + if err != nil { + ctx.Err = err + return + } + + user, err := user.SyncUser(&user.SyncUserInfo{ + Account: claims.PreferredUsername, + Name: claims.Name, + Email: claims.Email, + IdentityType: claims.FederatedClaims.ConnectorId, + }, ctx.Logger) + if err != nil { + ctx.Err = err + return + } + claims.UID = user.UID + claims.StandardClaims.ExpiresAt = time.Now().Add(time.Duration(config.TokenExpiresAt()) * time.Minute).Unix() + userToken, err := login.CreateToken(claims) + if err != nil { + ctx.Err = err + return + } + v := url.Values{} + v.Add("token", userToken) + redirectUrl := "/?" + v.Encode() + c.Redirect(http.StatusSeeOther, redirectUrl) +} diff --git a/pkg/shared/poetry/team.go b/pkg/microservice/user/core/handler/router.go similarity index 36% rename from pkg/shared/poetry/team.go rename to pkg/microservice/user/core/handler/router.go index 4b7d096d3501ebf3daa99947ce36df2fa036f2d9..7e12cc50b3a7834533d22eb66eebf1dfa15e5ce5 100644 --- a/pkg/shared/poetry/team.go +++ b/pkg/microservice/user/core/handler/router.go @@ -14,48 +14,50 @@ See the License for the specific language governing permissions and limitations under the License. */ -package poetry +package handler import ( - "fmt" + "github.com/gin-gonic/gin" - "go.uber.org/zap" - - "github.com/koderover/zadig/pkg/tool/httpclient" + "github.com/koderover/zadig/pkg/microservice/user/core/handler/login" + "github.com/koderover/zadig/pkg/microservice/user/core/handler/user" ) -type Team struct { - ID int `json:"id"` - OrgID int `json:"orgId"` - Name string `json:"name"` - Desc string `json:"desc"` - IsTeamLeader bool `json:"isTeamLeader"` - Users []*UserInfo `json:"leaders"` - CreatedAt int64 `json:"created_at"` - UpdatedAt int64 `json:"updated_at"` -} +type Router struct{} -func (c *Client) ListTeams(orgID int, log *zap.SugaredLogger) ([]*Team, error) { - url := "/directory/teamss/search" - resp := make([]*Team, 0) - _, err := c.Get(url, httpclient.SetQueryParam("orgId", fmt.Sprintf("%d", orgID)), httpclient.SetResult(&resp)) +func (*Router) Inject(router *gin.RouterGroup) { + users := router.Group("") + { + users.GET("/callback", login.Callback) - if err != nil { - log.Errorf("ListTeams error: %v", err) - return nil, err - } + users.POST("/users", user.CreateUser) - return resp, nil -} + users.PUT("/users/:uid/password", user.UpdatePassword) -func (c *Client) GetTeam(teamID int) (*Team, error) { - url := fmt.Sprintf("/directory/teams/%d", teamID) - resp := new(Team) - _, err := c.Get(url, httpclient.SetResult(&resp)) + users.PUT("/users/:uid", user.UpdateUser) - if err != nil { - return nil, err - } + users.PUT("/users/:uid/personal", user.UpdatePersonalUser) + + users.GET("/users/:uid", user.GetUser) + + users.DELETE("/users/:uid", user.DeleteUser) + + users.GET("/users/:uid/personal", user.GetPersonalUser) - return resp, nil + users.POST("/users/search", user.ListUsers) + + users.POST("/users/ldap/:ldapId", user.SyncLdapUser) + + router.GET("login", login.Login) + + router.GET("login-enabled", login.ThirdPartyLoginEnabled) + + router.POST("login", login.LocalLogin) + + router.POST("signup", user.SignUp) + + router.GET("retrieve", user.Retrieve) + + router.POST("reset", user.Reset) + } } diff --git a/pkg/microservice/user/core/handler/user/user.go b/pkg/microservice/user/core/handler/user/user.go new file mode 100644 index 0000000000000000000000000000000000000000..b94787bcabaa10ee6212735dc34ac5944cbfdaf8 --- /dev/null +++ b/pkg/microservice/user/core/handler/user/user.go @@ -0,0 +1,142 @@ +package user + +import ( + "github.com/gin-gonic/gin" + + "github.com/koderover/zadig/pkg/microservice/user/config" + "github.com/koderover/zadig/pkg/microservice/user/core/service/user" + internalhandler "github.com/koderover/zadig/pkg/shared/handler" + + e "github.com/koderover/zadig/pkg/tool/errors" +) + +func SyncLdapUser(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + ldapID := c.Param("ldapId") + + ctx.Err = user.SearchAndSyncUser(ldapID, ctx.Logger) +} + +func GetUser(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + ctx.Resp, ctx.Err = user.GetUser(c.Param("uid"), ctx.Logger) +} + +func DeleteUser(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + ctx.Err = user.DeleteUserByUID(c.Param("uid"), ctx.Logger) +} + +func GetPersonalUser(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + uid := c.Param("uid") + if ctx.UserID != uid { + ctx.Err = e.ErrForbidden + return + } + ctx.Resp, ctx.Err = user.GetUser(uid, ctx.Logger) +} + +func ListUsers(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + args := &user.QueryArgs{} + if err := c.ShouldBindJSON(args); err != nil { + ctx.Err = err + return + } + if len(args.UIDs) > 0 { + ctx.Resp, ctx.Err = user.SearchUsersByUIDs(args.UIDs, ctx.Logger) + } else if len(args.Account) > 0 { + if len(args.IdentityType) == 0 { + args.IdentityType = config.SystemIdentityType + } + ctx.Resp, ctx.Err = user.SearchUserByAccount(args, ctx.Logger) + } else { + ctx.Resp, ctx.Err = user.SearchUsers(args, ctx.Logger) + } +} + +func CreateUser(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + args := &user.User{} + if err := c.ShouldBindJSON(args); err != nil { + ctx.Err = err + return + } + ctx.Resp, ctx.Err = user.CreateUser(args, ctx.Logger) +} + +func UpdateUser(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + args := &user.UpdateUserInfo{} + if err := c.ShouldBindJSON(args); err != nil { + ctx.Err = err + return + } + uid := c.Param("uid") + ctx.Err = user.UpdateUser(uid, args, ctx.Logger) +} + +func UpdatePersonalUser(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + args := &user.UpdateUserInfo{} + if err := c.ShouldBindJSON(args); err != nil { + ctx.Err = err + return + } + uid := c.Param("uid") + if ctx.UserID != uid { + ctx.Err = e.ErrForbidden + return + } + ctx.Err = user.UpdateUser(uid, args, ctx.Logger) +} + +func SignUp(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + args := &user.User{} + if err := c.ShouldBindJSON(args); err != nil { + ctx.Err = err + return + } + ctx.Resp, ctx.Err = user.CreateUser(args, ctx.Logger) +} + +func Retrieve(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + ctx.Resp, ctx.Err = user.Retrieve(c.Query("account"), ctx.Logger) +} + +func UpdatePassword(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + args := &user.Password{} + if err := c.ShouldBindJSON(args); err != nil { + ctx.Err = err + return + } + args.Uid = c.Param("uid") + ctx.Err = user.UpdatePassword(args, ctx.Logger) +} + +func Reset(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + args := &user.ResetParams{} + if err := c.ShouldBindJSON(args); err != nil { + ctx.Err = err + return + } + args.Uid = ctx.UserID + ctx.Err = user.Reset(args, ctx.Logger) +} diff --git a/pkg/microservice/user/core/repository/models/base.go b/pkg/microservice/user/core/repository/models/base.go new file mode 100644 index 0000000000000000000000000000000000000000..cf42820a39b967c6c890f2d730d96f5d99a27597 --- /dev/null +++ b/pkg/microservice/user/core/repository/models/base.go @@ -0,0 +1,6 @@ +package models + +type Model struct { + CreatedAt int64 `json:"created_at"` + UpdatedAt int64 `json:"updated_at"` +} diff --git a/pkg/microservice/user/core/repository/models/user.go b/pkg/microservice/user/core/repository/models/user.go new file mode 100644 index 0000000000000000000000000000000000000000..30862a89062196ec231ddc346bc7e1986ecf5a6b --- /dev/null +++ b/pkg/microservice/user/core/repository/models/user.go @@ -0,0 +1,16 @@ +package models + +type User struct { + Model + UID string `json:"uid"` + Name string `json:"name"` + IdentityType string `gorm:"default:'unknown'" json:"identity_type"` + Email string `json:"email"` + Phone string `json:"phone"` + Account string `json:"account"` +} + +// TableName sets the insert table name for this struct type +func (User) TableName() string { + return "user" +} diff --git a/pkg/microservice/user/core/repository/models/user_login.go b/pkg/microservice/user/core/repository/models/user_login.go new file mode 100644 index 0000000000000000000000000000000000000000..f2b84804f6ebc3088d1418918a2c41550facf3be --- /dev/null +++ b/pkg/microservice/user/core/repository/models/user_login.go @@ -0,0 +1,15 @@ +package models + +type UserLogin struct { + Model + UID string `json:"uid"` + Password string `json:"password"` + LastLoginTime int64 `json:"last_login_time"` + LoginId string `json:"login_id"` + LoginType int `json:"login_type"` +} + +// TableName sets the insert table name for this struct type +func (UserLogin) TableName() string { + return "user_login" +} diff --git a/pkg/microservice/user/core/repository/orm/user.go b/pkg/microservice/user/core/repository/orm/user.go new file mode 100644 index 0000000000000000000000000000000000000000..73aeb28350a37fa708bd5c3465e55ea73dc12734 --- /dev/null +++ b/pkg/microservice/user/core/repository/orm/user.go @@ -0,0 +1,135 @@ +package orm + +import ( + "gorm.io/gorm" + + "github.com/koderover/zadig/pkg/microservice/user/core" + "github.com/koderover/zadig/pkg/microservice/user/core/repository/models" +) + +// CreateUser create a user +func CreateUser(user *models.User, db *gorm.DB) error { + if err := db.Create(&user).Error; err != nil { + return err + } + return nil +} + +// GetUser Get a user based on email and identityType +func GetUser(account string, identityType string, db *gorm.DB) (*models.User, error) { + var user models.User + err := db.Where("account = ? and identity_type = ?", account, identityType).First(&user).Error + if err != nil && err != gorm.ErrRecordNotFound { + return nil, err + } + if err == gorm.ErrRecordNotFound { + return nil, nil + } + return &user, nil +} + +// GetUserByUid Get a user based on uid +func GetUserByUid(uid string, db *gorm.DB) (*models.User, error) { + var user models.User + err := db.Where("uid = ?", uid).First(&user).Error + if err != nil && err != gorm.ErrRecordNotFound { + return nil, err + } + if err == gorm.ErrRecordNotFound { + return nil, nil + } + return &user, nil +} + +// ListUsers gets a list of users based on paging constraints +func ListUsers(page int, perPage int, name string, db *gorm.DB) ([]models.User, error) { + var ( + users []models.User + err error + ) + + err = db.Where("name LIKE ?", "%"+name+"%").Order("account ASC").Offset((page - 1) * perPage).Limit(perPage).Find(&users).Error + + if err != nil && err != gorm.ErrRecordNotFound { + return nil, err + } + + return users, nil +} + +// ListUsersByUIDs gets a list of users based on paging constraints +func ListUsersByUIDs(uids []string, db *gorm.DB) ([]models.User, error) { + var ( + users []models.User + err error + ) + + err = db.Find(&users, "uid in ?", uids).Error + + if err != nil && err != gorm.ErrRecordNotFound { + return nil, err + } + + return users, nil +} + +// ListUsersByIdentityType gets a list of users based on identityType +func ListUsersByIdentityType(identityType string, db *gorm.DB) ([]models.User, error) { + var ( + users []models.User + err error + ) + + err = db.Find(&users, "identity_type = ?", identityType).Error + + if err != nil && err != gorm.ErrRecordNotFound { + return nil, err + } + + return users, nil +} + +// DeleteUserByUids Delete users based on uids +func DeleteUserByUids(uids []string, db *gorm.DB) error { + var user models.User + err := db.Where("uid in ?", uids).Delete(&user).Error + if err != nil { + return err + } + return nil +} + +// DeleteUserByUid Delete users based on uids +func DeleteUserByUid(uid string, db *gorm.DB) error { + var user models.User + err := db.Where("uid = ?", uid).Delete(&user).Error + if err != nil { + return err + } + return nil +} + +// GetUsersCount gets user count +func GetUsersCount(name string) (int64, error) { + var ( + users []models.User + err error + count int64 + ) + + err = core.DB.Where("name LIKE ?", "%"+name+"%").Find(&users).Count(&count).Error + + if err != nil { + return 0, err + } + + return count, nil +} + +// UpdateUser update user info +func UpdateUser(uid string, user *models.User, db *gorm.DB) error { + if err := db.Model(&models.User{}).Where("uid = ?", uid).Updates(user).Error; err != nil { + return err + } + return nil +} diff --git a/pkg/microservice/user/core/repository/orm/user_login.go b/pkg/microservice/user/core/repository/orm/user_login.go new file mode 100644 index 0000000000000000000000000000000000000000..b44af3821e38daeb5ac8b1857700c521061456d2 --- /dev/null +++ b/pkg/microservice/user/core/repository/orm/user_login.go @@ -0,0 +1,67 @@ +package orm + +import ( + "gorm.io/gorm" + + "github.com/koderover/zadig/pkg/microservice/user/config" + "github.com/koderover/zadig/pkg/microservice/user/core/repository/models" +) + +// CreateUserLogin add a userLogin record +func CreateUserLogin(userLogin *models.UserLogin, db *gorm.DB) error { + if err := db.Create(&userLogin).Error; err != nil { + return err + } + return nil +} + +// GetUserLogin Get a userLogin based on uid +func GetUserLogin(uid string, account string, loginType config.LoginType, db *gorm.DB) (*models.UserLogin, error) { + var userLogin models.UserLogin + err := db.Where("uid = ? and login_id = ? and login_type = ?", uid, account, loginType).First(&userLogin).Error + if err != nil && err != gorm.ErrRecordNotFound { + return nil, err + } + if err == gorm.ErrRecordNotFound { + return nil, nil + } + return &userLogin, nil +} + +// DeleteUserLoginByUids Delete userLogin based on uids +func DeleteUserLoginByUids(uids []string, db *gorm.DB) error { + var userLogin models.UserLogin + err := db.Where("uid in ?", uids).Delete(&userLogin).Error + if err != nil { + return err + } + return nil +} + +// DeleteUserLoginByUid Delete userLogin based on uids +func DeleteUserLoginByUid(uid string, db *gorm.DB) error { + var userLogin models.UserLogin + err := db.Where("uid = ?", uid).Delete(&userLogin).Error + if err != nil { + return err + } + return nil +} + +// ListUserLogins Get a userLogin based on uid list +func ListUserLogins(uids []string, db *gorm.DB) (*[]models.UserLogin, error) { + var userLogins []models.UserLogin + err := db.Find(&userLogins, "uid in ?", uids).Error + if err != nil { + return nil, err + } + return &userLogins, nil +} + +// UpdateUserLogin update login info +func UpdateUserLogin(uid string, userLogin *models.UserLogin, db *gorm.DB) error { + if err := db.Model(&models.UserLogin{}).Where("uid = ?", uid).Updates(userLogin).Error; err != nil { + return err + } + return nil +} diff --git a/pkg/microservice/user/core/service.go b/pkg/microservice/user/core/service.go new file mode 100644 index 0000000000000000000000000000000000000000..29d1af0c43726800c2e4bc74a6f84dc49491d9a6 --- /dev/null +++ b/pkg/microservice/user/core/service.go @@ -0,0 +1,85 @@ +/* +Copyright 2021 The KodeRover 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 core + +import ( + "context" + "database/sql" + _ "embed" + "fmt" + + _ "github.com/go-sql-driver/mysql" + "gorm.io/gorm" + + "github.com/koderover/zadig/pkg/config" + config2 "github.com/koderover/zadig/pkg/microservice/user/config" + "github.com/koderover/zadig/pkg/setting" + gormtool "github.com/koderover/zadig/pkg/tool/gorm" + "github.com/koderover/zadig/pkg/tool/log" +) + +var DB *gorm.DB + +//go:embed service/init/mysql.sql +var mysql []byte + +func initDBAndTables() { + if len(mysql) == 0 { + return + } + db, err := sql.Open("mysql", fmt.Sprintf( + "%s:%s@tcp(%s)/?charset=utf8&multiStatements=true", + config.MysqlUser(), config.MysqlPassword(), config.MysqlHost(), + )) + if err != nil { + log.Panic(err) + } + defer db.Close() + _, err = db.Exec(string(mysql)) + + if err != nil { + log.Panic(err) + } +} + +func Start(_ context.Context) { + log.Init(&log.Config{ + Level: config.LogLevel(), + Filename: config.LogFile(), + SendToFile: config.SendLogToFile(), + Development: config.Mode() != setting.ReleaseMode, + }) + + initDatabase() + DB = gormtool.DB(config2.MysqlUserDB()) +} + +func initDatabase() { + initDBAndTables() + err := gormtool.Open(config.MysqlUser(), + config.MysqlPassword(), + config.MysqlHost(), + config2.MysqlUserDB(), + ) + if err != nil { + log.Panicf("Failed to open database %s", config2.MysqlUserDB()) + } +} + +func Stop(_ context.Context) { + gormtool.Close() +} diff --git a/pkg/microservice/user/core/service/init/mysql.sql b/pkg/microservice/user/core/service/init/mysql.sql new file mode 100644 index 0000000000000000000000000000000000000000..bb77d2f9719bba822ba20012353243e91530301e --- /dev/null +++ b/pkg/microservice/user/core/service/init/mysql.sql @@ -0,0 +1,28 @@ +CREATE DATABASE IF NOT EXISTS user; +use user; +CREATE TABLE IF NOT EXISTS `user_login`( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `uid` varchar(64) NOT NULL DEFAULT '0' COMMENT '用户id', + `login_id` varchar(64) NOT NULL DEFAULT '0' COMMENT '用户登录id,如账号名', + `login_type` int(4) unsigned NOT NULL DEFAULT '0' COMMENT '登录类型,0.账号名', + `password` varchar(64) DEFAULT '' COMMENT '密码', + `last_login_time` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '最后登陆时间', + `created_at` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间', + `updated_at` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '更新时间', + UNIQUE KEY `login` (`uid`,`login_id`,`login_type`), + PRIMARY KEY (`id`), + KEY `idx_uid` (`uid`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 59 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '账号登陆表' ROW_FORMAT = Compact; + +CREATE TABLE IF NOT EXISTS `user`( + `uid` varchar(64) NOT NULL COMMENT '用户ID', + `account` varchar(32) NOT NULL DEFAULT '' COMMENT '用户账号', + `name` varchar(32) NOT NULL DEFAULT '' COMMENT '用户名', + `identity_type` varchar(32) NOT NULL DEFAULT 'unknown' COMMENT '用户来源', + `phone` varchar(16) NOT NULL DEFAULT '' COMMENT '手机号码', + `email` varchar(100) NOT NULL DEFAULT '' COMMENT '邮箱', + `created_at` int(11) unsigned NOT NULL COMMENT '创建时间', + `updated_at` int(11) unsigned NOT NULL COMMENT '修改时间', + UNIQUE KEY `account` (`account`,`identity_type`), + PRIMARY KEY (`uid`) +) ENGINE = InnoDB AUTO_INCREMENT = 59 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户信息表' ROW_FORMAT = Compact; \ No newline at end of file diff --git a/pkg/microservice/user/core/service/login/local.go b/pkg/microservice/user/core/service/login/local.go new file mode 100644 index 0000000000000000000000000000000000000000..83a8ecb5575183ddb8c34f4362461854d27cc6b4 --- /dev/null +++ b/pkg/microservice/user/core/service/login/local.go @@ -0,0 +1,92 @@ +package login + +import ( + "fmt" + "time" + + "github.com/golang-jwt/jwt" + "go.uber.org/zap" + "golang.org/x/crypto/bcrypt" + + "github.com/koderover/zadig/pkg/microservice/user/config" + "github.com/koderover/zadig/pkg/microservice/user/core" + "github.com/koderover/zadig/pkg/microservice/user/core/repository/orm" + "github.com/koderover/zadig/pkg/setting" +) + +type LoginArgs struct { + Account string `json:"account"` + Password string `json:"password"` +} + +type User struct { + Uid string `json:"uid"` + Token string `json:"token"` + Email string `json:"email"` + Phone string `json:"phone"` + Name string `json:"name"` + Account string `json:"account"` + IdentityType string `json:"identityType"` +} + +func LocalLogin(args *LoginArgs, logger *zap.SugaredLogger) (*User, error) { + user, err := orm.GetUser(args.Account, config.SystemIdentityType, core.DB) + if err != nil { + logger.Errorf("InternalLogin get user account:%s error", args.Account) + return nil, err + } + if user == nil { + return nil, fmt.Errorf("user not exist") + } + userLogin, err := orm.GetUserLogin(user.UID, args.Account, config.AccountLoginType, core.DB) + if err != nil { + logger.Errorf("LocalLogin get user:%s user login not exist, error msg:%s", args.Account, err.Error()) + return nil, err + } + if userLogin == nil { + logger.Errorf("InternalLogin user:%s user login not exist", args.Account) + return nil, fmt.Errorf("user login not exist") + } + password := []byte(args.Password) + err = bcrypt.CompareHashAndPassword([]byte(userLogin.Password), password) + if err == bcrypt.ErrMismatchedHashAndPassword { + return nil, fmt.Errorf("password is wrong") + } + if err != nil { + logger.Errorf("LocalLogin user:%s check password error, error msg:%s", args.Account, err) + return nil, fmt.Errorf("check password error, error msg:%s", err) + } + userLogin.LastLoginTime = time.Now().Unix() + err = orm.UpdateUserLogin(userLogin.UID, userLogin, core.DB) + if err != nil { + logger.Errorf("LocalLogin user:%s update user login password error, error msg:%s", args.Account, err.Error()) + return nil, err + } + token, err := CreateToken(&Claims{ + Name: user.Name, + UID: user.UID, + Email: user.Email, + PreferredUsername: user.Account, + StandardClaims: jwt.StandardClaims{ + Audience: setting.ProductName, + ExpiresAt: time.Now().Add(24 * time.Hour).Unix(), + }, + FederatedClaims: FederatedClaims{ + ConnectorId: user.IdentityType, + UserId: user.Account, + }, + }) + if err != nil { + logger.Errorf("LocalLogin user:%s create token error, error msg:%s", args.Account, err.Error()) + return nil, err + } + return &User{ + Uid: user.UID, + Token: token, + Email: user.Email, + Phone: user.Phone, + Name: user.Name, + Account: user.Account, + IdentityType: user.IdentityType, + }, nil +} diff --git a/pkg/microservice/user/core/service/login/third_party.go b/pkg/microservice/user/core/service/login/third_party.go new file mode 100644 index 0000000000000000000000000000000000000000..ba50713edf1aa309a1189a0b16c74e151cadfc75 --- /dev/null +++ b/pkg/microservice/user/core/service/login/third_party.go @@ -0,0 +1,20 @@ +package login + +import ( + "github.com/koderover/zadig/pkg/shared/client/systemconfig" + "github.com/koderover/zadig/pkg/tool/log" +) + +type enabledStatus struct { + Enabled bool `json:"enabled"` +} + +func ThirdPartyLoginEnabled() *enabledStatus { + connectors, err := systemconfig.New().ListConnectors() + if err != nil { + log.Warnf("Failed to list connectors, err: %s", err) + } + return &enabledStatus{ + Enabled: len(connectors) > 0, + } +} diff --git a/pkg/microservice/user/core/service/login/token.go b/pkg/microservice/user/core/service/login/token.go new file mode 100644 index 0000000000000000000000000000000000000000..bc24988e46570e12ec271744871b8354ec959456 --- /dev/null +++ b/pkg/microservice/user/core/service/login/token.go @@ -0,0 +1,30 @@ +package login + +import ( + "github.com/golang-jwt/jwt" + + "github.com/koderover/zadig/pkg/config" +) + +type Claims struct { + Name string `json:"name"` + Email string `json:"email"` + UID string `json:"uid"` + PreferredUsername string `json:"preferred_username"` + FederatedClaims FederatedClaims `json:"federated_claims"` + jwt.StandardClaims +} + +type FederatedClaims struct { + ConnectorId string `json:"connector_id"` + UserId string `json:"user_id"` +} + +func CreateToken(claims *Claims) (string, error) { + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + tokenString, err := token.SignedString([]byte(config.SecretKey())) + if err != nil { + return "", err + } + return tokenString, nil +} diff --git a/pkg/microservice/user/core/service/user/retrieve.html b/pkg/microservice/user/core/service/user/retrieve.html new file mode 100644 index 0000000000000000000000000000000000000000..87f024a4b8214ed32c1e94ae6e56204139255be4 --- /dev/null +++ b/pkg/microservice/user/core/service/user/retrieve.html @@ -0,0 +1,34 @@ +
+
+ + + + + + +
hi,您好
+
+
+ +
+
+

非常感谢使用 Zadig,点击下面的链接完成重置密码。

+
+
+ + + + + + + + + +
{{.Url}}
如果您不想继续完成密码重置,请忽略该邮件,链接将在5分钟之后过期!
+
+
+ +
+

本邮件由 Zadig 系统自动发出,请勿直接回复。

+

Made By Zadig Team ♥ Happy Coding.

+
\ No newline at end of file diff --git a/pkg/microservice/user/core/service/user/user.go b/pkg/microservice/user/core/service/user/user.go new file mode 100644 index 0000000000000000000000000000000000000000..f43ac7ecad121b6c67905906309c216eec588076 --- /dev/null +++ b/pkg/microservice/user/core/service/user/user.go @@ -0,0 +1,549 @@ +package user + +import ( + _ "embed" + "fmt" + "net/url" + "time" + + "github.com/dexidp/dex/connector/ldap" + ldapv3 "github.com/go-ldap/ldap/v3" + "github.com/golang-jwt/jwt" + "github.com/google/uuid" + "go.uber.org/zap" + "golang.org/x/crypto/bcrypt" + + configbase "github.com/koderover/zadig/pkg/config" + "github.com/koderover/zadig/pkg/microservice/user/config" + "github.com/koderover/zadig/pkg/microservice/user/core" + "github.com/koderover/zadig/pkg/microservice/user/core/repository/models" + "github.com/koderover/zadig/pkg/microservice/user/core/repository/orm" + "github.com/koderover/zadig/pkg/microservice/user/core/service/login" + "github.com/koderover/zadig/pkg/setting" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" + "github.com/koderover/zadig/pkg/tool/mail" +) + +type User struct { + Name string `json:"name"` + Password string `json:"password"` + Email string `json:"email"` + Account string `json:"account"` + Phone string `json:"phone,omitempty"` +} + +type UpdateUserInfo struct { + Name string `json:"name,omitempty"` + Email string `json:"email,omitempty"` + Phone string `json:"phone,omitempty"` +} + +type QueryArgs struct { + Name string `json:"name,omitempty"` + Account string `json:"account,omitempty"` + IdentityType string `json:"identity_type,omitempty"` + UIDs []string `json:"uids,omitempty"` + PerPage int `json:"per_page,omitempty"` + Page int `json:"page,omitempty"` +} + +type UserInfo struct { + LastLoginTime int64 `json:"lastLoginTime"` + Uid string `json:"uid"` + Name string `json:"name"` + IdentityType string `gorm:"default:'unknown'" json:"identity_type"` + Email string `json:"email"` + Phone string `json:"phone"` + Account string `json:"account"` +} + +type Password struct { + Uid string `json:"uid"` + OldPassword string `json:"oldPassword"` + NewPassword string `json:"newPassword"` +} + +type ResetParams struct { + Uid string `json:"uid"` + Password string `json:"password"` +} + +type UsersResp struct { + Users []UserInfo `json:"users"` + TotalCount int64 `json:"totalCount"` +} + +type SyncUserInfo struct { + Account string `json:"account"` + IdentityType string `json:"identityType"` + Name string `json:"name"` + Email string `json:"email"` +} + +type RetrieveResp struct { + Email string `json:"email"` +} + +func SearchAndSyncUser(ldapId string, logger *zap.SugaredLogger) error { + systemConfigClient := systemconfig.New() + si, err := systemConfigClient.GetLDAPConnector(ldapId) + if err != nil { + logger.Errorf("SearchAndSyncUser GetLDAPConnector error, error msg:%s", err) + return fmt.Errorf("SearchAndSyncUser GetLDAPConnector error, error msg:%s", err) + } + if si == nil || si.Config == nil { + logger.Error("can't find connector") + return fmt.Errorf("can't find connector") + } + + config := si.Config.(*ldap.Config) + l, err := ldapv3.Dial("tcp", config.Host) + if err != nil { + logger.Errorf("ldap dial host:%s error, error msg:%s", config.Host, err) + return err + } + defer l.Close() + + err = l.Bind(config.BindDN, config.BindPW) + if err != nil { + logger.Errorf("ldap bind host:%s error, error msg:%s", config.Host, err) + return err + } + + searchRequest := ldapv3.NewSearchRequest( + config.GroupSearch.BaseDN, + ldapv3.ScopeWholeSubtree, ldapv3.NeverDerefAliases, 0, 0, false, + config.GroupSearch.Filter, // The filter to apply + []string{config.GroupSearch.NameAttr, config.UserSearch.NameAttr, config.UserSearch.PreferredUsernameAttrAttr, + config.UserSearch.EmailAttr}, // A list attributes to retrieve + nil, + ) + + sr, err := l.Search(searchRequest) + if err != nil { + logger.Errorf("ldap search host:%s error, error msg:%s", config.Host, err) + return err + } + for _, entry := range sr.Entries { + account := config.UserSearch.PreferredUsernameAttrAttr + name := account + if len(config.UserSearch.NameAttr) != 0 { + name = config.UserSearch.NameAttr + } + _, err := SyncUser(&SyncUserInfo{ + Account: entry.GetAttributeValue(account), + Name: entry.GetAttributeValue(name), + Email: entry.GetAttributeValue(config.UserSearch.EmailAttr), + IdentityType: si.ID, // ldap may have not only one instance, so use id as identityType + }, logger) + if err != nil { + logger.Errorf("ldap host:%s sync user error, error msg:%s", config.Host, err) + return err + } + } + return nil +} + +func GetUser(uid string, logger *zap.SugaredLogger) (*UserInfo, error) { + user, err := orm.GetUserByUid(uid, core.DB) + if err != nil { + logger.Errorf("GetUser getUserByUid:%s error, error msg:%s", uid, err.Error()) + return nil, err + } + if user == nil { + return nil, nil + } + userLogin, err := orm.GetUserLogin(uid, user.Account, config.AccountLoginType, core.DB) + if err != nil { + logger.Errorf("GetUser GetUserLogin:%s error, error msg:%s", uid, err.Error()) + return nil, err + } + userInfo := mergeUserLogin([]models.User{*user}, []models.UserLogin{*userLogin}, logger) + return &userInfo[0], nil +} + +func SearchUserByAccount(args *QueryArgs, logger *zap.SugaredLogger) (*UsersResp, error) { + user, err := orm.GetUser(args.Account, args.IdentityType, core.DB) + if err != nil { + logger.Errorf("SearchUserByAccount GetUser By account:%s error, error msg:%s", args.Account, err.Error()) + return nil, err + } + if user == nil { + return &UsersResp{ + Users: nil, + TotalCount: 0, + }, nil + } + userLogins, err := orm.ListUserLogins([]string{user.UID}, core.DB) + if err != nil { + logger.Errorf("SearchUserByAccount ListUserLogins By uid:%s error, error msg:%s", user.UID, err.Error()) + return nil, err + } + usersInfo := mergeUserLogin([]models.User{*user}, *userLogins, logger) + return &UsersResp{ + Users: usersInfo, + TotalCount: int64(len(usersInfo)), + }, nil +} + +func SearchUsers(args *QueryArgs, logger *zap.SugaredLogger) (*UsersResp, error) { + count, err := orm.GetUsersCount(args.Name) + if err != nil { + logger.Errorf("SeachUsers GetUsersCount By name:%s error, error msg:%s", args.Name, err.Error()) + return nil, err + } + if count == 0 { + return &UsersResp{ + TotalCount: 0, + }, nil + } + + users, err := orm.ListUsers(args.Page, args.PerPage, args.Name, core.DB) + if err != nil { + logger.Errorf("SeachUsers SeachUsers By name:%s error, error msg:%s", args.Name, err.Error()) + return nil, err + } + var uids []string + for _, user := range users { + uids = append(uids, user.UID) + } + userLogins, err := orm.ListUserLogins(uids, core.DB) + if err != nil { + logger.Errorf("SeachUsers ListUserLogins By uids:%s error, error msg:%s", uids, err.Error()) + return nil, err + } + usersInfo := mergeUserLogin(users, *userLogins, logger) + return &UsersResp{ + Users: usersInfo, + TotalCount: count, + }, nil +} + +func mergeUserLogin(users []models.User, userLogins []models.UserLogin, logger *zap.SugaredLogger) []UserInfo { + userLoginMap := make(map[string]models.UserLogin) + for _, userLogin := range userLogins { + userLoginMap[userLogin.UID] = userLogin + } + var usersInfo []UserInfo + for _, user := range users { + if userLogin, ok := userLoginMap[user.UID]; ok { + usersInfo = append(usersInfo, UserInfo{ + LastLoginTime: userLogin.LastLoginTime, + Uid: user.UID, + Phone: user.Phone, + Name: user.Name, + Email: user.Email, + IdentityType: user.IdentityType, + Account: user.Account, + }) + } else { + logger.Error("user:%s login info not exist") + } + } + return usersInfo +} + +func SearchUsersByUIDs(uids []string, logger *zap.SugaredLogger) (*UsersResp, error) { + users, err := orm.ListUsersByUIDs(uids, core.DB) + if err != nil { + logger.Errorf("SearchUsersByUIDs SeachUsers By uids:%s error, error msg:%s", uids, err.Error()) + return nil, err + } + userLogins, err := orm.ListUserLogins(uids, core.DB) + if err != nil { + logger.Errorf("SearchUsersByUIDs ListUserLogins By uids:%s error, error msg:%s", uids, err.Error()) + return nil, err + } + usersInfo := mergeUserLogin(users, *userLogins, logger) + return &UsersResp{ + Users: usersInfo, + TotalCount: int64(len(usersInfo)), + }, nil +} + +func getLoginId(user *models.User, loginType config.LoginType) string { + switch loginType { + case config.AccountLoginType: + return user.Account + default: + return user.Account + } + +} + +func DeleteUserByUID(uid string, logger *zap.SugaredLogger) error { + tx := core.DB.Begin() + defer func() { + if r := recover(); r != nil { + tx.Rollback() + } + }() + err := orm.DeleteUserByUid(uid, tx) + if err != nil { + tx.Rollback() + logger.Errorf("DeleteUserByUID DeleteUserByUid :%s error, error msg:%s", uid, err.Error()) + return err + } + err = orm.DeleteUserLoginByUid(uid, tx) + if err != nil { + tx.Rollback() + logger.Errorf("DeleteUserByUID DeleteUserLoginByUid:%s error, error msg:%s", uid, err.Error()) + return err + } + return tx.Commit().Error +} + +//go:embed retrieve.html +var retrieveHemlTemplate []byte + +func Retrieve(account string, logger *zap.SugaredLogger) (*RetrieveResp, error) { + user, err := orm.GetUser(account, config.SystemIdentityType, core.DB) + if err != nil { + logger.Errorf("Retrieve GetUser:%s error, error msg:%s ", account, err) + return nil, fmt.Errorf("Retrieve GetUser:%s error, error msg:%s ", account, err) + } + if user == nil { + return nil, fmt.Errorf("user not exist") + } + if len(user.Email) == 0 { + logger.Errorf("the account:%s has not email", account) + return nil, fmt.Errorf("the account has not email") + } + + token, err := login.CreateToken(&login.Claims{ + Name: user.Name, + UID: user.UID, + Email: user.Email, + StandardClaims: jwt.StandardClaims{ + Audience: setting.ProductName, + ExpiresAt: time.Now().Add(5 * time.Minute).Unix(), + }, + FederatedClaims: login.FederatedClaims{ + UserId: user.Account, + ConnectorId: user.IdentityType, + }, + }) + if err != nil { + logger.Errorf("Retrieve user:%s create token error, error msg:%s", user.Account, err) + return nil, err + } + v := url.Values{} + v.Add("idtoken", token) + retrieveURL := configbase.SystemAddress() + "/signin?" + v.Encode() + body, err := mail.RenderEmailTemplate(retrieveURL, string(retrieveHemlTemplate)) + if err != nil { + logger.Errorf("Retrieve renderEmailTemplate error, error msg:%s ", err) + return nil, fmt.Errorf("Retrieve renderEmailTemplate error, error msg:%s ", err) + } + systemConfigClient := systemconfig.New() + email, err := systemConfigClient.GetEmailHost() + if err != nil { + logger.Errorf("Retrieve GetEmailHost error, error msg:%s", err) + return nil, fmt.Errorf("Retrieve GetEmailHost error, error msg:%s ", err) + } + err = mail.SendEmail(&mail.EmailParams{ + From: email.UserName, + To: user.Email, + Subject: "重置密码", + Host: email.Name, + UserName: email.UserName, + Password: email.Password, + Port: email.Port, + Body: body, + }) + if err != nil { + logger.Errorf("Retrieve SendEmail error, error msg:%s ", err) + return nil, err + } + return &RetrieveResp{ + Email: user.Email, + }, nil +} + +func CreateUser(args *User, logger *zap.SugaredLogger) (*models.User, error) { + uid, _ := uuid.NewUUID() + user := &models.User{ + Name: args.Name, + Email: args.Email, + IdentityType: config.SystemIdentityType, + Phone: args.Phone, + Account: args.Account, + UID: uid.String(), + } + tx := core.DB.Begin() + defer func() { + if r := recover(); r != nil { + tx.Rollback() + } + }() + err := orm.CreateUser(user, tx) + if err != nil { + tx.Rollback() + logger.Errorf("CreateUser CreateUser :%v error, error msg:%s", user, err.Error()) + return nil, err + } + hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(args.Password), bcrypt.DefaultCost) + userLogin := &models.UserLogin{ + UID: user.UID, + Password: string(hashedPassword), + LastLoginTime: 0, + LoginId: getLoginId(user, config.AccountLoginType), + LoginType: int(config.AccountLoginType), + } + err = orm.CreateUserLogin(userLogin, tx) + if err != nil { + tx.Rollback() + logger.Errorf("CreateUser CreateUserLogin:%v error, error msg:%s", user, err.Error()) + return nil, err + } + return user, tx.Commit().Error +} + +func UpdateUser(uid string, args *UpdateUserInfo, _ *zap.SugaredLogger) error { + user := &models.User{ + Name: args.Name, + Email: args.Email, + Phone: args.Phone, + } + return orm.UpdateUser(uid, user, core.DB) + +} + +func UpdatePassword(args *Password, logger *zap.SugaredLogger) error { + user, err := orm.GetUserByUid(args.Uid, core.DB) + if err != nil { + logger.Errorf("UpdatePassword GetUserByUid:%s error, error msg:%s", args.Uid, err.Error()) + return err + } + if user == nil { + return fmt.Errorf("user not exist") + } + userLogin, err := orm.GetUserLogin(user.UID, user.Account, config.AccountLoginType, core.DB) + if err != nil { + logger.Errorf("UpdatePassword GetUserLogin:%s error, error msg:%s", args.Uid, err.Error()) + return err + } + if userLogin == nil { + logger.Errorf("UpdatePassword GetUserLogin:%s not exist", args.Uid) + return fmt.Errorf("userLogin not exist") + } + password := []byte(args.OldPassword) + err = bcrypt.CompareHashAndPassword([]byte(userLogin.Password), password) + if err == bcrypt.ErrMismatchedHashAndPassword { + return fmt.Errorf("password is wrong") + } + if err != nil { + logger.Errorf("UpdatePassword CompareHashAndPassword userLogin password:%s, password:%s error,"+ + " error msg:%s", userLogin.Password, password, err.Error()) + return err + } + hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(args.NewPassword), bcrypt.DefaultCost) + userLogin = &models.UserLogin{ + UID: user.UID, + Password: string(hashedPassword), + } + err = orm.UpdateUserLogin(user.UID, userLogin, core.DB) + if err != nil { + logger.Errorf("UpdatePassword UpdateUserLogin:%v error, error msg:%s", userLogin, err.Error()) + return err + } + return nil +} + +func Reset(args *ResetParams, logger *zap.SugaredLogger) error { + user, err := orm.GetUserByUid(args.Uid, core.DB) + if err != nil { + logger.Errorf("Reset GetUserByUid:%s error, error msg:%s", args.Uid, err) + return err + } + if user == nil { + logger.Error("user not exist") + return fmt.Errorf("user not exist") + } + + hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(args.Password), bcrypt.DefaultCost) + userLogin := &models.UserLogin{ + UID: user.UID, + Password: string(hashedPassword), + } + err = orm.UpdateUserLogin(user.UID, userLogin, core.DB) + if err != nil { + logger.Errorf("UpdatePassword UpdateUserLogin:%v error, error msg:%s", userLogin, err.Error()) + return err + } + return nil +} + +func SyncUser(syncUserInfo *SyncUserInfo, logger *zap.SugaredLogger) (*models.User, error) { + user, err := orm.GetUser(syncUserInfo.Account, syncUserInfo.IdentityType, core.DB) + if err != nil { + logger.Error("SyncUser get user:%s error, error msg:%s", syncUserInfo.Account, err.Error()) + return nil, err + } + tx := core.DB.Begin() + defer func() { + if r := recover(); r != nil { + tx.Rollback() + } + }() + if user == nil { + uid, _ := uuid.NewUUID() + user = &models.User{ + UID: uid.String(), + Name: syncUserInfo.Name, + Account: syncUserInfo.Account, + Email: syncUserInfo.Email, + IdentityType: syncUserInfo.IdentityType, + } + err = orm.CreateUser(user, tx) + if err != nil { + tx.Rollback() + logger.Error("SyncUser create user:%s error, error msg:%s", syncUserInfo.Account, err.Error()) + return nil, err + } + } else { + err = orm.UpdateUser(user.UID, &models.User{ + Name: syncUserInfo.Name, + Account: syncUserInfo.Account, + Email: syncUserInfo.Email, + }, tx) + if err != nil { + tx.Rollback() + logger.Error("SyncUser update user:%s error, error msg:%s", syncUserInfo.Account, err.Error()) + return nil, err + } + } + userLogin, err := orm.GetUserLogin(user.UID, user.Account, config.AccountLoginType, tx) + if err != nil { + tx.Rollback() + logger.Error("UpdateLoginInfo get user:%s login error, error msg:%s", user.UID, err.Error()) + return nil, err + } + if userLogin != nil { + userLogin.LastLoginTime = time.Now().Unix() + err = orm.UpdateUserLogin(user.UID, userLogin, tx) + if err != nil { + tx.Rollback() + logger.Error("UpdateLoginInfo update user:%s login error, error msg:%s", user.UID, err.Error()) + return nil, err + } + } else { + err = orm.CreateUserLogin(&models.UserLogin{ + UID: user.UID, + LastLoginTime: time.Now().Unix(), + LoginId: getLoginId(user, config.AccountLoginType), + LoginType: int(config.AccountLoginType), + }, tx) + if err != nil { + tx.Rollback() + logger.Error("UpdateLoginInfo create user:%s login error, error msg:%s", user.UID, err.Error()) + return nil, err + } + } + err = tx.Commit().Error + if err != nil { + logger.Errorf("SyncUser tx commit error, error msg:%s ", err) + return nil, err + } + return user, nil +} diff --git a/pkg/microservice/user/server/rest/router.go b/pkg/microservice/user/server/rest/router.go new file mode 100644 index 0000000000000000000000000000000000000000..51139f3a6bddf883dc16c6882df6b72498b8e540 --- /dev/null +++ b/pkg/microservice/user/server/rest/router.go @@ -0,0 +1,35 @@ +/* +Copyright 2021 The KodeRover 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 rest + +import ( + "github.com/gin-gonic/gin" + + "github.com/koderover/zadig/pkg/microservice/user/core/handler" +) + +func (s *engine) injectRouterGroup(router *gin.RouterGroup) { + for _, r := range []injector{ + new(handler.Router), + } { + r.Inject(router.Group("/api/v1")) + } +} + +type injector interface { + Inject(router *gin.RouterGroup) +} diff --git a/pkg/microservice/user/server/rest/server.go b/pkg/microservice/user/server/rest/server.go new file mode 100644 index 0000000000000000000000000000000000000000..18843b0a5ead8f194d217a281527d5152e939795 --- /dev/null +++ b/pkg/microservice/user/server/rest/server.go @@ -0,0 +1,76 @@ +/* +Copyright 2021 The KodeRover 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 rest + +import ( + "net/http" + + "github.com/gin-gonic/gin" + + "github.com/koderover/zadig/pkg/config" + ginmiddleware "github.com/koderover/zadig/pkg/middleware/gin" + "github.com/koderover/zadig/pkg/tool/log" +) + +type engine struct { + *gin.Engine + + mode string +} + +func NewEngine() *engine { + s := &engine{mode: config.Mode()} + + gin.SetMode(s.mode) + + s.injectMiddlewares() + s.injectRouters() + + return s +} + +func (s *engine) injectMiddlewares() { + g := gin.New() + defer func() { + s.Engine = g + }() + + if s.mode == gin.TestMode { + return + } + g.Use(ginmiddleware.Response()) + g.Use(ginmiddleware.RequestID()) + g.Use(ginmiddleware.RequestLog(log.NewFileLogger(config.RequestLogFile()))) + g.Use(gin.Recovery()) +} + +func (s *engine) injectRouters() { + g := s.Engine + + g.NoRoute(func(c *gin.Context) { + c.String(http.StatusNotFound, "Invalid path: %s", c.Request.URL.Path) + }) + g.HandleMethodNotAllowed = true + g.NoMethod(func(c *gin.Context) { + c.String(http.StatusMethodNotAllowed, "Method not allowed: %s %s", c.Request.Method, c.Request.URL.Path) + }) + + apiRouters := g.Group("") + s.injectRouterGroup(apiRouters) + + s.Engine = g +} diff --git a/pkg/microservice/user/server/server.go b/pkg/microservice/user/server/server.go new file mode 100644 index 0000000000000000000000000000000000000000..aa0f55e5dc51bc614d6fe57f1bf620e9918011b4 --- /dev/null +++ b/pkg/microservice/user/server/server.go @@ -0,0 +1,60 @@ +/* +Copyright 2021 The KodeRover 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 server + +import ( + "context" + "net/http" + "time" + + "github.com/koderover/zadig/pkg/microservice/user/core" + "github.com/koderover/zadig/pkg/microservice/user/server/rest" + "github.com/koderover/zadig/pkg/tool/log" +) + +func Serve(ctx context.Context) error { + core.Start(ctx) + defer core.Stop(ctx) + + log.Info("Start user system service") + + engine := rest.NewEngine() + server := &http.Server{Addr: ":80", Handler: engine} + + stopChan := make(chan struct{}) + go func() { + defer close(stopChan) + + <-ctx.Done() + + ctx, cancel := context.WithTimeout(context.TODO(), 5*time.Second) + defer cancel() + + if err := server.Shutdown(ctx); err != nil { + log.Errorf("Failed to stop server, error: %s", err) + } + }() + + if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { + log.Errorf("Failed to start http server, error: %s", err) + return err + } + + <-stopChan + + return nil +} diff --git a/pkg/microservice/warpdrive/config/config.go b/pkg/microservice/warpdrive/config/config.go index 2795735f46e0997740541ee678daa26d4f6832f0..c4f31d1c093a8fa4e61d6fe91c3e039ca4724976 100644 --- a/pkg/microservice/warpdrive/config/config.go +++ b/pkg/microservice/warpdrive/config/config.go @@ -34,10 +34,6 @@ func NSQLookupAddrs() []string { return strings.Split(viper.GetString(setting.ENVNsqLookupAddrs), ",") } -func PoetryAPIRootKey() string { - return viper.GetString(setting.ENVPoetryAPIRootKey) -} - func ReleaseImageTimeout() string { return viper.GetString(setting.ReleaseImageTimeout) } diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/build.go b/pkg/microservice/warpdrive/core/service/taskplugin/build.go index 19f50df97acee82053333b07fcafc3e96f11c276..db5c7f0782755220747a2b4872f7d81f52e68a38 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/build.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/build.go @@ -29,11 +29,9 @@ import ( "k8s.io/apimachinery/pkg/util/sets" "sigs.k8s.io/controller-runtime/pkg/client" - configbase "github.com/koderover/zadig/pkg/config" "github.com/koderover/zadig/pkg/microservice/warpdrive/config" "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types/task" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/poetry" krkubeclient "github.com/koderover/zadig/pkg/tool/kube/client" "github.com/koderover/zadig/pkg/tool/kube/updater" ) @@ -181,11 +179,6 @@ func (p *BuildTaskPlugin) Run(ctx context.Context, pipelineTask *task.Task, pipe Installs: p.Task.InstallCtx, } - poetryClient := poetry.New(configbase.PoetryServiceAddress(), config.PoetryAPIRootKey()) - if fs, err := poetryClient.ListFeatures(); err == nil { - pipelineTask.Features = fs - } - if p.Task.BuildStatus == nil { p.Task.BuildStatus = &task.BuildStatus{} } diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/deploy.go b/pkg/microservice/warpdrive/core/service/taskplugin/deploy.go index 36c186a9d4109df45fba082a4ed2835f27d64990..1748ab51821a9d0fc5c6cc0b6038e9476d8601ce 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/deploy.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/deploy.go @@ -39,6 +39,7 @@ import ( "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types" "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types/task" "github.com/koderover/zadig/pkg/setting" + "github.com/koderover/zadig/pkg/shared/kube/resource" "github.com/koderover/zadig/pkg/shared/kube/wrapper" helmtool "github.com/koderover/zadig/pkg/tool/helmclient" "github.com/koderover/zadig/pkg/tool/httpclient" @@ -60,8 +61,6 @@ func InitializeDeployTaskPlugin(taskType config.TaskType) TaskPlugin { kubeClient: krkubeclient.Client(), restConfig: krkubeclient.RESTConfig(), httpClient: httpclient.New( - httpclient.SetAuthScheme(setting.RootAPIKey), - httpclient.SetAuthToken(config.PoetryAPIRootKey()), httpclient.SetHostURL(configbase.AslanServiceAddress()), ), } @@ -133,30 +132,58 @@ type EnvArgs struct { ProductName string `json:"product_name"` } -type SelectorBuilder struct { - ProductName string - GroupName string - ServiceName string - ConfigBackup string - EnvName string +type ResourceComponentSet interface { + GetName() string + GetAnnotations() map[string]string + GetContainers() []*resource.ContainerImage + GetKind() string } -const ( - // ProductLabel ... - ProductLabel = "s-product" - // GroupLabel ... - GroupLabel = "s-group" - // ServiceLabel ... - ServiceLabel = "s-service" - // ConfigBackupLabel ... - ConfigBackupLabel = "config-backup" - // NamespaceLabel - EnvNameLabel = "s-env" - // EnvName ... - UpdateBy = "update-by" - UpdateByID = "update-by-id" - UpdateTime = "update-time" -) +func RcsListFromDeployments(source []*appsv1.Deployment) []ResourceComponentSet { + rcsList := make([]ResourceComponentSet, 0, len(source)) + for _, deploy := range source { + rcsList = append(rcsList, wrapper.Deployment(deploy)) + } + return rcsList +} + +func RcsListFromStatefulSets(source []*appsv1.StatefulSet) []ResourceComponentSet { + rcsList := make([]ResourceComponentSet, 0, len(source)) + for _, sfs := range source { + rcsList = append(rcsList, wrapper.StatefulSet(sfs)) + } + return rcsList +} + +// find affected resources(deployment+statefulSet) for helm install or upgrade +// resource type: deployment statefulSet +func (p *DeployTaskPlugin) findHelmAffectedResources(namespace, serviceName string, resList []ResourceComponentSet) { + for _, res := range resList { + annotation := res.GetAnnotations() + if len(annotation) == 0 { + continue + } + // filter by services + if chartRelease, ok := annotation[setting.HelmReleaseNameAnnotation]; ok { + extractedServiceName := util.ExtraServiceName(chartRelease, namespace) + if extractedServiceName != serviceName { + continue + } + } + for _, container := range res.GetContainers() { + resolvedImageUrl := resolveImageUrl(container.Image) + if resolvedImageUrl[setting.PathSearchComponentImage] == p.Task.ContainerName { + p.Log.Infof("%s find match container.name:%s container.image:%s", res.GetKind(), container.Name, container.Image) + p.Task.ReplaceResources = append(p.Task.ReplaceResources, task.Resource{ + Kind: res.GetKind(), + Container: container.Name, + Origin: container.Image, + Name: res.GetName(), + }) + } + } + } +} func (p *DeployTaskPlugin) Run(ctx context.Context, pipelineTask *task.Task, _ *task.PipelineCtx, _ string) { var ( @@ -337,35 +364,20 @@ func (p *DeployTaskPlugin) Run(ctx context.Context, pipelineTask *task.Task, _ * helmClient helmclient.Client ) - deployments, _ := getter.ListDeployments(p.Task.Namespace, nil, p.kubeClient) - for _, deploy := range deployments { - for _, container := range deploy.Spec.Template.Spec.Containers { - if strings.Contains(container.Image, p.Task.ContainerName) { - p.Log.Infof("deployments find match container.name:%s", container.Name) - p.Task.ReplaceResources = append(p.Task.ReplaceResources, task.Resource{ - Kind: setting.Deployment, - Container: container.Name, - Origin: container.Image, - Name: deploy.Name, - }) - } - } + rcsList := make([]ResourceComponentSet, 0) + deployments, err := getter.ListDeployments(p.Task.Namespace, nil, p.kubeClient) + if err != nil { + p.Log.Errorf("failed to list deployments in namespace %s, productName %s, err %s", p.Task.Namespace, p.Task.ProductName, err) + } else { + rcsList = append(rcsList, RcsListFromDeployments(deployments)...) } - statefulSets, _ := getter.ListStatefulSets(p.Task.Namespace, nil, p.kubeClient) - for _, sts := range statefulSets { - for _, container := range sts.Spec.Template.Spec.Containers { - if strings.Contains(container.Image, p.Task.ContainerName) { - p.Log.Infof("statefulSets find match container.name:%s", container.Name) - p.Task.ReplaceResources = append(p.Task.ReplaceResources, task.Resource{ - Kind: setting.StatefulSet, - Container: container.Name, - Origin: container.Image, - Name: sts.Name, - }) - } - } + if err != nil { + p.Log.Errorf("failed to list statefulsets in namespace %s, productName %s, err %s", p.Task.Namespace, p.Task.ProductName, err) + } else { + rcsList = append(rcsList, RcsListFromStatefulSets(statefulSets)...) } + p.findHelmAffectedResources(p.Task.Namespace, p.Task.ServiceName, rcsList) p.Log.Infof("start helm deploy, productName %s serviceName %s containerName %s namespace %s", p.Task.ProductName, p.Task.ServiceName, p.Task.ContainerName, p.Task.Namespace) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/jira.go b/pkg/microservice/warpdrive/core/service/taskplugin/jira.go index f544f50e4e4176d6e792c638ca517e31c0ccc393..d14c33c516d5083c7aa153a13c0ae749117fb2c1 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/jira.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/jira.go @@ -26,12 +26,11 @@ import ( "github.com/xanzy/go-gitlab" "go.uber.org/zap" - configbase "github.com/koderover/zadig/pkg/config" "github.com/koderover/zadig/pkg/microservice/warpdrive/config" wdgithub "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/taskplugin/github" "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types/task" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/poetry" + "github.com/koderover/zadig/pkg/shared/client/systemconfig" "github.com/koderover/zadig/pkg/tool/jira" "github.com/koderover/zadig/pkg/tool/log" "github.com/koderover/zadig/pkg/util" @@ -340,8 +339,7 @@ func (p *JiraPlugin) SetEndTime() { func (p *JiraPlugin) getJiraIssue(pipelineTask *task.Task, key string) (*task.JiraIssue, error) { jiraIssue := new(task.JiraIssue) - poetryClient := poetry.New(configbase.PoetryServiceAddress(), config.PoetryAPIRootKey()) - jiraInfo, err := poetryClient.GetJiraInfo() + jiraInfo, err := systemconfig.New().GetJiraInfo() if err != nil { return nil, fmt.Errorf("getJiraInfo [%s] error: %v", key, err) } diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/security.go b/pkg/microservice/warpdrive/core/service/taskplugin/security.go index 43ac5a4ffb361a724519600db59d713b6e70add5..b03ab81ac354210f416e4612289b57ca7d847280 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/security.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/security.go @@ -29,7 +29,6 @@ import ( "github.com/koderover/zadig/pkg/microservice/warpdrive/config" "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types" "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types/task" - "github.com/koderover/zadig/pkg/setting" "github.com/koderover/zadig/pkg/tool/httpclient" ) @@ -39,8 +38,6 @@ func InitializeSecurityPlugin(taskType config.TaskType) TaskPlugin { Name: taskType, errorChan: make(chan error, 1), httpClient: httpclient.New( - httpclient.SetAuthScheme(setting.RootAPIKey), - httpclient.SetAuthToken(config.PoetryAPIRootKey()), httpclient.SetHostURL(configbase.AslanServiceAddress()), ), } diff --git a/pkg/microservice/warpdrive/core/service/types/task/build.go b/pkg/microservice/warpdrive/core/service/types/task/build.go index 5c296f7e46bf5c7d941beeaa95dd62f5e9e1d102..4d6e55c3bd28c5eff2b5d40fc6a448190385bb64 100644 --- a/pkg/microservice/warpdrive/core/service/types/task/build.go +++ b/pkg/microservice/warpdrive/core/service/types/task/build.go @@ -85,7 +85,6 @@ type Install struct { } type RegistryNamespace struct { - OrgID int `bson:"org_id" json:"org_id"` RegAddr string `bson:"reg_addr" json:"reg_addr"` RegType string `bson:"reg_type" json:"reg_type"` RegProvider string `bson:"reg_provider" json:"reg_provider"` diff --git a/pkg/microservice/warpdrive/core/service/types/task/config_payload.go b/pkg/microservice/warpdrive/core/service/types/task/config_payload.go index 0dfdbcda7f82f49f9d16b5c80ce1e48cd82776ba..3b3e6e0a8f735c0007ab176b1e5a77a135294cd3 100644 --- a/pkg/microservice/warpdrive/core/service/types/task/config_payload.go +++ b/pkg/microservice/warpdrive/core/service/types/task/config_payload.go @@ -121,13 +121,13 @@ type RegistryConfig struct { type ReleaseConfig struct { // ReaperImage sets build job image - // e.g. xxx.com/poetry-resources/reaper-plugin:1.0.0 + // e.g. xxx.com/resources/reaper-plugin:1.0.0 ReaperImage string // ReaperBinaryFile sets download url of reaper binary file in build job // e.g. http://resource.koderover.com/reaper-20201014203000 ReaperBinaryFile string // PredatorImage sets docker build image - // e.g. xxx.com/poetry-resources/predator-plugin:v0.1.0 + // e.g. xxx.com/resources/predator-plugin:v0.1.0 PredatorImage string } diff --git a/pkg/microservice/warpdrive/core/service/types/task/model.go b/pkg/microservice/warpdrive/core/service/types/task/model.go index 8c635017b9ac22ae530070314e1ad2e77545df97..d6a0d9751efdae6481adb4bc075e187a31094112 100644 --- a/pkg/microservice/warpdrive/core/service/types/task/model.go +++ b/pkg/microservice/warpdrive/core/service/types/task/model.go @@ -67,7 +67,6 @@ type Task struct { // ConfigPayload 系统配置信息 ConfigPayload *ConfigPayload `json:"config_payload,omitempty"` Error string `bson:"error,omitempty" json:"error,omitempty"` - OrgID int `bson:"org_id,omitempty" json:"org_id,omitempty"` Services [][]*ProductService `bson:"services" json:"services"` Render *RenderInfo `bson:"render" json:"render"` StorageURI string `bson:"storage_uri,omitempty" json:"storage_uri,omitempty"` diff --git a/pkg/middleware/gin/audit_log.go b/pkg/middleware/gin/audit_log.go index d4c79a4a0b9cd7c76258d02f0d1483ec7336e201..e3c1a6c0c0055af1cee4c83d8839dbb899265a5a 100644 --- a/pkg/middleware/gin/audit_log.go +++ b/pkg/middleware/gin/audit_log.go @@ -31,7 +31,7 @@ func UpdateOperationLogStatus(c *gin.Context) { if c.GetString("operationLogID") == "" { return } - err := aslan.New(config.AslanServiceAddress(), config.PoetryAPIRootKey()).UpdateAuditLog(c.GetString("operationLogID"), c.Writer.Status(), log) + err := aslan.New(config.AslanServiceAddress()).UpdateAuditLog(c.GetString("operationLogID"), c.Writer.Status(), log) if err != nil { log.Errorf("UpdateOperation err:%v", err) } diff --git a/pkg/middleware/gin/auth.go b/pkg/middleware/gin/auth.go deleted file mode 100644 index 515781639f4838789e8e5d1b73075ecc29fdf3ce..0000000000000000000000000000000000000000 --- a/pkg/middleware/gin/auth.go +++ /dev/null @@ -1,84 +0,0 @@ -/* -Copyright 2021 The KodeRover 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 gin - -import ( - "net/http" - "strings" - - "github.com/gin-gonic/gin" - - "github.com/koderover/zadig/pkg/config" - "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/poetry" - "github.com/koderover/zadig/pkg/tool/log" -) - -// Auth 返回会判断 Session 的中间件 -func Auth() gin.HandlerFunc { - return func(c *gin.Context) { - authorization := c.Request.Header.Get(setting.AuthorizationHeader) - if authorization != "" { - if strings.Contains(authorization, setting.RootAPIKey) { - token := strings.Split(authorization, " ") - if len(token) == 2 && token[1] == config.PoetryAPIRootKey() { - c.Set(setting.SessionUsername, "fake-user") - c.Set(setting.SessionUser, &poetry.UserInfo{Name: "fake-user", IsSuperUser: true, IsAdmin: true, OrganizationID: 1}) - c.Next() - return - } - } - if strings.Contains(authorization, setting.TIMERAPIKEY) { - token := strings.Split(authorization, " ") - if len(token) == 2 && token[1] == config.PoetryAPIRootKey() { - c.Set(setting.SessionUsername, "timer") - c.Set(setting.SessionUser, &poetry.UserInfo{Name: "timer", IsSuperUser: true, IsAdmin: true, OrganizationID: 1}) - c.Next() - return - } - } - if strings.Contains(authorization, setting.UserAPIKey) { - token := strings.Split(authorization, " ") - if len(token) == 2 { - userInfo, err := poetry.GetUserDetailByToken(config.PoetryServiceAddress(), token[1]) - if err != nil { - log.Errorf("get user detail err :%v", err) - c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"message": "get user detail error"}) - return - } - c.Set(setting.SessionUsername, userInfo.Name) - c.Set(setting.SessionUser, userInfo) - c.Next() - return - } - } - } else if token, err := c.Cookie("TOKEN"); err == nil { - userInfo, err := poetry.GetUserDetailByToken(config.PoetryServiceAddress(), token) - if err != nil { - log.Errorf("get user detail err :%v", err) - c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"message": "get user detail error"}) - return - } - c.Set(setting.SessionUsername, userInfo.Name) - c.Set(setting.SessionUser, userInfo) - c.Next() - return - } - - c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"message": "auth failed"}) - } -} diff --git a/pkg/middleware/gin/permission.go b/pkg/middleware/gin/permission.go deleted file mode 100644 index 8f5a690c43638de62c33ac400b5a0cc37c0486fc..0000000000000000000000000000000000000000 --- a/pkg/middleware/gin/permission.go +++ /dev/null @@ -1,190 +0,0 @@ -/* -Copyright 2021 The KodeRover 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 gin - -import ( - "fmt" - "net/http" - - "github.com/gin-gonic/gin" - "k8s.io/apimachinery/pkg/util/sets" - - "github.com/koderover/zadig/pkg/config" - "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/poetry" - "github.com/koderover/zadig/pkg/types/permission" - "github.com/koderover/zadig/pkg/util/ginzap" -) - -// RequireSuperAdminAuth require super user role -func RequireSuperAdminAuth(c *gin.Context) { - log := ginzap.WithContext(c).Sugar() - username := c.GetString(setting.SessionUsername) - user, err := authUser(username, c) - if err != nil { - log.Errorf("authUser(%s) failed, %v", username, err) - c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"message": "Authentication failed."}) - return - } - if user.IsSuperUser { - c.Next() - return - } - c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"message": "Require super user permission"}) -} - -//判断用户是否有某个权限 -func IsHavePermission(permissionUUIDs []string, paramType int) gin.HandlerFunc { - return func(c *gin.Context) { - log := ginzap.WithContext(c).Sugar() - username := c.GetString(setting.SessionUsername) - user, err := authUser(username, c) - if err != nil { - log.Errorf("authUser(%s) failed, %v", username, err) - c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"message": "Authentication failed."}) - return - } - - if user.IsSuperUser { - c.Next() - return - } - - var productName string - poetryClient := poetry.New(config.PoetryServiceAddress(), config.PoetryAPIRootKey()) - - if paramType == permission.ParamType { - productName = c.Param("name") - if productName == "" { - productName = c.Param("productName") - } - } else if paramType == permission.QueryType { - productName = c.Query("productName") - if productName == "" { - productName = c.Query("productTmpl") - } - } else if paramType == permission.ContextKeyType { - productName = c.GetString("productName") - } - - if productName == "" { - log.Errorf("productName is null") - c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"message": "Authentication failed."}) - return - } - - //其他权限 - permissionUUID := "" - if len(permissionUUIDs) == 1 { - permissionUUID = permissionUUIDs[0] - } else if len(permissionUUIDs) == 2 || len(permissionUUIDs) == 3 { - envType := c.Query("envType") - switch envType { - case setting.ProdENV: - permissionUUID = permissionUUIDs[1] - default: - permissionUUID = permissionUUIDs[0] - } - } - - //判断用户是否有操作的权限uuid - if rolePermissionMap, err := poetryClient.GetUserPermissionUUIDMap(productName, permissionUUID, user.ID, log); err == nil { - if rolePermissionMap["isContain"] { - c.Next() - return - } - } else { - c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"message": "Authentication failed."}) - return - } - - //判断用户是否有环境授权权限uuid - if roleEnvPermissions, err := poetryClient.ListEnvRolePermission(productName, "", 0, log); err == nil { - for _, roleEnvPermission := range roleEnvPermissions { - if roleEnvPermission.PermissionUUID == permissionUUID { - c.Next() - return - } - } - } else { - c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"message": "Authentication failed."}) - return - } - - if len(permissionUUIDs) == 3 { - permissionUUID = permissionUUIDs[2] - if rolePermissionMap, err := poetryClient.GetUserPermissionUUIDMap(productName, permissionUUID, user.ID, log); err == nil { - if rolePermissionMap["isContain"] { - c.Next() - return - } - } else { - c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"message": "Authentication failed."}) - return - } - } - - // 判断项目里面是否有all-users设置,以及该有的权限 - productRole, _ := poetryClient.ListRoles(productName, log) - if productRole != nil { - uuids, err := poetryClient.GetUserPermissionUUIDs(productRole.ID, productName, log) - if err != nil { - log.Errorf("GetUserPermissionUUIDs error: %v", err) - c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"message": "Authentication failed."}) - return - } - if sets.NewString(uuids...).Has(permissionUUID) { - c.Next() - return - } - } - - //判断普通用户的默认权限是否包含 - uuids, err := poetryClient.GetUserPermissionUUIDs(setting.RoleUserID, "", log) - if err != nil { - log.Errorf("GetUserPermissionUUIDs error: %v", err) - c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"message": "Authentication failed."}) - return - } - if sets.NewString(uuids...).Has(permissionUUID) { - c.Next() - return - } - - c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"message": "对不起,您没有权限访问!"}) - } -} - -func authUser(username interface{}, c *gin.Context) (*permission.User, error) { - - username, ok := username.(string) - if !ok || username == "" { - return nil, fmt.Errorf("empty user id") - } - - userInfo, isExist := c.Get(setting.SessionUser) - user := new(poetry.UserInfo) - if isExist { - user = userInfo.(*poetry.UserInfo) - } - //说明用户可能已经删除 - if user.Name == "" { - return nil, fmt.Errorf("user %s has been disabled", username) - } - - return poetry.ConvertUserInfo(user), nil -} diff --git a/pkg/setting/consts.go b/pkg/setting/consts.go index 6b98738154fd2dbfa860c90094120eb4f383c59b..c8c77099e1eeabc028896be5a1c6f56a74524008 100644 --- a/pkg/setting/consts.go +++ b/pkg/setting/consts.go @@ -28,7 +28,9 @@ const ( ENVMongoDBConnectionString = "MONGODB_CONNECTION_STRING" ENVAslanDBName = "ASLAN_DB" ENVHubAgentImage = "HUB_AGENT_IMAGE" - ENVPoetryAPIRootKey = "POETRY_API_ROOT_KEY" + ENVMysqlUser = "MYSQL_USER" + ENVMysqlPassword = "MYSQL_PASSWORD" + ENVMysqlHost = "MYSQL_HOST" // Aslan ENVPodName = "BE_POD_NAME" @@ -99,6 +101,22 @@ const ( DebugMode = "debug" ReleaseMode = "release" TestMode = "test" + + // user + ENVIssuerURL = "ISSUER_URL" + ENVClientID = "CLIENT_ID" + ENVClientSecret = "CLIENT_SECRET" + ENVRedirectURI = "REDIRECT_URI" + ENVSecretKey = "SECRET_KEY" + ENVMysqlUserDB = "MYSQL_USER_DB" + ENVScopes = "SCOPES" + ENVTokenExpiresAt = "TOKEN_EXPIRES_AT" + ENVUserPort = "USER_PORT" + + // initconfig + ENVAdminEmail = "ADMIN_EMAIL" + ENVAdminPassword = "ADMIN_PASSWORD" + PresetAccount = "admin" ) // k8s concepts @@ -254,11 +272,6 @@ const ( ) const ( - SessionUsername = "Username" - SessionUser = "User" - UserAPIKey = "X-API-KEY" - RootAPIKey = "X-ROOT-API-KEY" - TIMERAPIKEY = "X-TIMER-API-KEY" AuthorizationHeader = "Authorization" ) @@ -518,3 +531,15 @@ const ( ) const ChartTemplatesPath = "charts" + +type RoleType string + +const ( + Contributor RoleType = "contributor" + ReadOnly RoleType = "read-only" + Admin RoleType = "project-admin" + RoleBindingNameFmt string = "user:%s,role:%s,project:%s" +) + +// ModernWorkflowType 自由编排工作流 +const ModernWorkflowType = "ModernWorkflow" diff --git a/pkg/setting/types.go b/pkg/setting/types.go index dd56e0cffdc9adb805e8d6ad9c04143a15dadb82..dfec91faa4e9810deed54f93c44ca053b9908897 100644 --- a/pkg/setting/types.go +++ b/pkg/setting/types.go @@ -42,11 +42,13 @@ const ( Cron // 5 HubServer // 6 PodExec // 7 - Poetry // 8 SonarQube // 9 WarpDrive // 10 Minio // 11 OPA // 12 + Policy // 13 + Config // 14 + User // 15 ) type ServiceInfo struct { @@ -83,10 +85,6 @@ var Services = map[int]*ServiceInfo{ Name: "podexec", Port: 27000, }, - Poetry: { - Name: "poetry", - Port: 34001, - }, SonarQube: { Name: "sonarqube", Port: 80, @@ -103,4 +101,16 @@ var Services = map[int]*ServiceInfo{ Name: "opa", Port: 8181, }, + Policy: { + Name: "policy", + Port: 80, + }, + Config: { + Name: "config", + Port: 80, + }, + User: { + Name: "user", + Port: 80, + }, } diff --git a/pkg/shared/client/aslan/client.go b/pkg/shared/client/aslan/client.go index c34553ca0b1af38144523f301ac94fc8853a2978..ab453625b5092509346f4dc3b999db2a9e403ea0 100644 --- a/pkg/shared/client/aslan/client.go +++ b/pkg/shared/client/aslan/client.go @@ -17,43 +17,38 @@ limitations under the License. package aslan import ( - "github.com/koderover/zadig/pkg/setting" "github.com/koderover/zadig/pkg/tool/httpclient" ) type Client struct { *httpclient.Client - host string - token string + host string + token string external bool } -func New(host, token string) *Client { +func New(host string) *Client { c := httpclient.New( - httpclient.SetAuthScheme(setting.RootAPIKey), - httpclient.SetAuthToken(token), - httpclient.SetHostURL(host+"/api"), + httpclient.SetHostURL(host + "/api"), ) return &Client{ Client: c, host: host, - token: token, } } func NewExternal(host, token string) *Client { c := httpclient.New( - httpclient.SetAuthScheme(setting.UserAPIKey), httpclient.SetAuthToken(token), httpclient.SetHostURL(host+"/api/aslan"), ) return &Client{ - Client: c, - host: host, - token: token, + Client: c, + host: host, + token: token, external: true, } } diff --git a/pkg/shared/client/aslanx/client.go b/pkg/shared/client/aslanx/client.go index 05caf54c1d2bb3ef4c910a9097f6b2538e26d89f..0408946276a8e421077c58040d85f9a80b7e45bf 100644 --- a/pkg/shared/client/aslanx/client.go +++ b/pkg/shared/client/aslanx/client.go @@ -17,27 +17,22 @@ limitations under the License. package aslanx import ( - "github.com/koderover/zadig/pkg/setting" "github.com/koderover/zadig/pkg/tool/httpclient" ) type Client struct { *httpclient.Client - host string - token string + host string } -func New(host, token string) *Client { +func New(host string) *Client { c := httpclient.New( - httpclient.SetAuthScheme(setting.RootAPIKey), - httpclient.SetAuthToken(token), httpclient.SetHostURL(host), ) return &Client{ Client: c, host: host, - token: token, } } diff --git a/pkg/shared/poetry/auth.go b/pkg/shared/client/policy/client.go similarity index 51% rename from pkg/shared/poetry/auth.go rename to pkg/shared/client/policy/client.go index 201659581436fe6a3c99fe09bc7a558235f8d7a9..b81bce82466ecdde74d3ca1952d69f6d55e35954 100644 --- a/pkg/shared/poetry/auth.go +++ b/pkg/shared/client/policy/client.go @@ -14,30 +14,47 @@ See the License for the specific language governing permissions and limitations under the License. */ -package poetry +package policy import ( - "fmt" + "time" - "github.com/koderover/zadig/pkg/setting" + "github.com/koderover/zadig/pkg/config" "github.com/koderover/zadig/pkg/tool/httpclient" ) -type userView struct { - User *UserInfo `json:"info"` +const retryInterval = 200 * time.Millisecond + +type Client struct { + *httpclient.Client + + host string } -func GetUserDetailByToken(poetryHost, token string) (*UserInfo, error) { - url := "/directory/user/detail" +func New() *Client { + host := config.PolicyServiceAddress() - cl := httpclient.New(httpclient.SetHostURL(poetryHost)) + c := httpclient.New( + httpclient.SetHostURL(host+"/api/v1"), + httpclient.SetRetryCount(100), + httpclient.SetRetryWaitTime(retryInterval), + ) - //根据token获取用户 - userViewInfo := &userView{} - _, err := cl.Get(url, httpclient.SetHeader(setting.AuthorizationHeader, fmt.Sprintf("%s %s", setting.UserAPIKey, token)), httpclient.SetResult(userViewInfo)) - if err != nil { - return nil, err + return &Client{ + Client: c, + host: host, } +} - return userViewInfo.User, nil +func NewDefault() *Client { + host := config.PolicyServiceAddress() + + c := httpclient.New( + httpclient.SetHostURL(host + "/api/v1"), + ) + + return &Client{ + Client: c, + host: host, + } } diff --git a/pkg/shared/client/policy/policy.go b/pkg/shared/client/policy/policy.go new file mode 100644 index 0000000000000000000000000000000000000000..ae27d619466606dd3dc25230c460f80035038bb8 --- /dev/null +++ b/pkg/shared/client/policy/policy.go @@ -0,0 +1,113 @@ +package policy + +import ( + "fmt" + + "github.com/koderover/zadig/pkg/tool/httpclient" +) + +type Policy struct { + Resource string `json:"resource"` + Alias string `json:"alias"` + Description string `json:"description"` + Rules []*Rule `json:"rules"` +} + +type Rule struct { + Action string `json:"action"` + Alias string `json:"alias"` + Description string `json:"description"` + Rules []*ActionRule `json:"rules"` +} + +type ActionRule struct { + Method string `json:"method"` + Endpoint string `json:"endpoint"` +} + +type RoleBinding struct { + Name string `json:"name"` + UID string `json:"uid"` + Role string `json:"role"` + Public bool `json:"public"` +} + +func (c *Client) CreateOrUpdatePolicy(p *Policy) error { + url := fmt.Sprintf("/policies/%s", p.Resource) + + _, err := c.Put(url, httpclient.SetBody(p)) + + return err +} + +func (c *Client) ListRoleBindings(projectName string) ([]*RoleBinding, error) { + url := fmt.Sprintf("/rolebindings?projectName=%s", projectName) + + res := make([]*RoleBinding, 0) + _, err := c.Get(url, httpclient.SetResult(&res)) + + return res, err +} + +func (c *Client) CreateOrUpdateRoleBinding(projectName string, roleBinding *RoleBinding) error { + url := fmt.Sprintf("/rolebindings/%s?projectName=%s", roleBinding.Name, projectName) + _, err := c.Put(url, httpclient.SetBody(roleBinding)) + return err +} + +func (c *Client) CreateOrUpdateSystemRoleBinding(roleBinding *RoleBinding) error { + url := fmt.Sprintf("/system-rolebindings/%s", roleBinding.Name) + _, err := c.Put(url, httpclient.SetBody(roleBinding)) + return err +} + +func (c *Client) DeleteRoleBinding(name string, projectName string) error { + url := fmt.Sprintf("/rolebindings/%s?projectName=%s", name, projectName) + _, err := c.Delete(url) + return err +} + +type NameArgs struct { + Names []string `json:"names"` +} + +func (c *Client) DeleteRoleBindings(names []string, projectName string) error { + url := fmt.Sprintf("/rolebindings/bulk-delete?projectName=%s", projectName) + nameArgs := &NameArgs{} + for _, v := range names { + nameArgs.Names = append(nameArgs.Names, v) + } + _, err := c.Post(url, httpclient.SetBody(nameArgs)) + return err +} + +func (c *Client) DeleteRoles(names []string, projectName string) error { + url := fmt.Sprintf("/roles/bulk-delete?projectName=%s", projectName) + nameArgs := &NameArgs{} + for _, v := range names { + nameArgs.Names = append(nameArgs.Names, v) + } + _, err := c.Post(url, httpclient.SetBody(nameArgs)) + return err +} + +func (c *Client) CreateSystemRole(name string, role *Role) error { + url := fmt.Sprintf("/system-roles/%s", name) + _, err := c.Put(url, httpclient.SetBody(role)) + return err +} + +func (c *Client) CreatePublicRole(name string, role *Role) error { + url := fmt.Sprintf("/public-roles/%s", name) + _, err := c.Put(url, httpclient.SetBody(role)) + return err +} + +type Role struct { + Name string `json:"name"` + Rules []*struct { + Verbs []string `json:"verbs"` + Resources []string `json:"resources"` + Kind string `json:"kind"` + } `json:"rules"` +} diff --git a/pkg/shared/poetry/permission.go b/pkg/shared/client/systemconfig/client.go similarity index 61% rename from pkg/shared/poetry/permission.go rename to pkg/shared/client/systemconfig/client.go index c0f1d0793c17778fe2d49fac2520e7126b55eacc..cc9052c52bd4843ed7fc010cbc520bda346e39aa 100644 --- a/pkg/shared/poetry/permission.go +++ b/pkg/shared/client/systemconfig/client.go @@ -14,23 +14,27 @@ See the License for the specific language governing permissions and limitations under the License. */ -package poetry +package systemconfig import ( + "github.com/koderover/zadig/pkg/config" "github.com/koderover/zadig/pkg/tool/httpclient" ) -type UserEnvPermission struct { - UserID int `json:"userId"` - ProductName string `json:"productName"` - EnvName string `json:"envName"` - PermissionUUIDs []string `json:"permissionUUIDs"` -} +type Client struct { + *httpclient.Client -func (c *Client) CreateUserEnvPermission(p *UserEnvPermission) error { - url := "/directory/userEnvPermission" - _, err := c.Post(url, httpclient.SetBody(p)) + host string +} - return err +func New() *Client { + host := config.ConfigServiceAddress() + c := httpclient.New( + httpclient.SetHostURL(host + "/api/v1"), + ) + return &Client{ + Client: c, + host: host, + } } diff --git a/pkg/shared/poetry/codehost.go b/pkg/shared/client/systemconfig/codehost.go similarity index 30% rename from pkg/shared/poetry/codehost.go rename to pkg/shared/client/systemconfig/codehost.go index add22aa37316ce78c9dc8f5c815c5145a041f234..733fcf0bc316f7d38993387ae2a48897ffd77b05 100644 --- a/pkg/shared/poetry/codehost.go +++ b/pkg/shared/client/systemconfig/codehost.go @@ -1,28 +1,20 @@ -/* -Copyright 2021 The KodeRover 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 poetry +package systemconfig import ( + "fmt" + "github.com/koderover/zadig/pkg/tool/httpclient" ) +const ( + GitLabProvider = "gitlab" + GitHubProvider = "github" + GerritProvider = "gerrit" + CodeHubProvider = "codehub" +) + type CodeHost struct { ID int `json:"id"` - OrgID int `json:"orgId"` Address string `json:"address"` Type string `json:"type"` AccessToken string `json:"accessToken"` @@ -34,14 +26,62 @@ type CodeHost struct { Password string `json:"password"` } +type Option struct { + CodeHostType string + Address string + Namespace string + CodeHostID int +} + +func GetCodeHostInfo(opt *Option) (*CodeHost, error) { + return New().GetCodeHostByAddressAndOwner(opt.Address, opt.Namespace, opt.CodeHostType) +} + +func (c *Client) GetCodeHost(id int) (*CodeHost, error) { + url := fmt.Sprintf("/codehosts/%d", id) + + res := &CodeHost{} + _, err := c.Get(url, httpclient.SetResult(res)) + if err != nil { + return nil, err + } + + return res, nil +} + func (c *Client) ListCodeHosts() ([]*CodeHost, error) { - url := "/directory/codehostss/search" + url := "/codehosts" - codeHosts := make([]*CodeHost, 0) - _, err := c.Get(url, httpclient.SetResult(&codeHosts), httpclient.SetQueryParam("orgId", "1")) + res := make([]*CodeHost, 0) + _, err := c.Get(url, httpclient.SetResult(&res)) if err != nil { return nil, err } - return codeHosts, nil + return res, nil +} + +func (c *Client) GetCodeHostByAddressAndOwner(address, owner, source string) (*CodeHost, error) { + url := "/codehosts" + + res := make([]*CodeHost, 0) + + req := map[string]string{ + "address": address, + "owner": owner, + "source": source, + } + + _, err := c.Get(url, httpclient.SetQueryParams(req), httpclient.SetResult(&res)) + if err != nil { + return nil, err + } + + if len(res) == 0 { + return nil, fmt.Errorf("no codehost found") + } else if len(res) > 1 { + return nil, fmt.Errorf("more than one codehosts found") + } + + return res[0], nil } diff --git a/pkg/shared/client/systemconfig/connector.go b/pkg/shared/client/systemconfig/connector.go new file mode 100644 index 0000000000000000000000000000000000000000..ad1359ffba2ae2c964af1a8505575d877370306f --- /dev/null +++ b/pkg/shared/client/systemconfig/connector.go @@ -0,0 +1,52 @@ +package systemconfig + +import ( + "encoding/json" + + "github.com/dexidp/dex/connector/ldap" + + "github.com/koderover/zadig/pkg/tool/httpclient" +) + +type Connector struct { + Type string `json:"type"` + ID string `json:"id"` + Name string `json:"name"` + Config interface{} `json:"config"` +} + +func (c *Client) GetLDAPConnector(id string) (*Connector, error) { + url := "/connectors/" + id + + res := &Connector{} + _, err := c.Get(url, httpclient.SetResult(res)) + if err != nil { + return nil, err + } + + configData, err := json.Marshal(res.Config) + if err != nil { + return nil, err + } + + ldapConfig := &ldap.Config{} + if err = json.Unmarshal(configData, ldapConfig); err != nil { + return nil, err + } + + res.Config = ldapConfig + + return res, err +} + +func (c *Client) ListConnectors() ([]*Connector, error) { + url := "/connectors" + + res := make([]*Connector, 0) + _, err := c.Get(url, httpclient.SetResult(&res)) + if err != nil { + return nil, err + } + + return res, err +} diff --git a/pkg/shared/client/systemconfig/email.go b/pkg/shared/client/systemconfig/email.go new file mode 100644 index 0000000000000000000000000000000000000000..721894144e8af8ffec9f758d3c30fe6a4133965b --- /dev/null +++ b/pkg/shared/client/systemconfig/email.go @@ -0,0 +1,24 @@ +package systemconfig + +import ( + "github.com/koderover/zadig/pkg/tool/httpclient" +) + +type Email struct { + Name string `json:"name"` + Port int `json:"port"` + UserName string `json:"username"` + Password string `json:"password"` +} + +func (c *Client) GetEmailHost() (*Email, error) { + url := "/emails/internal/host/" + + res := &Email{} + _, err := c.Get(url, httpclient.SetResult(res)) + if err != nil { + return nil, err + } + + return res, err +} diff --git a/pkg/shared/poetry/jira.go b/pkg/shared/client/systemconfig/jira.go similarity index 78% rename from pkg/shared/poetry/jira.go rename to pkg/shared/client/systemconfig/jira.go index 88fd8d7233c4f321a013d87e33270e9e11f37302..fb2698b80fef8b544704eb66ad13dce13c86bca3 100644 --- a/pkg/shared/poetry/jira.go +++ b/pkg/shared/client/systemconfig/jira.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package poetry +package systemconfig import ( "github.com/koderover/zadig/pkg/tool/httpclient" @@ -24,25 +24,20 @@ type JiraInfo struct { ID int64 `json:"id"` Host string `json:"host"` User string `json:"user"` - AccessToken string `json:"accessToken"` + AccessToken string `json:"access_token"` OrganizationID int `json:"organizationId"` CreatedAt int64 `json:"created_at"` UpdatedAt int64 `json:"updated_at"` } func (c *Client) GetJiraInfo() (*JiraInfo, error) { - url := "/directory/jira" + url := "/jira" jira := &JiraInfo{} - _, err := c.Get(url, httpclient.SetResult(jira), httpclient.SetQueryParam("orgId", "1")) + _, err := c.Get(url, httpclient.SetResult(jira)) if err != nil { return nil, err } return jira, nil } - -func GetJiraInfo(host, token string) (*JiraInfo, error) { - c := New(host, token) - return c.GetJiraInfo() -} diff --git a/pkg/shared/poetry/client.go b/pkg/shared/client/user/client.go similarity index 68% rename from pkg/shared/poetry/client.go rename to pkg/shared/client/user/client.go index 323db52acca20ac858ccd0856038e390009d26ea..5e6d8ac15e89bad3c8d9917c9d714db7b45001be 100644 --- a/pkg/shared/poetry/client.go +++ b/pkg/shared/client/user/client.go @@ -14,36 +14,28 @@ See the License for the specific language governing permissions and limitations under the License. */ -package poetry +package user import ( - "github.com/koderover/zadig/pkg/setting" + "github.com/koderover/zadig/pkg/config" "github.com/koderover/zadig/pkg/tool/httpclient" ) -const ( - GitLabProvider = "gitlab" - GitHubProvider = "github" - GerritProvider = "gerrit" -) - type Client struct { *httpclient.Client - host string - token string + host string } -func New(host, token string) *Client { +func New() *Client { + host := config.UserServiceAddress() + c := httpclient.New( - httpclient.SetAuthScheme(setting.RootAPIKey), - httpclient.SetAuthToken(token), - httpclient.SetHostURL(host), + httpclient.SetHostURL(host + "/api/v1"), ) return &Client{ Client: c, host: host, - token: token, } } diff --git a/pkg/shared/client/user/user.go b/pkg/shared/client/user/user.go new file mode 100644 index 0000000000000000000000000000000000000000..d51c371cd968b0efd9e2ff8b4edfe284f8d06e51 --- /dev/null +++ b/pkg/shared/client/user/user.go @@ -0,0 +1,71 @@ +package user + +import ( + "github.com/koderover/zadig/pkg/tool/httpclient" +) + +type User struct { + UID string `json:"uid"` + Name string `json:"name"` + Email string `json:"email"` + Phone string `json:"phone"` + IdentityType string `json:"identity_type"` + Account string `json:"account"` +} + +type usersResp struct { + Users []*User `json:"users"` +} + +type SearchArgs struct { + UIDs []string `json:"uids"` +} + +func (c *Client) ListUsers(args *SearchArgs) ([]*User, error) { + url := "/users/search" + + res := &usersResp{} + _, err := c.Post(url, httpclient.SetResult(res), httpclient.SetBody(args)) + if err != nil { + return nil, err + } + + return res.Users, err +} + +type CreateUserArgs struct { + Name string `json:"name"` + Password string `json:"password"` + Email string `json:"email"` + Phone string `json:"phone"` + Account string `json:"account"` +} + +type CreateUserResp struct { + Name string `json:"name"` + Account string `json:"account"` + Uid string `json:"uid"` +} + +func (c *Client) CreateUser(args *CreateUserArgs) (*CreateUserResp, error) { + url := "/users" + resp := &CreateUserResp{} + _, err := c.Post(url, httpclient.SetBody(args), httpclient.SetResult(resp)) + return resp, err +} + +type SearchUserArgs struct { + Account string `json:"account"` +} + +type SearchUserResp struct { + TotalCount int `json:"totalCount"` + Users []*User `json:"users"` +} + +func (c *Client) SearchUser(args *SearchUserArgs) (*SearchUserResp, error) { + url := "/users/search" + resp := &SearchUserResp{} + _, err := c.Post(url, httpclient.SetBody(args), httpclient.SetResult(resp)) + return resp, err +} diff --git a/pkg/shared/codehost/codehost.go b/pkg/shared/codehost/codehost.go deleted file mode 100644 index c3d0cfa0052e62a3d4fb20075d3632c2426834c4..0000000000000000000000000000000000000000 --- a/pkg/shared/codehost/codehost.go +++ /dev/null @@ -1,147 +0,0 @@ -/* -Copyright 2021 The KodeRover 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 codehost - -import ( - "errors" - "strings" - - "github.com/koderover/zadig/pkg/config" - "github.com/koderover/zadig/pkg/shared/poetry" -) - -const ( - GitLabProvider = "gitlab" - GitHubProvider = "github" - GerritProvider = "gerrit" - CodeHubProvider = "codehub" -) - -type CodeHost struct { - ID int `json:"id"` - OrgID int `json:"orgId"` - Address string `json:"address"` - Type string `json:"type"` - AccessToken string `json:"accessToken"` - Namespace string `json:"namespace"` -} - -type Option struct { - CodeHostType string - Address string - Namespace string - CodeHostID int -} - -type Detail struct { - ID int `json:"id"` - Name string `json:"name"` - Address string `json:"address"` - Owner string `json:"repoowner"` - Source string `json:"source"` - OauthToken string `json:"oauth_token"` - Region string `json:"region"` - Username string `json:"username"` - Password string `json:"password"` - AccessKey string `json:"applicationId"` - SecretKey string `json:"clientSecret"` -} - -func GetCodeHostList() ([]*poetry.CodeHost, error) { - poetryClient := poetry.New(config.PoetryServiceAddress(), config.PoetryAPIRootKey()) - return poetryClient.ListCodeHosts() -} - -func GetCodeHostInfo(option *Option) (*poetry.CodeHost, error) { - codeHosts, err := GetCodeHostList() - if err != nil { - return nil, err - } - - for _, codeHost := range codeHosts { - if option.CodeHostID != 0 && codeHost.ID == option.CodeHostID { - return codeHost, nil - } else if option.CodeHostID == 0 && option.CodeHostType != "" { - switch option.CodeHostType { - case GitHubProvider: - ns := strings.ToLower(codeHost.Namespace) - if strings.Contains(option.Address, codeHost.Address) && strings.ToLower(option.Namespace) == ns { - return codeHost, nil - } - default: - if strings.Contains(option.Address, codeHost.Address) { - return codeHost, nil - } - } - } - } - - return nil, errors.New("not find codeHost") -} - -func GetCodeHostInfoByID(id int) (*poetry.CodeHost, error) { - return GetCodeHostInfo(&Option{CodeHostID: id}) -} - -func GetCodehostDetail(codehostID int) (*Detail, error) { - codehost, err := GetCodeHostInfo(&Option{CodeHostID: codehostID}) - if err != nil { - return nil, err - } - detail := &Detail{ - codehostID, - "", - codehost.Address, - codehost.Namespace, - codehost.Type, - codehost.AccessToken, - codehost.Region, - codehost.Username, - codehost.Password, - codehost.AccessKey, - codehost.SecretKey, - } - - return detail, nil -} - -func ListCodehostDetial() ([]*Detail, error) { - codehosts, err := GetCodeHostList() - if err != nil { - return nil, err - } - - var details []*Detail - - for _, codehost := range codehosts { - details = append(details, &Detail{ - codehost.ID, - "", - codehost.Address, - codehost.Namespace, - codehost.Type, - codehost.AccessToken, - codehost.Region, - codehost.Username, - codehost.Password, - codehost.AccessKey, - codehost.SecretKey, - }) - } - - return details, nil -} diff --git a/pkg/shared/config/client.go b/pkg/shared/config/client.go new file mode 100644 index 0000000000000000000000000000000000000000..07eeb4b25c56a4a89bbcab57bb281f4838002b9b --- /dev/null +++ b/pkg/shared/config/client.go @@ -0,0 +1,22 @@ +package config + +import ( + "github.com/koderover/zadig/pkg/tool/httpclient" +) + +type Client struct { + *httpclient.Client + + host string +} + +func New(host string) *Client { + c := httpclient.New( + httpclient.SetHostURL(host), + ) + + return &Client{ + Client: c, + host: host, + } +} diff --git a/pkg/shared/config/features.go b/pkg/shared/config/features.go new file mode 100644 index 0000000000000000000000000000000000000000..9f542e10215729e06f6ddf58a633af10eeccb7ed --- /dev/null +++ b/pkg/shared/config/features.go @@ -0,0 +1,24 @@ +package config + +import ( + "fmt" + + "github.com/koderover/zadig/pkg/tool/httpclient" +) + +type feature struct { + Name string `json:"name"` + Enabled bool `json:"enabled"` +} + +func (c *Client) CheckFeature(featureName string) (bool, error) { + url := fmt.Sprintf("/api/v1/features/%s", featureName) + + fs := &feature{} + _, err := c.Get(url, httpclient.SetResult(fs)) + if err != nil { + return false, err + } + + return fs.Enabled, nil +} diff --git a/pkg/shared/handler/base.go b/pkg/shared/handler/base.go index c59719d52a726f6df1d9bda42da2fbcbc7255f91..001400a61abaca1f62f8604add498b6a9c1f4be3 100644 --- a/pkg/shared/handler/base.go +++ b/pkg/shared/handler/base.go @@ -17,7 +17,11 @@ limitations under the License. package handler import ( + "encoding/base64" + "encoding/json" + "fmt" "reflect" + "strings" "github.com/gin-gonic/gin" "go.uber.org/zap" @@ -25,8 +29,6 @@ import ( "github.com/koderover/zadig/pkg/config" "github.com/koderover/zadig/pkg/setting" "github.com/koderover/zadig/pkg/shared/client/aslan" - "github.com/koderover/zadig/pkg/shared/poetry" - "github.com/koderover/zadig/pkg/types/permission" "github.com/koderover/zadig/pkg/util/ginzap" ) @@ -35,32 +37,56 @@ type Context struct { Logger *zap.SugaredLogger Err error Resp interface{} - Username string - User *permission.User + UserName string + UserID string RequestID string } +type jwtClaims struct { + Name string `json:"name"` + UID string `json:"uid"` +} + func NewContext(c *gin.Context) *Context { + logger := ginzap.WithContext(c).Sugar() + var claims jwtClaims + + token := c.GetHeader(setting.AuthorizationHeader) + if len(token) > 0 { + var err error + claims, err = getUserFromJWT(token) + if err != nil { + logger.Warnf("Failed to get user from token, err: %s", err) + } + } + return &Context{ - Username: currentUsername(c), - User: currentUser(c), + UserName: claims.Name, + UserID: claims.UID, Logger: ginzap.WithContext(c).Sugar(), RequestID: c.GetString(setting.RequestID), } } -// CurrentUser return current session user -func currentUser(c *gin.Context) *permission.User { - userInfo, isExist := c.Get(setting.SessionUser) - user, ok := userInfo.(*poetry.UserInfo) - if isExist && ok { - return poetry.ConvertUserInfo(user) +func getUserFromJWT(token string) (jwtClaims, error) { + cs := jwtClaims{} + + parts := strings.Split(token, ".") + if len(parts) != 3 { + return cs, fmt.Errorf("compact JWS format must have three parts") + } + + payload, err := base64.RawURLEncoding.DecodeString(parts[1]) + if err != nil { + return cs, err + } + + err = json.Unmarshal(payload, &cs) + if err != nil { + return cs, err } - return permission.AnonymousUser -} -func currentUsername(c *gin.Context) (username string) { - return c.GetString(setting.SessionUsername) + return cs, nil } func JSONResponse(c *gin.Context, ctx *Context) { @@ -78,7 +104,7 @@ func JSONResponse(c *gin.Context, ctx *Context) { // InsertOperationLog 插入操作日志 func InsertOperationLog(c *gin.Context, username, productName, method, function, detail, requestBody string, logger *zap.SugaredLogger) { - operationLogID, err := aslan.New(config.AslanServiceAddress(), config.PoetryAPIRootKey()).AddAuditLog(username, productName, method, function, detail, requestBody, logger) + operationLogID, err := aslan.New(config.AslanServiceAddress()).AddAuditLog(username, productName, method, function, detail, requestBody, logger) if err != nil { logger.Errorf("InsertOperation err:%v", err) } diff --git a/pkg/shared/kube/wrapper/deployment.go b/pkg/shared/kube/wrapper/deployment.go index 5cd417f7a39c2bf9446b2b7b1c0337f5fae918b5..6d0c5e79b3d7d92cc6f4387e72cf5308c8e03f55 100644 --- a/pkg/shared/kube/wrapper/deployment.go +++ b/pkg/shared/kube/wrapper/deployment.go @@ -80,3 +80,15 @@ func (w *deployment) ImageInfos() (images []string) { } return } + +func (w *deployment) GetKind() string { + return w.Kind +} + +func (w *deployment) GetContainers() []*resource.ContainerImage { + containers := make([]*resource.ContainerImage, 0, len(w.Spec.Template.Spec.Containers)) + for _, c := range w.Spec.Template.Spec.Containers { + containers = append(containers, &resource.ContainerImage{Name: c.Name, Image: c.Image}) + } + return containers +} diff --git a/pkg/shared/kube/wrapper/statefulset.go b/pkg/shared/kube/wrapper/statefulset.go index 0ae9c3332f0cdc3d59c6be9fa519a73233ab0643..7f4bb459ca6a5a77d67828a917ae6bdb93a1afec 100644 --- a/pkg/shared/kube/wrapper/statefulset.go +++ b/pkg/shared/kube/wrapper/statefulset.go @@ -80,3 +80,15 @@ func (w *statefulSet) ImageInfos() (images []string) { } return } + +func (w *statefulSet) GetKind() string { + return w.Kind +} + +func (w *statefulSet) GetContainers() []*resource.ContainerImage { + containers := make([]*resource.ContainerImage, 0, len(w.Spec.Template.Spec.Containers)) + for _, c := range w.Spec.Template.Spec.Containers { + containers = append(containers, &resource.ContainerImage{Name: c.Name, Image: c.Image}) + } + return containers +} diff --git a/pkg/shared/poetry/actions.go b/pkg/shared/poetry/actions.go deleted file mode 100644 index bca860415b0435723089d637f65301be89d611c8..0000000000000000000000000000000000000000 --- a/pkg/shared/poetry/actions.go +++ /dev/null @@ -1,156 +0,0 @@ -/* -Copyright 2021 The KodeRover 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 poetry - -import ( - "fmt" - "strconv" - - "go.uber.org/zap" - - e "github.com/koderover/zadig/pkg/tool/errors" - "github.com/koderover/zadig/pkg/tool/httpclient" -) - -func (c *Client) AddEnvRolePermission(productName, envName string, permissionUUIDs []string, roleID int, log *zap.SugaredLogger) (int, error) { - url := "/directory/roleEnv" - req := map[string]interface{}{ - "productName": productName, - "envName": envName, - "permissionUUIDs": permissionUUIDs, - "roleId": roleID, - } - - rm := &ResponseMessage{} - _, err := c.Post(url, httpclient.SetBody(req), httpclient.SetResult(rm)) - if err != nil { - log.Errorf("AddEnvRolePermission error: %v", err) - return 0, e.ErrListUsers.AddDesc(err.Error()) - } - - if rm.ResultCode == 0 { - return 1, nil - } - - return 0, e.ErrListUsers.AddDesc(fmt.Sprintf("ResultCode: %d", rm.ResultCode)) -} - -func (c *Client) DeleteEnvRolePermission(productName, envName string, log *zap.SugaredLogger) (int, error) { - url := "/directory/roleEnv" - qs := map[string]string{ - "productName": productName, - "envName": envName, - } - - rm := &ResponseMessage{} - _, err := c.Delete(url, httpclient.SetQueryParams(qs), httpclient.SetResult(rm)) - if err != nil { - log.Errorf("DeleteEnvRolePermission error: %v", err) - return 0, e.ErrListUsers.AddDesc(err.Error()) - } - - if rm.ResultCode == 0 { - return 1, nil - } - return 0, e.ErrListUsers.AddDesc(fmt.Sprintf("ResultCode: %d", rm.ResultCode)) -} - -func (c *Client) ListEnvRolePermission(productName, envName string, roleID int64, log *zap.SugaredLogger) ([]*EnvRolePermission, error) { - url := "/directory/roleEnv" - qs := map[string]string{ - "productName": productName, - "envName": envName, - "roleId": strconv.Itoa(int(roleID)), - } - - res := make([]*EnvRolePermission, 0) - _, err := c.Get(url, httpclient.SetQueryParams(qs), httpclient.SetResult(&res)) - if err != nil { - log.Errorf("GetEnvRolePermission error: %v", err) - return res, e.ErrListUsers.AddDesc(err.Error()) - } - - return res, nil -} - -func (c *Client) AddProductTeam(productName string, teamID int, userIDs []int, log *zap.SugaredLogger) (int, error) { - url := "/directory/teamProduct" - req := map[string]interface{}{ - "productName": productName, - "teamId": teamID, - "userIds": userIDs, - } - - rm := &ResponseMessage{} - _, err := c.Post(url, httpclient.SetBody(req), httpclient.SetResult(rm)) - if err != nil { - log.Errorf("AddProductTeam error: %v", err) - return 0, e.ErrCreateProductTeam.AddDesc(err.Error()) - } - - if rm.ResultCode == 0 { - return 1, nil - } - return 0, e.ErrCreateProductTeam.AddDesc(fmt.Sprintf("ResultCode: %d", rm.ResultCode)) -} - -func (c *Client) DeleteProductTeam(productName string, log *zap.SugaredLogger) error { - url := "/directory/teamProduct" - - rm := &ResponseMessage{} - _, err := c.Delete(url, httpclient.SetQueryParam("productName", productName), httpclient.SetResult(rm)) - if err != nil { - log.Errorf("DeleteProductTeam error: %v", err) - return e.ErrDeleteProductTeam.AddDesc(err.Error()) - } - if rm.ResultCode == 0 { - return nil - } - return e.ErrDeleteProductTeam.AddDesc(fmt.Sprintf("ResultCode: %d", rm.ResultCode)) -} - -func (c *Client) HasOperatePermission(productName, permissionUUID string, userID int, isSuperUser bool, log *zap.SugaredLogger) bool { - if isSuperUser { - return true - } - - res, err := c.GetUserPermissionUUIDMap(productName, permissionUUID, userID, log) - if err != nil { - return false - } - - return res["isContain"] -} - -func (c *Client) GetUserPermissionUUIDMap(productName, permissionUUID string, userID int, log *zap.SugaredLogger) (map[string]bool, error) { - url := "/directory/userPermissionRelation" - qs := map[string]string{ - "productName": productName, - "userId": strconv.Itoa(userID), - "permissionUUID": permissionUUID, - "permissionType": "2", - } - - res := make(map[string]bool) - _, err := c.Get(url, httpclient.SetQueryParams(qs), httpclient.SetResult(&res)) - if err != nil { - log.Errorf("GetUserPermissionUUIDMap error: %v", err) - return nil, err - } - - return res, nil -} diff --git a/pkg/shared/poetry/types.go b/pkg/shared/poetry/types.go deleted file mode 100644 index 3434f5004b282a06f1ec24d3fcc9153841fdad2d..0000000000000000000000000000000000000000 --- a/pkg/shared/poetry/types.go +++ /dev/null @@ -1,80 +0,0 @@ -/* -Copyright 2021 The KodeRover 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 poetry - -import "github.com/koderover/zadig/pkg/types/permission" - -const ( - ProjectOwner = 3 -) - -type User interface { - GetName() string - GetEmail() string - GetPhone() string -} - -type UserInfo struct { - ID int `json:"id"` - Name string `json:"name"` - Email string `json:"email"` - Password string `json:"password"` - Phone string `json:"phone"` - IsAdmin bool `json:"isAdmin"` - IsSuperUser bool `json:"isSuperUser"` - IsTeamLeader bool `json:"isTeamLeader"` - OrganizationID int `json:"organization_id"` - Directory string `json:"directory"` - LastLoginAt int64 `json:"lastLogin"` - CreatedAt int64 `json:"created_at"` - UpdatedAt int64 `json:"updated_at"` -} - -type ResponseMessage struct { - ResultCode int `json:"resultCode"` - ErrorMsg string `json:"errorMsg"` -} - -type EnvRolePermission struct { - ID int64 `json:"id"` - ProductName string `json:"productName"` - EnvName string `json:"envName"` - RoleID int64 `json:"roleId"` - PermissionUUID string `json:"permissionUUID"` - RoleName string `json:"roleName"` -} - -func ConvertUserInfo(userInfo *UserInfo) *permission.User { - if userInfo == nil { - return nil - } - user := new(permission.User) - user.ID = userInfo.ID - user.Name = userInfo.Name - user.Email = userInfo.Email - user.Password = userInfo.Password - user.Phone = userInfo.Phone - user.IsAdmin = userInfo.IsAdmin - user.IsSuperUser = userInfo.IsSuperUser - user.IsTeamLeader = userInfo.IsTeamLeader - user.OrganizationID = userInfo.OrganizationID - user.Directory = userInfo.Directory - user.LastLoginAt = userInfo.LastLoginAt - user.CreatedAt = userInfo.CreatedAt - user.UpdatedAt = userInfo.UpdatedAt - return user -} diff --git a/pkg/shared/poetry/user.go b/pkg/shared/poetry/user.go deleted file mode 100644 index db5d535362e73c96387c288abb1346f9c1657584..0000000000000000000000000000000000000000 --- a/pkg/shared/poetry/user.go +++ /dev/null @@ -1,418 +0,0 @@ -/* -Copyright 2021 The KodeRover 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 poetry - -import ( - "fmt" - "strconv" - "strings" - "time" - - "go.uber.org/zap" - - "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/tool/httpclient" - "github.com/koderover/zadig/pkg/types/permission" -) - -//roleType -const ( - ProjectType = 2 - AllUsersRoleName = "all-users" -) - -type UserRole struct { - RoleID int64 `json:"roleId"` - UserID int `json:"userId"` - ProductName string `json:"productName"` -} - -type RoleProduct struct { - RoleID int64 `json:"roleId"` - ProductName string `json:"productName"` - Role Role `json:"role"` -} - -type UpdateUserRoleReq struct { - ProductName string `json:"productName"` - RoleID int64 `json:"roleId"` - RoleType int `json:"roleType"` - UserIDList []int `json:"userIds"` -} - -type RolePermission struct { - RoleID int64 `json:"roleId"` - PermissionUUID string `json:"permissionUUID"` -} - -type RoleEnv struct { - RoleID int `json:"roleId"` - EnvName string `json:"envName"` - ProductName string `json:"productName"` -} - -type RolePermissionReq struct { - RoleID int64 `json:"roleId"` - PermissionUUID []string `json:"permissionUUIDs"` - RoleType int `json:"roleType"` - ProductName string `json:"productName"` -} - -type Role struct { - ID int64 `json:"id"` - IsDisabled bool `json:"isDisabled"` - Name string `json:"name"` - ProductName string `json:"productName"` - RoleType int `json:"roleType"` - UpdateBy string `json:"updateBy"` - UpdateAt int64 `json:"updatedAt"` -} - -type UserEnv struct { - ProductName string `json:"productName"` - EnvName string `json:"envName"` - UserID int `json:"userId"` - PermissionUUID string `json:"permissionUUID"` -} - -func (c *Client) ListUserRoles(userID, roleType int, log *zap.SugaredLogger) ([]*UserRole, error) { - url := "/directory/roleUser" - - ur := make([]*UserRole, 0) - _, err := c.Get(url, httpclient.SetResult(&ur), httpclient.SetQueryParam("roleType", strconv.Itoa(roleType)), httpclient.SetQueryParam("userId", strconv.Itoa(userID))) - if err != nil { - log.Errorf("ListUserRoles error: %v", err) - return nil, err - } - - return ur, nil -} - -func (c *Client) ListPermissionUsers(productName string, roleID int64, roleType int, log *zap.SugaredLogger) ([]int, error) { - url := "/directory/roleUser" - qs := map[string]string{ - "productName": productName, - "roleType": strconv.Itoa(roleType), - "roleId": strconv.Itoa(int(roleID)), - } - - ur := make([]*UserRole, 0) - _, err := c.Get(url, httpclient.SetResult(&ur), httpclient.SetQueryParams(qs)) - if err != nil { - log.Errorf("ListPermissionUsers error: %v", err) - return nil, err - } - - var ret []int - for _, userRole := range ur { - ret = append(ret, userRole.UserID) - } - return ret, nil -} - -func (c *Client) UpdateUserRole(roleID int64, roleType int, productName string, userIDList []int, log *zap.SugaredLogger) error { - url := "/directory/roleUser" - req := &UpdateUserRoleReq{ - ProductName: productName, - RoleID: roleID, - RoleType: roleType, - UserIDList: userIDList, - } - - _, err := c.Post(url, httpclient.SetBody(req)) - if err != nil { - log.Errorf("UpdateUserRole failed, error: %v", err) - return err - } - - return nil -} - -func (c *Client) DeleteUserRole(roleID int64, roleType, userID int, productName string, log *zap.SugaredLogger) error { - url := "/directory/roleUser" - qs := map[string]string{ - "productName": productName, - "roleType": strconv.Itoa(roleType), - "roleId": strconv.Itoa(int(roleID)), - "userId": strconv.Itoa(userID), - } - - _, err := c.Delete(url, httpclient.SetQueryParams(qs)) - if err != nil { - log.Errorf("DeleteUserRole error: %v", err) - return err - } - return nil -} - -func (c *Client) ListRoleProjects(roleID int64, log *zap.SugaredLogger) ([]*RoleProduct, error) { - url := "/directory/roleProduct" - - rp := make([]*RoleProduct, 0) - _, err := c.Get(url, httpclient.SetResult(&rp), httpclient.SetQueryParam("roleId", strconv.Itoa(int(roleID)))) - if err != nil { - log.Errorf("ListRoleProjects error: %v", err) - return nil, err - } - - return rp, nil -} - -func (c *Client) ContributorRoleExist(productName string, log *zap.SugaredLogger) bool { - url := "/directory/roleProduct" - - rp := make([]*RoleProduct, 0) - _, err := c.Get(url, httpclient.SetResult(&rp), httpclient.SetQueryParam("productName", productName)) - if err != nil { - log.Errorf("Failed to list role project, error: %v", err) - return false - } - - for _, roleProduct := range rp { - if roleProduct.Role.Name == setting.RoleContributor { - return true - } - } - return false -} - -func (c *Client) GetContributorRoleID(productName string, log *zap.SugaredLogger) int64 { - url := "/directory/roleProduct" - - rp := make([]*RoleProduct, 0) - _, err := c.Get(url, httpclient.SetResult(&rp), httpclient.SetQueryParam("productName", productName)) - if err != nil { - log.Errorf("Failed to list role project, sendRequest error: %v", err) - return -1 - } - - for _, roleProduct := range rp { - if roleProduct.Role.Name == setting.RoleContributor { - return roleProduct.RoleID - } - } - return -1 -} - -func (c *Client) ListRolePermissions(roleID int64, roleType int, productName string, log *zap.SugaredLogger) ([]*RolePermission, error) { - url := "/directory/rolePermission" - qs := map[string]string{ - "productName": productName, - "roleType": strconv.Itoa(roleType), - "roleId": strconv.Itoa(int(roleID)), - } - - rp := make([]*RolePermission, 0) - _, err := c.Get(url, httpclient.SetResult(&rp), httpclient.SetQueryParams(qs)) - if err != nil { - log.Errorf("ListRolePermissions error: %v", err) - return nil, err - } - - return rp, nil -} - -func (c *Client) ListRoleEnvs(productName, envName string, roleID int64, log *zap.SugaredLogger) ([]*RoleEnv, error) { - url := "/directory/roleEnv" - qs := map[string]string{ - "productName": productName, - "envName": envName, - "roleId": strconv.Itoa(int(roleID)), - } - - re := make([]*RoleEnv, 0) - _, err := c.Get(url, httpclient.SetResult(&re), httpclient.SetQueryParams(qs)) - if err != nil { - log.Errorf("ListRoleEnvs error: %v", err) - return nil, err - } - - return re, nil -} - -func (c *Client) GetUserProject(userID int, log *zap.SugaredLogger) (map[string][]int64, error) { - productNameMap := make(map[string][]int64) - userRoles, err := c.ListUserRoles(userID, ProjectType, log) - if err != nil { - log.Errorf("GetUserProject ListUserRoles error: %v", err) - return productNameMap, fmt.Errorf("GetUserProject ListUserRoles error: %v", err) - } - for _, userRole := range userRoles { - productNameMap[userRole.ProductName] = append(productNameMap[userRole.ProductName], userRole.RoleID) - } - return productNameMap, nil -} - -func (c *Client) GetUserPermissionUUIDs(roleID int64, productName string, log *zap.SugaredLogger) ([]string, error) { - permissionUUIDs := make([]string, 0) - rolePermissions, err := c.ListRolePermissions(roleID, ProjectType, productName, log) - if err != nil { - log.Errorf("GetUserPermission ListRolePermissions error: %v", err) - return []string{}, fmt.Errorf("GetUserPermission ListRolePermissions error: %v", err) - } - for _, rolePermission := range rolePermissions { - permissionUUIDs = append(permissionUUIDs, rolePermission.PermissionUUID) - } - return permissionUUIDs, nil -} - -// ListProductPermissionUsers productName和permissionId为空时只返回所有管理员用户,不为空则返回所有管理员用户和有该权限的普通用户 -func (c *Client) ListProductPermissionUsers(productName, permissionID string, log *zap.SugaredLogger) ([]string, error) { - url := "/directory/productUser" - qs := map[string]string{ - "productName": productName, - "permissionId": permissionID, - } - - resp := make([]string, 0) - _, err := c.Get(url, httpclient.SetResult(&resp), httpclient.SetQueryParams(qs)) - if err != nil { - log.Errorf("ListProductPermissionUsers error: %v", err) - return nil, err - } - - return resp, nil -} - -func (c *Client) CreateContributorRole(product string, log *zap.SugaredLogger) error { - // create role first - url := "/directory/roles" - req := &Role{ - IsDisabled: false, - Name: setting.RoleContributor, - ProductName: product, - RoleType: ProjectType, - UpdateBy: setting.SystemUser, - UpdateAt: time.Now().Unix(), - } - - r := &Role{} - _, err := c.Post(url, httpclient.SetBody(req), httpclient.SetResult(r)) - if err != nil { - log.Errorf("CreateContributorRole failed, error: %v", err) - return err - } - - // 然后创建role product - roleProductURL := "/directory/roleProduct" - roleProductReq := RoleProduct{ - RoleID: r.ID, - ProductName: product, - } - - _, err = c.Post(roleProductURL, httpclient.SetBody(roleProductReq)) - if err != nil { - log.Errorf("CreateContributorRole failed, error: %v", err) - return err - } - permissionList := []string{ - permission.WorkflowTaskUUID, - permission.WorkflowListUUID, - permission.TestEnvDeleteUUID, - permission.TestEnvManageUUID, - permission.TestEnvListUUID, - permission.TestUpdateEnvUUID, - permission.BuildListUUID, - permission.TestListUUID, - permission.ServiceTemplateListUUID, - } - permissionReq := RolePermissionReq{ - RoleID: r.ID, - RoleType: r.RoleType, - PermissionUUID: permissionList, - ProductName: product, - } - rolePermissionURL := "/directory/rolePermission" - - _, err = c.Post(rolePermissionURL, httpclient.SetBody(permissionReq)) - if err != nil { - log.Errorf("CreateContributorRole failed, error: %v", err) - return err - } - - return nil -} - -// ListRoles 根据项目里面的角色名称获取对应的角色ID -func (c *Client) ListRoles(productName string, log *zap.SugaredLogger) (*Role, error) { - url := "/directory/roles" - qs := map[string]string{ - "name": AllUsersRoleName, - "productName": productName, - "roleType": strconv.Itoa(ProjectType), - } - - resp := make([]*Role, 0) - _, err := c.Get(url, httpclient.SetResult(&resp), httpclient.SetQueryParams(qs)) - if err != nil { - log.Errorf("ListRoles error: %v", err) - return nil, err - } - - if len(resp) == 0 { - return nil, fmt.Errorf("ListRoles Not Found") - } - - return resp[0], nil -} - -func (c *Client) ListUserEnvPermission(productName string, userID int, log *zap.SugaredLogger) ([]*UserEnv, error) { - url := "/directory/userEnvPermission" - qs := map[string]string{ - "productName": productName, - "userId": strconv.Itoa(userID), - } - - resp := make([]*UserEnv, 0) - _, err := c.Get(url, httpclient.SetResult(&resp), httpclient.SetQueryParams(qs)) - if err != nil { - log.Errorf("ListUserEnvPermission error: %v", err) - return nil, err - } - - return resp, nil -} - -func (c *Client) DeleteUserEnvPermission(productName, username string, userID int, log *zap.SugaredLogger) error { - url := "/directory/userEnvPermission" - qs := map[string]string{ - "productName": productName, - "envName": strings.ToLower(username), - "userId": strconv.Itoa(userID), - } - - _, err := c.Delete(url, httpclient.SetQueryParams(qs)) - if err != nil { - log.Errorf("DeleteUserEnvPermission error: %v", err) - return err - } - - return nil -} - -func (c *Client) GetUserEnvPermission(userID int, log *zap.SugaredLogger) ([]*UserEnv, error) { - url := "/directory/userEnvPermission" - - resp := make([]*UserEnv, 0) - _, err := c.Get(url, httpclient.SetResult(&resp), httpclient.SetQueryParam("userId", strconv.Itoa(userID))) - if err != nil { - log.Errorf("UserEnvPermission request error: %v", err) - return nil, err - } - - return resp, nil -} diff --git a/pkg/tool/errors/http_errors.go b/pkg/tool/errors/http_errors.go index 740a97082ef6ad679dc1b6f8de5d541e61736a0f..45554ea7610ee1996efd9d34fa7ec6a7280409ca 100644 --- a/pkg/tool/errors/http_errors.go +++ b/pkg/tool/errors/http_errors.go @@ -44,7 +44,8 @@ var ( ErrListUsers = NewHTTPError(6002, "列出用户信息失败") // ErrFindUser ... ErrFindUser = NewHTTPError(6002, "获取用户信息失败") - + // ErrCallBackUser ... + ErrCallBackUser = NewHTTPError(6003, "dex回调用户失败") //----------------------------------------------------------------------------------------------- // Team APIs Range: 6020 - 6039 //----------------------------------------------------------------------------------------------- @@ -671,4 +672,12 @@ var ( ErrTestJenkinsConnection = NewHTTPError(6835, "用户名或者密码不正确") ErrListJobNames = NewHTTPError(6836, "获取job名称列表失败") ErrListJobBuildArgs = NewHTTPError(6837, "获取job构建参数列表失败") + + //----------------------------------------------------------------------------------------------- + // external link Error Range: 6840 - 6849 + //----------------------------------------------------------------------------------------------- + ErrCreateExternalLink = NewHTTPError(6841, "创建链接失败") + ErrUpdateExternalLink = NewHTTPError(6842, "更新链接失败") + ErrDeleteExternalLink = NewHTTPError(6843, "删除链接失败") + ErrListExternalLink = NewHTTPError(6844, "获取链接列表失败") ) diff --git a/pkg/tool/git/github/repositories.go b/pkg/tool/git/github/repositories.go index 77f4e7ce0a5e35f588464b0bee8daecc409d3bb3..5bba3419c55946611131292469e175fa41445f7c 100644 --- a/pkg/tool/git/github/repositories.go +++ b/pkg/tool/git/github/repositories.go @@ -185,11 +185,43 @@ func (c *Client) CreateHook(ctx context.Context, owner, repo string, hook *git.H Active: hook.Active, } created, err := wrap(c.Repositories.CreateHook(ctx, owner, repo, h)) - if h, ok := created.(*github.Hook); ok { - return h, err + if err != nil { + return nil, err } - return nil, err + res, ok := created.(*github.Hook) + if !ok { + return nil, fmt.Errorf("object is not a github Hook") + } + + return res, nil +} + +func (c *Client) UpdateHook(ctx context.Context, owner, repo string, id int64, hook *git.Hook) (*github.Hook, error) { + h := &github.Hook{ + Config: map[string]interface{}{ + "url": hook.URL, + "content_type": "json", + "secret": hook.Secret, + }, + } + if len(hook.Events) > 0 { + h.Events = hook.Events + } + if hook.Active != nil { + h.Active = hook.Active + } + updated, err := wrap(c.Repositories.EditHook(ctx, owner, repo, id, h)) + if err != nil { + return nil, err + } + + res, ok := updated.(*github.Hook) + if !ok { + return nil, fmt.Errorf("object is not a github Hook") + } + + return res, nil } func (c *Client) CreateStatus(ctx context.Context, owner, repo, ref string, status *github.RepoStatus) (*github.RepoStatus, error) { diff --git a/pkg/tool/git/gitlab/project.go b/pkg/tool/git/gitlab/project.go index bea1ea800bf06d42a1144be34d49e45ef9035584..36f29e0df866a8a2e1a08c7f1e1c9f8c8c5459ed 100644 --- a/pkg/tool/git/gitlab/project.go +++ b/pkg/tool/git/gitlab/project.go @@ -17,6 +17,7 @@ limitations under the License. package gitlab import ( + "fmt" "strings" "github.com/xanzy/go-gitlab" @@ -67,11 +68,34 @@ func (c *Client) AddProjectHook(owner, repo string, hook *git.Hook) (*gitlab.Pro return nil, err } - if h, ok := created.(*gitlab.ProjectHook); ok { - return h, nil + res, ok := created.(*gitlab.ProjectHook) + if !ok { + return nil, fmt.Errorf("object is not a gitlab Hook") } - return nil, err + return res, nil +} + +func (c *Client) UpdateProjectHook(owner, repo string, id int, hook *git.Hook) (*gitlab.ProjectHook, error) { + opts := &gitlab.EditProjectHookOptions{} + if hook.URL != "" { + opts.URL = gitlab.String(hook.URL) + } + if hook.Secret != "" { + opts.Token = gitlab.String(hook.Secret) + } + opts = addEventsToProjectHookEditOptions(hook.Events, opts) + updated, err := wrap(c.Projects.EditProjectHook(generateProjectName(owner, repo), id, opts)) + if err != nil { + return nil, err + } + + res, ok := updated.(*gitlab.ProjectHook) + if !ok { + return nil, fmt.Errorf("object is not a gitlab Hook") + } + + return res, nil } func (c *Client) DeleteProjectHook(owner, repo string, id int) error { @@ -140,3 +164,18 @@ func addEventsToProjectHookOptions(events []string, opts *gitlab.AddProjectHookO return opts } + +func addEventsToProjectHookEditOptions(events []string, opts *gitlab.EditProjectHookOptions) *gitlab.EditProjectHookOptions { + for _, evt := range events { + switch evt { + case git.PushEvent: + opts.PushEvents = boolptr.True() + case git.PullRequestEvent: + opts.MergeRequestsEvents = boolptr.True() + case git.BranchOrTagCreateEvent: + opts.TagPushEvents = boolptr.True() + } + } + + return opts +} diff --git a/pkg/tool/gorm/client.go b/pkg/tool/gorm/client.go new file mode 100644 index 0000000000000000000000000000000000000000..c5e65fb1058e07b48a57918c2cb30f9742f5f858 --- /dev/null +++ b/pkg/tool/gorm/client.go @@ -0,0 +1,45 @@ +package gorm + +import ( + "fmt" + + "gorm.io/driver/mysql" + "gorm.io/gorm" +) + +var connections = make(map[string]*gorm.DB) + +func getConnection(db string) *gorm.DB { + return connections[db] +} + +func Open(username, password, host, db string) error { + conn, err := openDB(username, password, host, db) + if err != nil { + return err + } + + connections[db] = conn + + return nil +} + +func DB(db string) *gorm.DB { + return getConnection(db) +} + +func Close() { + //for _, conn := range connections { + // conn.Close() + //} +} + +func openDB(username, password, host, db string) (*gorm.DB, error) { + + // refer https://github.com/go-sql-driver/mysql#dsn-data-source-name for details + dsn := fmt.Sprintf( + "%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", + username, password, host, db, + ) + return gorm.Open(mysql.Open(dsn), &gorm.Config{}) +} diff --git a/pkg/tool/httpclient/request_options.go b/pkg/tool/httpclient/request_options.go index dde8bfd67af0f78ce81960410d7965a9bb90efef..afc19279279b7fa46e59c5d1e229048bbe216696 100644 --- a/pkg/tool/httpclient/request_options.go +++ b/pkg/tool/httpclient/request_options.go @@ -17,6 +17,7 @@ limitations under the License. package httpclient import ( + "net/http" "net/url" "github.com/go-resty/resty/v2" @@ -42,6 +43,12 @@ func SetHeader(header, value string) RequestFunc { } } +func SetHeadersFromHTTPHeader(header http.Header) RequestFunc { + return func(r *resty.Request) { + r.Header = header + } +} + func SetQueryParamsFromValues(params url.Values) RequestFunc { return func(r *resty.Request) { r.SetQueryParamsFromValues(params) diff --git a/pkg/tool/mail/mail.go b/pkg/tool/mail/mail.go new file mode 100644 index 0000000000000000000000000000000000000000..ca8acdb1ee9167938fe68e5bf7d45218f6e5a6d4 --- /dev/null +++ b/pkg/tool/mail/mail.go @@ -0,0 +1,50 @@ +package mail + +import ( + "bytes" + "html/template" + + "gopkg.in/gomail.v2" +) + +type EmailParams struct { + From string + To string + Subject string + Body string + Host string + Port int + UserName string + Password string +} + +func SendEmail(param *EmailParams) error { + m := gomail.NewMessage() + m.SetHeader("From", param.From) + m.SetHeader("To", param.To) + m.SetHeader("Subject", param.Subject) + m.SetBody("text/html", param.Body) + + d := gomail.NewDialer(param.Host, param.Port, param.UserName, param.Password) + + if err := d.DialAndSend(m); err != nil { + return err + } + return nil +} + +type GenerateUrl struct { + Url string +} + +func RenderEmailTemplate(url string, html string) (content string, err error) { + buf := new(bytes.Buffer) + t := template.Must(template.New("email").Funcs(template.FuncMap{}).Parse(html)) + + if err = t.Execute(buf, &GenerateUrl{ + Url: url, + }); err != nil { + return "", err + } + return buf.String(), nil +} diff --git a/pkg/tool/s3/client.go b/pkg/tool/s3/client.go index cdabe6c6922e37f955035fd2a1a7f62dcdcdaa27..9f8cd450b231f5cbd6427ef1e443638ddf6c632e 100644 --- a/pkg/tool/s3/client.go +++ b/pkg/tool/s3/client.go @@ -38,6 +38,15 @@ type Client struct { *s3.S3 } +type DownloadOption struct { + IgnoreNotExistError bool + RetryNum int +} + +var defaultDownloadOption = &DownloadOption{ + RetryNum: 3, +} + func NewClient(endpoint, ak, sk string, insecure, forcedPathStyle bool) (*Client, error) { creds := credentials.NewStaticCredentials(ak, sk, "") config := &aws.Config{ @@ -70,12 +79,21 @@ func (c *Client) ValidateBucket(bucketName string) error { return fmt.Errorf("validate s3 error: given bucket does not exist") } +func (c *Client) DownloadWithOption(bucketName, objectKey, dest string, option *DownloadOption) error { + return c.download(bucketName, objectKey, dest, option) +} + // Download the file to object storage func (c *Client) Download(bucketName, objectKey, dest string) error { + return c.download(bucketName, objectKey, dest, defaultDownloadOption) +} + +func (c *Client) download(bucketName, objectKey, dest string, option *DownloadOption) error { + retry := 0 var err error - for retry < 3 { + for retry < option.RetryNum { opt := &s3.GetObjectInput{ Bucket: aws.String(bucketName), Key: aws.String(objectKey), @@ -83,6 +101,9 @@ func (c *Client) Download(bucketName, objectKey, dest string) error { obj, err1 := c.GetObject(opt) if err1 != nil { if e, ok := err1.(awserr.Error); ok && e.Code() == s3.ErrCodeNoSuchKey { + if option.IgnoreNotExistError { + return nil + } return err1 } diff --git a/pkg/types/permission/permission.go b/pkg/types/permission/permission.go deleted file mode 100644 index abbbfaf7af2774b26e646357c567f7404845f020..0000000000000000000000000000000000000000 --- a/pkg/types/permission/permission.go +++ /dev/null @@ -1,66 +0,0 @@ -/* -Copyright 2021 The KodeRover 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 permission - -const ( - SuperUserUUID = "00000" //超级用户权限 - //产品工作流相关 - WorkflowTaskUUID = "30001" //产品工作流(执行任务、重启任务、取消任务) - WorkflowUpdateUUID = "30002" //产品工作流(更新) - WorkflowCreateUUID = "30003" //产品工作流(创建) - WorkflowDeleteUUID = "30004" //产品工作流(删除) - WorkflowListUUID = "30005" //产品工作流(查看) - WorkflowDeliveryUUID = "30006" //产品工作流(添加交付) - - //集成环境(测试环境) - TestEnvCreateUUID = "40001" //创建环境 - TestEnvDeleteUUID = "40002" //删除环境 - TestEnvManageUUID = "40003" //环境管理(环境更新、单服务更新、服务伸缩、服务重启、configmap更新、configmap回滚、重启实例、yaml导出) - TestEnvListUUID = "40004" //环境查看 - TestEnvShareUUID = "40005" //环境授权 - TestUpdateEnvUUID = "40010" //更新环境 - - //集成环境(生产环境) - ProdEnvListUUID = "40006" //环境查看 - ProdEnvCreateUUID = "40007" //创建环境 - ProdEnvManageUUID = "40008" //环境管理(环境更新、单服务更新、服务伸缩、服务重启、configMap更新、configMap回滚、重启实例、yaml导出) - ProdEnvDeleteUUID = "40009" //删除环境 - - //原项目管理相关 - //构建管理 - BuildDeleteUUID = "50007" //删除构建配置 - BuildManageUUID = "50008" //构建配置管理(创建构建、修改构建、修改服务组件) - BuildListUUID = "50019" //构建配置查看 - - //服务管理 - ServiceTemplateEditUUID = "50022" //修改服务编排 - ServiceTemplateManageUUID = "50023" //服务模板管理(创建服务模板、修改服务模板) - ServiceTemplateDeleteUUID = "50024" //删除服务模板 - ServiceTemplateListUUID = "50025" //查看服务模板 - - //测试管理 - TestDeleteUUID = "50010" //删除测试 - TestManageUUID = "50011" //测试管理(创建测试、修改测试) - TestListUUID = "50020" //查看测试 - - //交付中心 - ReleaseDeleteUUID = "70001" //交付中心删除版本 - - ParamType = 1 - QueryType = 2 - ContextKeyType = 3 -) diff --git a/pkg/types/permission/user.go b/pkg/types/permission/user.go deleted file mode 100644 index 24b3b5f6a820ebb4fb41462008977e48aeedfd44..0000000000000000000000000000000000000000 --- a/pkg/types/permission/user.go +++ /dev/null @@ -1,40 +0,0 @@ -/* -Copyright 2021 The KodeRover 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 permission - -const ( - AnonymousUserID = 0 - AnonymousUserName = "Anonymous" -) - -type User struct { - ID int `json:"id"` - Name string `json:"name"` - Email string `json:"email"` - Password string `json:"password"` - Phone string `json:"phone"` - IsAdmin bool `json:"isAdmin"` - IsSuperUser bool `json:"isSuperUser"` - IsTeamLeader bool `json:"isTeamLeader"` - OrganizationID int `json:"organization_id"` - Directory string `json:"directory"` - LastLoginAt int64 `json:"lastLogin"` - CreatedAt int64 `json:"created_at"` - UpdatedAt int64 `json:"updated_at"` -} - -var AnonymousUser = &User{ID: AnonymousUserID, Name: AnonymousUserName} diff --git a/version/version.go b/version/version.go index 9d7035727fd48342d1441d88ab55a232c7fde119..90ad69753ea5ca151a42d89468551b36f038fcd8 100644 --- a/version/version.go +++ b/version/version.go @@ -17,7 +17,7 @@ limitations under the License. package version var ( - Version = "1.6.0" + Version = "1.7.0" BuildNumber = "0" GitCommit = "" )