diff --git a/develop/code-standards.md b/develop/code-standards.md index ee46ba1..a6e6bbc 100644 --- a/develop/code-standards.md +++ b/develop/code-standards.md @@ -1,84 +1,114 @@ -# 代码规范 +# paas-api 代码规范 -### 目录结构 +## 目录结构 ``` -├── Dockerfile // Dockerfile文件 -├── Makefile // 本地开发使用makefile -├── README.md // 介绍 -├── app.cfg // 配置文件 -├── cmd // 启动目录 -│   ├── client // 客户端操作入口 -│   └── server // server 端入口 -├── config.yaml // kubeconfig 文件 -├── docs // 文档 -│   ├── README.md -├── go.mod // go mod依赖 -├── go.sum // go mod依赖详情 -├── install // 可能需要安装的一些yaml文件 -├── src // 源码包 以下分为两个层级,src/下为组件, src/pkg/下 为模块 -│   ├── amqp // rabbimt 的操作实现 -│   ├── casbin // casbin 的实现 -│   ├── cmd // cmd参数处理 -│   ├── config // 配置文件处理实例化 -│   ├── consul // 操作consul kv 的实现 -│   ├── email -│   ├── event -│   ├── git-repo // 操作 gitlab及github 的实现 -│   ├── istio -│   ├── jenkins // 操作jenkins 的实现 -│   ├── jwt // jwt -│   ├── kubernetes // 连接kubernetes这病 -│   ├── logging -│   ├── middleware // 中间件 -│   ├── mysql // 数据连接处理 -│   ├── pkg // 具体的业务实现逻辑 -│   │   ├── account // 账号相关实现 -│   │   ├── audit // 就用审核逻辑 -│   │   ├── auth // 授权登陆 -│   │   ├── build // 应用的构建逻辑 -│   │   ├── configmap -│   │   ├── consul -│   │   ├── cronjob -│   │   ├── dashboard -│   │   ├── deployment -│   │   ├── discovery -│   │   ├── event -│   │   ├── gateway -│   │   ├── git -│   │   ├── group -│   │   ├── hooks -│   │   ├── ingress -│   │   ├── market -│   │   ├── member -│   │   ├── monitor -│   │   ├── msgs -│   │   ├── namespace -│   │   ├── notice -│   │   ├── permission -│   │   ├── persistentvolume -│   │   ├── persistentvolumeclaim -│   │   ├── pod -│   │   ├── proclaim -│   │   ├── project -│   │   ├── public -│   │   ├── role -│   │   ├── service -│   │   ├── statistics -│   │   ├── storage -│   │   ├── template -│   │   ├── terminal -│   │   ├── tools -│   │   ├── virtualservice -│   │   ├── wechat -│   │   └── workspace -│   ├── redis // redis 单点或集群的实现 -│   ├── repository // 操作数据库的具体实现 -│   │   ├── types // 数据库表的struct -│   └── util // 所需要用到的工具 -└── static // 静态目录 前端所编译好的代码 - ├── terminal.html - └── xterm // 前端命令行终端 +. +├── Dockerfile // 构建使用的Dockerfile文件 +├── LICENSE +├── Makefile // 本地开发、调试方便使用 +├── README.md // README +├── app.dev.cfg // 开发配置文件 +├── app.prod.cfg // 生产配置文件 +├── app.test.cfg // 测试配置文件 +├── cmd // 入口 +│ ├── client // 客户端测试 +│ │ └── client.go +│ ├── main.go // 入口main +│ └── service +│ ├── service.go // 启动前的基础配置,各个模块的实例化、数据库等外部资源的连接初始化都在这 +│ ├── service_gen.go // 数据库命令行操作 +│ ├── service_setting.go // 系统设置命令行操作 +│ ├── service_sore.go // 初始化验证码仓库 +│ ├── service_start.go // 启动服务, http、grpc初始化都会在这 +│ └── service_tracer.go // 初始化tracer +├── docker-compose.yaml +├── docs // 文档目录 +├── go.mod // go依赖 +├── go.sum +├── src // 源 +│ ├── api // 所有连接外部的api统一出入口 +│ │ ├── alarm // 统一告警中心api +│ │ │ ├── logging.go // 日志 +│ │ │ ├── service.go // 实现逻辑 +│ │ │ ├── service_test.go // 单元测试 +│ │ │ └── tracing.go // 链路 +│ │ ├── api.go // 初始化各个外部api服务 +│ ├── encode // 处理response的逻辑包 +│ │ ├── response.go // response处理逻辑 +│ │ └── responsestatus.go // 错误码定义 +│ ├── helpers // helpers +│ │ └── hashids // 生成唯一码 +│ │ └── hashids.go +│ ├── jwt // jwt +│ │ └── jwt.go +│ ├── kubernetes // 连接k8s客户端实现逻辑 +│ │ ├── client.go +│ │ ├── logging.go +│ │ └── tracing.go +│ ├── logging // 全局日志配置 +│ │ └── logging.go // 输出的方式,及未被定义的错误会在这进行处理 +│ ├── middleware // 全局、上层中间件 +│ │ ├── access.go // 授权验证中间件 +│ │ ├── asd.go // 登陆验证中间件 +│ │ ├── audit.go // 审计中间件 +│ │ ├── cluster.go // 集群验证中间件 +│ │ ├── limitter.go // 限流中间件 +│ │ ├── namespace.go // 项目空间处理中间件 +│ │ └── tracing.go // 链路追踪中间件 +│ ├── pkg // 业务模块包 +│ │ ├── access // 授权管理模块 +│ │ │ ├── endpoint.go // 端点连接request,middleware,service,response +│ │ │ ├── http.go // 处理http请求 +│ │ │ ├── logging.go // 处理grpc请求 +│ │ │ ├── service.go // 具体业务逻辑代码 +│ │ │ └── tracing.go // 链路追踪 +│ │ ├── auth // 登陆授权模块 +│ │ │ ├── endpoint.go // 端点连接request,middleware,service,response +│ │ │ ├── http.go // 处理http请求 +│ │ │ ├── instrumenting.go // 模块指标监控 给prometheus的监控指标 +│ │ │ ├── logging.go // 日志 +│ │ │ ├── middleware.go // 本模块独立中间件 +│ │ │ ├── service.go // 具体业务逻辑代码 +│ │ │ └── tracing.go // 链路追踪 +│ │ ├── openapi // 开放API模块,对外开放的接口模块,只对开放API使用,其他模块不允许调用业务功能多的时候可能会独立出出去 +│ │ │ ├── nginx // nginx操作业务模块 +│ │ │ │ ├── endpoint.go // 端点连接request,middleware,service,response +│ │ │ │ ├── http.go // 处理http请求 +│ │ │ │ ├── grpc.go // 处理grpc请求 +│ │ │ │ ├── pb // grpc 的pb文件 +│ │ │ │ ├── logging.go // 日志 +│ │ │ │ ├── middleware.go // 本模块独立中间件 +│ │ │ │ ├── service.go // 具体业务逻辑代码 +│ │ │ │ └── tracing.go // 链路追踪 +│ │ │ └── user // 用户相关操作业务模块 +│ │ │ ├── endpoint.go // 端点连接request,middleware,service,response +│ │ │ ├── http.go // 处理http请求 +│ │ │ ├── logging.go // 日志 +│ │ │ ├── service.go // 具体业务逻辑代码 +│ │ │ ├── service_test.go // 单元测试 +│ │ │ └── tracing.go // 链路追踪 +│ ├── redis // redis客户端 +│ │ ├── redis.go +│ │ └── redis_middleware.go +│ ├── repository // 数据仓库处理逻辑 +│ │ ├── access // access 相关表数据库操作逻辑实现包 +│ │ │ ├── cache.go // 缓存 +│ │ │ ├── logging.go // 日志 +│ │ │ ├── service.go // 实现逻辑 +│ │ │ └── tracing.go // 链路 +│ │ ├── repository.go // 连接各个数据库、数据表的统一出入口,实现各各表操作逻辑初始化 +│ │ └── types // 数据库表结构定义 +│ │ ├── auth_access.go +│ │ ├── auth_resource.go +│ │ ├── auth_service.go +│ └── util // util包 +│ ├── aes.go +├── tests // 单元测试 +│ ├── README.md +│ ├── grpc_test.go +│ └── service_client_test.go +└── web // 前端文件 ``` ## 代码规范 @@ -101,31 +131,99 @@ src/ 目录下创建的是可公用的组件,src/pkg/下是各个功能模块 #### 模块包规范 -新增加的模块必须在src/pkg目录下,每个模块必须包含4个文件,分别是service.go、logging.go、endpoint.go、transport.go +新增加的模块必须在src/pkg目录下,每个模块只干该模块该干的事,基础文件有service.go、logging.go、endpoint.go、http.go、tracing.go、service_test.go -logging.go: +**logging.go 参考:** ```go -type loggingService struct { - logger log.Logger - Service -} +import ( + "context" + "github.com/go-kit/kit/log" + "github.com/go-kit/kit/log/level" + "time" +) -func NewLoggingService(logger log.Logger, s Service) Service { - return &loggingService{logger, s} +type logging struct { + logger log.Logger + next Service + traceId string } -func (s *loggingService) Get(ctx context.Context, name string) (rs interface{}, err error) { +func (l *logging) Push(ctx context.Context, title, content, metrics, project, service string, level Level, silencePeriod int) (err error) { defer func(begin time.Time) { - _ = s.logger.Log( - "method", "Get", - "name", name, + _ = l.logger.Log( + l.traceId, ctx.Value(l.traceId), + "method", "Push", + "title", title, + "content", content, + "metrics", metrics, + "project", project, + "service", service, + "level", level, + "silencePeriod", silencePeriod, "took", time.Since(begin), "err", err, ) }(time.Now()) - return s.Service.Get(ctx, name) + return l.next.Push(ctx, title, content, metrics, project, service, level, silencePeriod) +} + +func NewLogging(logger log.Logger, traceId string) Middleware { + logger = log.With(logger, "api.alarm", "logging") + return func(next Service) Service { + return &logging{ + logger: level.Info(logger), + next: next, + traceId: traceId, + } + } +} +``` + +**tracing.go 参考:** + +```go +import ( + "context" + "github.com/opentracing/opentracing-go" + "github.com/opentracing/opentracing-go/ext" +) + +type tracing struct { + next Service + tracer opentracing.Tracer +} + +func (s *tracing) Push(ctx context.Context, title, content, metrics, project, service string, level Level, silencePeriod int) (err error) { + span, ctx := opentracing.StartSpanFromContextWithTracer(ctx, s.tracer, "Push", opentracing.Tag{ + Key: string(ext.Component), + Value: "Api.Alarm", + }) + defer func() { + span.LogKV( + "title", title, + "content", content, + "metrics", metrics, + "project", project, + "service", service, + "level", level, + "silencePeriod", silencePeriod, + "err", err) + span.SetTag(string(ext.Error), err != nil) + span.Finish() + }() + return s.next.Push(ctx, title, content, metrics, project, service, level, silencePeriod) +} + +func NewTracing(otTracer opentracing.Tracer) Middleware { + return func(next Service) Service { + return &tracing{ + next: next, + tracer: otTracer, + } + } } + ``` service.go 里的每个方法必须带有一个logging方法,日志输打印入参入出参和错误信息。 @@ -136,39 +234,34 @@ service.go 里的每个方法必须带有一个logging方法,日志输打印 ```go type Service interface { - // 获取pod详情页数据 - Get(ctx context.Context, podName string) (res map[string]interface{}, err error) - - // 获取容器日志 - GetLog(ctx context.Context, podName, container string, previous bool) (res *LogDetails, err error) - - // 下载pod 容器日志 - DownloadLog(ctx context.Context, podName, container string, previous bool) (res io.ReadCloser, err error) - - // 删除pod - Delete(ctx context.Context, podName string) (err error) + // Delete 删除Pod, 根据pod名称删除pod + // clusterId: 中间件取得 + // ns: 空间标识 + // podName: 需要删除的pod名称 + Delete(ctx context.Context, clusterId int64, ns, podName string) (err error) } ``` 接口的实现: ```go +type Middleware func(Service) Service type service struct { + traceId string logger log.Logger k8sClient kubernetes.K8sClient config *config.Config } -func NewService(logger log.Logger, k8sClient kubernetes.K8sClient, +func New(logger log.Logger, traceId string, k8sClient kubernetes.K8sClient, config *config.Config) Service { - return &service{logger, k8sClient, config} + return &service{traceId, logger, k8sClient, config} } -func (c *service) Delete(ctx context.Context, podName string) (err error) { +func (s *service) Delete(ctx context.Context, clusterId int64, ns, podName string) (err error) { // ... return } - ``` #### 变量 @@ -185,24 +278,23 @@ var ( ) ``` - - #### 常量 常量全部以驼峰式大写字母开头的方式命名: ```go +type ASDContext string const ( - UserIdContext ASDContext = "userId" - EmailContext ASDContext = "email" - NamespaceContext ASDContext = "namespace" - NameContext ASDContext = "name" + ContextKeyClusterName ASDContext = "ctx-cluster-name" // 集群名称 + ContextKeyClusterId ASDContext = "ctx-cluster-id" // 集群ID + ContextKeyNamespaceName ASDContext = "ctx-namespace-name" // 空间标识 + ContextKeyNamespaceId ASDContext = "ctx-namespace-id" // 集群id ) ``` #### 错误处理命名 -错误处理的原则就是不能丢弃任何有返回 err 的调用,不要采用_丢弃,必须全部处理。接收到错误,要么返回 err,并用 log记录下来。 error 的信息不要采用大写字母,尽量保持你的错误简短,但是要足够表达你的错误的意思。**每个pkg下的模块的错误必须定义在本模块下,不得跨模块调用。** +错误处理的原则就是不能丢弃任何有返回 err 的调用,不要采用_丢弃,必须全部处理。接收到错误,要么返回 err,并用 log记录下来。 error 的信息不要采用大写字母,尽量保持你的错误简短,但是要足够表达你的错误的意思。**所有的错误全部定义在src/encode/responsestatus.go上** 除了在man.go可以使用panic外,其于地方一率不得使用panic。 @@ -211,16 +303,42 @@ const ( 命名参考: ```go -var ( - ErrInvalidArgument = errors.New("invalid argument") - ErrStorageClassNotFound = errors.New("没有找到相关存储类") - ErrStorageClassIsExists = errors.New("存储类已经存在") - ErrStorageClassTemplateNotExists = errors.New("存储类模版不存在") - ErrStorageClassTemplateEncode = errors.New("存储类模版处理失败") - ErrStorageClassK8sCreate = errors.New("存储类创建失败") - ErrStorageClassList = errors.New("存储类列表获取失败") - ErrStorageClassK8sGet = errors.New("存储类获取失败") + +type ResStatus string +var ResponseMessage = map[ResStatus]int{ + ErrAccessSave: 2501, + ErrAccessNotfound: 2502, + ErrAccessResourceNotfound: 2503, + ErrAccessResourceExpireTime: 2504, +} + +const ( + ErrAccessSave ResStatus = "保存失败" + ErrAccessNotfound ResStatus = "授权不存在" + ErrAccessResourceNotfound ResStatus = "授权资源不存在" + ErrAccessResourceExpireTime ResStatus = "授权已过期" ) +``` + +> 未来被定义的错误信息会统一返回“系统错误”,并发出一条告警信息到统一告警中心。 + +**使用方式** +直接返回错误: + +``` +return encode.ErrAccessNotfound.Error() ``` +拼接上层错误: + +``` +var err = errors.New("parent error.") +return encode.ErrAccessNotfound.Wrap(err) +``` + +返回字符串错误: + +``` +return encode.ErrAccessNotfound.String() +```