generated from pkg/go-template
feat: service
continuous-integration/drone/push Build was killed
Details
continuous-integration/drone/push Build was killed
Details
parent
35119f2003
commit
baa0eb8db2
|
@ -44,8 +44,14 @@ spec:
|
|||
- containerPort: {{ .Values.port }}
|
||||
protocol: TCP
|
||||
env:
|
||||
- name: endpoints
|
||||
- name: ENDPOINTS
|
||||
value: 'etcd:2379'
|
||||
- name: APP_NAME
|
||||
value: {{ .Values.appName }}
|
||||
- name: NAMESPACE
|
||||
value: {{ .Values.nameSpace }}
|
||||
- name: APP_TYPE
|
||||
value: api
|
||||
resources:
|
||||
limits:
|
||||
cpu: 200m
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
nameSpace: zeus
|
||||
appName: lark
|
||||
aliasName: 飞书
|
||||
image: reg.icechen.cn/zeus/api-lark
|
||||
imageTag: latest
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
FROM golang:1.17 as builder
|
||||
ENV GO111MODULE on
|
||||
ENV GOPROXY https://goproxy.io,direct
|
||||
WORKDIR /go/cache
|
||||
ADD go.mod .
|
||||
ADD go.sum .
|
||||
RUN go mod download -x
|
||||
WORKDIR /go/src
|
||||
ADD . .
|
||||
RUN go mod tidy
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o service_lark ./app/zeus/service/lark
|
||||
|
||||
FROM reg.icechen.cn/alpine as lark
|
||||
WORKDIR /go/src
|
||||
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo
|
||||
COPY --from=builder /go/src/service_lark ./
|
||||
ENV TZ=Asia/Shanghai
|
||||
RUN chmod +x ./service_lark
|
||||
EXPOSE 8080
|
||||
CMD ["./service_lark"]
|
|
@ -0,0 +1,23 @@
|
|||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*.orig
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
||||
.vscode/
|
|
@ -0,0 +1,24 @@
|
|||
apiVersion: v2
|
||||
name: lark
|
||||
description: 飞书
|
||||
|
||||
# A chart can be either an 'application' or a 'library' chart.
|
||||
#
|
||||
# Application charts are a collection of templates that can be packaged into versioned archives
|
||||
# to be deployed.
|
||||
#
|
||||
# Library charts provide useful utilities or functions for the chart developer. They're included as
|
||||
# a dependency of application charts to inject those utilities and functions into the rendering
|
||||
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
|
||||
type: application
|
||||
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||
version: 0.0.1
|
||||
|
||||
# This is the version number of the application being deployed. This version number should be
|
||||
# incremented each time you make changes to the application. Versions are not expected to
|
||||
# follow Semantic Versioning. They should reflect the version the application is using.
|
||||
# It is recommended to use it with quotes.
|
||||
appVersion: "0.0.1"
|
|
@ -0,0 +1 @@
|
|||
notes
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: app.k8s.io/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: {{ .Release.Name }}
|
||||
namespace: {{ .Values.nameSpace }}
|
||||
labels:
|
||||
app: {{ .Release.Name }}
|
||||
app.kubernetes.io/version: v1
|
||||
app.kubernetes.io/name: {{ .Release.Name }}
|
||||
version: v1
|
||||
annotations:
|
||||
servicemesh.kubesphere.io/enabled: 'true'
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{ .Release.Name }}
|
||||
app.kubernetes.io/version: v1
|
||||
app.kubernetes.io/name: {{ .Release.Name }}
|
||||
version: v1
|
||||
addOwnerRef: true
|
|
@ -0,0 +1,82 @@
|
|||
kind: Deployment
|
||||
apiVersion: apps/v1
|
||||
metadata:
|
||||
name: {{ .Release.Name }}
|
||||
namespace: {{ .Values.nameSpace }}
|
||||
labels:
|
||||
app: {{ .Release.Name }}
|
||||
app.kubernetes.io/version: v1
|
||||
app.kubernetes.io/name: {{ .Release.Name }}
|
||||
version: v1
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
annotations:
|
||||
kubesphere.io/alias-name: {{ .Values.aliasName }}
|
||||
kubesphere.io/creator: drone
|
||||
meta.helm.sh/release-name: {{ .Release.Name }}
|
||||
meta.helm.sh/release-namespace: {{ .Values.nameSpace }}
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{ .Release.Name }}
|
||||
app.kubernetes.io/version: v1
|
||||
app.kubernetes.io/name: {{ .Release.Name }}
|
||||
version: v1
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: {{ .Release.Name }}
|
||||
app.kubernetes.io/version: v1
|
||||
app.kubernetes.io/name: {{ .Release.Name }}
|
||||
version: v1
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
spec:
|
||||
volumes:
|
||||
- name: host-time
|
||||
hostPath:
|
||||
path: /etc/localtime
|
||||
type: ''
|
||||
containers:
|
||||
- name: {{ .Release.Name }}
|
||||
image: {{ .Values.image }}:{{ .Values.imageTag }}
|
||||
ports:
|
||||
- containerPort: {{ .Values.port }}
|
||||
protocol: TCP
|
||||
env:
|
||||
- name: ENDPOINTS
|
||||
value: 'etcd:2379'
|
||||
- name: APP_NAME
|
||||
value: {{ .Values.appName }}
|
||||
- name: NAMESPACE
|
||||
value: {{ .Values.nameSpace }}
|
||||
- name: APP_TYPE
|
||||
value: service
|
||||
resources:
|
||||
limits:
|
||||
cpu: 200m
|
||||
memory: 1000Mi
|
||||
requests:
|
||||
cpu: 10m
|
||||
memory: 200Mi
|
||||
volumeMounts:
|
||||
- name: host-time
|
||||
readOnly: true
|
||||
mountPath: /etc/localtime
|
||||
terminationMessagePath: /dev/termination-log
|
||||
terminationMessagePolicy: File
|
||||
imagePullPolicy: IfNotPresent
|
||||
restartPolicy: Always
|
||||
terminationGracePeriodSeconds: 30
|
||||
dnsPolicy: ClusterFirst
|
||||
securityContext: {}
|
||||
imagePullSecrets:
|
||||
- name: registry-secret
|
||||
schedulerName: default-scheduler
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate:
|
||||
maxUnavailable: 25%
|
||||
maxSurge: 25%
|
||||
revisionHistoryLimit: 10
|
||||
progressDeadlineSeconds: 600
|
|
@ -0,0 +1,26 @@
|
|||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: {{ .Release.Name }}
|
||||
namespace: {{ .Values.nameSpace }}
|
||||
annotations:
|
||||
kubesphere.io/creator: drone
|
||||
labels:
|
||||
app: {{ .Release.Name }}
|
||||
app.kubernetes.io/version: v1
|
||||
app.kubernetes.io/name: {{ .Release.Name }}
|
||||
version: v1
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
spec:
|
||||
ports:
|
||||
- name: http-{{ .Release.Name }}
|
||||
protocol: TCP
|
||||
port: 80
|
||||
targetPort: {{ .Values.port }}
|
||||
selector:
|
||||
app: {{ .Release.Name }}
|
||||
type: ClusterIP
|
||||
sessionAffinity: None
|
||||
ipFamilies:
|
||||
- IPv4
|
||||
ipFamilyPolicy: SingleStack
|
|
@ -0,0 +1,6 @@
|
|||
nameSpace: zeus
|
||||
appName: lark
|
||||
aliasName: 飞书
|
||||
image: reg.icechen.cn/zeus/service-lark
|
||||
imageTag: latest
|
||||
port: 3000
|
|
@ -0,0 +1,17 @@
|
|||
package config
|
||||
|
||||
import "git.icechen.cn/monorepo/backend/pkg/config"
|
||||
|
||||
type Cfg struct {
|
||||
LarkAppID string `json:"lark_app_id"`
|
||||
LarkAppSecret string `json:"lark_app_secret"`
|
||||
}
|
||||
|
||||
var Config Cfg
|
||||
|
||||
func init() {
|
||||
err := config.GetConfig(&Config)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package lark
|
||||
|
||||
import (
|
||||
"context"
|
||||
cfg "git.icechen.cn/monorepo/backend/app/zeus/service/lark/internal/config"
|
||||
"github.com/larksuite/oapi-sdk-go/core"
|
||||
"github.com/larksuite/oapi-sdk-go/core/config"
|
||||
authen "github.com/larksuite/oapi-sdk-go/service/authen/v1"
|
||||
)
|
||||
|
||||
type Lark struct {
|
||||
conf *config.Config
|
||||
}
|
||||
|
||||
func NewLark() Lark {
|
||||
appSettings := core.NewInternalAppSettings(
|
||||
core.SetAppCredentials(cfg.Config.LarkAppID, cfg.Config.LarkAppSecret))
|
||||
conf := core.NewConfig(core.DomainFeiShu, appSettings, core.SetLoggerLevel(core.LoggerLevelError))
|
||||
|
||||
return Lark{
|
||||
conf: conf,
|
||||
}
|
||||
}
|
||||
|
||||
func (l Lark) Auth(code string) (*authen.UserAccessTokenInfo, error) {
|
||||
s := authen.NewService(l.conf)
|
||||
return s.Authens.AccessToken(core.WrapContext(context.Background()), &authen.AuthenAccessTokenReqBody{
|
||||
GrantType: "",
|
||||
Code: code,
|
||||
}).Do()
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package lark
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"google.golang.org/grpc/keepalive"
|
||||
"log"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"git.icechen.cn/monorepo/backend/pkg/proto/zeus/lark"
|
||||
"github.com/jinzhu/copier"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/reflection"
|
||||
)
|
||||
|
||||
func RpcServer() {
|
||||
lis, err := net.Listen("tcp", ":3000")
|
||||
if err != nil {
|
||||
log.Fatalf("failed to listen: %v", err)
|
||||
}
|
||||
|
||||
s := grpc.NewServer(grpc.KeepaliveParams(keepalive.ServerParameters{
|
||||
MaxConnectionIdle: 5 * time.Minute,
|
||||
}))
|
||||
lark.RegisterUserServer(s, &Server{})
|
||||
|
||||
reflection.Register(s)
|
||||
|
||||
fmt.Println("lark server run in :3000")
|
||||
if err := s.Serve(lis); err != nil {
|
||||
log.Fatalf("failed to serve: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
type Server struct{}
|
||||
|
||||
func (s Server) Login(ctx context.Context, in *lark.LoginRequest) (*lark.LoginResponse, error) {
|
||||
userInfo, err := NewLark().Auth(in.Code)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp := new(lark.LoginResponse)
|
||||
err = copier.Copy(resp, userInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"git.icechen.cn/monorepo/backend/app/zeus/service/lark/internal/lark"
|
||||
)
|
||||
|
||||
func main() {
|
||||
lark.RpcServer()
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var db *gorm.DB
|
||||
|
||||
func init() {
|
||||
err := db.AutoMigrate(&UserInfo{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package model
|
||||
|
||||
import "gorm.io/gorm"
|
||||
|
||||
type UserInfo struct {
|
||||
gorm.Model
|
||||
AccessToken string `json:"access_token,omitempty" gorm:"access_token"`
|
||||
TokenType string `json:"token_type,omitempty" gorm:"token_type"`
|
||||
ExpiresIn int `json:"expires_in,omitempty" gorm:"expires_in"`
|
||||
Name string `json:"name,omitempty" gorm:"name"`
|
||||
EnName string `json:"en_name,omitempty" gorm:"en_name"`
|
||||
AvatarUrl string `json:"avatar_url,omitempty" gorm:"avatar_url"`
|
||||
AvatarThumb string `json:"avatar_thumb,omitempty" gorm:"avatar_thumb"`
|
||||
AvatarMiddle string `json:"avatar_middle,omitempty" gorm:"avatar_middle"`
|
||||
AvatarBig string `json:"avatar_big,omitempty" gorm:"avatar_big"`
|
||||
OpenId string `json:"open_id,omitempty" gorm:"open_id"`
|
||||
UnionId string `json:"union_id,omitempty" gorm:"union_id"`
|
||||
Email string `json:"email,omitempty" gorm:"email"`
|
||||
UserId string `json:"user_id,omitempty" gorm:"user_id"`
|
||||
Mobile string `json:"mobile,omitempty" gorm:"mobile"`
|
||||
TenantKey string `json:"tenant_key,omitempty" gorm:"tenant_key"`
|
||||
RefreshExpiresIn int `json:"refresh_expires_in,omitempty" gorm:"refresh_expires_in"`
|
||||
RefreshToken string `json:"refresh_token,omitempty" gorm:"refresh_token"`
|
||||
}
|
||||
|
||||
func (UserInfo) TableName() string {
|
||||
return "user_info"
|
||||
}
|
|
@ -3,48 +3,70 @@ package config
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"git.icechen.cn/monorepo/backend/pkg/env"
|
||||
"git.icechen.cn/monorepo/backend/pkg/etcd"
|
||||
"github.com/pkg/errors"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
const (
|
||||
prefix = "/config"
|
||||
env = "/env"
|
||||
envKey = "/env"
|
||||
)
|
||||
|
||||
type Env string
|
||||
|
||||
const (
|
||||
EnvTest = "test"
|
||||
EnvOnl = "onl"
|
||||
EnvTest Env = "test"
|
||||
EnvOnl Env = "onl"
|
||||
)
|
||||
|
||||
// GetConfig 根据etcd获取存入配置
|
||||
func GetConfig(name string, config interface{}) error {
|
||||
key := fmt.Sprintf("%v/config/%v", prefix, name)
|
||||
func GetConfig(config interface{}) error {
|
||||
return Bind("config", config)
|
||||
}
|
||||
|
||||
// GetMysql 获取数据库连接字符串
|
||||
func GetMysql() (string, error) {
|
||||
return GetString("mysql")
|
||||
}
|
||||
|
||||
// Bind 读取配置项到结构体
|
||||
func Bind(item string, out interface{}) error {
|
||||
if reflect.TypeOf(out).Kind() != reflect.Ptr {
|
||||
return errors.New("bind对象不是指针类型")
|
||||
}
|
||||
key := fmt.Sprintf("%s/%s/%s/%s", prefix, env.Namespace, env.GetAppNameWithType(), item)
|
||||
value, err := etcd.GetValue(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = json.Unmarshal([]byte(value), config)
|
||||
err = json.Unmarshal([]byte(value), out)
|
||||
if err != nil {
|
||||
return errors.WithMessage(err, "etcd配置解析到json失败")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetMysql(name string) (string, error) {
|
||||
key := fmt.Sprintf("%v/mysql/%v", prefix, name)
|
||||
// GetString 读取配置项字符串
|
||||
func GetString(item string) (string, error) {
|
||||
key := fmt.Sprintf("%s/%s/%s/%s", prefix, env.Namespace, env.GetAppNameWithType(), item)
|
||||
return etcd.GetValue(key)
|
||||
}
|
||||
|
||||
func GetEnv() (string, error) {
|
||||
return etcd.GetValue(env)
|
||||
// GetEnv 获取环境
|
||||
func GetEnv() (Env, error) {
|
||||
envString, err := etcd.GetValue(envKey)
|
||||
return Env(envString), err
|
||||
}
|
||||
|
||||
// IsTest 是否是测试环境
|
||||
func IsTest() bool {
|
||||
envString, _ := GetEnv()
|
||||
return envString == EnvTest
|
||||
}
|
||||
|
||||
// IsOnl 是否是正式环境
|
||||
func IsOnl() bool {
|
||||
envString, _ := GetEnv()
|
||||
return envString == EnvOnl
|
||||
|
|
|
@ -2,6 +2,8 @@ package config
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -10,24 +12,11 @@ type config struct {
|
|||
Es string `json:"es,omitempty"`
|
||||
}
|
||||
|
||||
func TestGetMysql(t *testing.T) {
|
||||
//获取 /config/mysql/api-zeus 的str
|
||||
mysql, err := GetMysql("api-zeus")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(mysql)
|
||||
}
|
||||
|
||||
func TestConfig(t *testing.T) {
|
||||
c := new(config)
|
||||
err := GetConfig("api-zeus", c)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnv(t *testing.T) {
|
||||
resp, err := http.Get("http://api-lark-test/user")
|
||||
b, _ := ioutil.ReadAll(resp.Body)
|
||||
t.Log(string(b))
|
||||
|
||||
env, err := GetEnv()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
|
|
|
@ -1,6 +1,26 @@
|
|||
package env
|
||||
|
||||
import "os"
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func init() {
|
||||
AppName = GetEnvDefault("APP_NAME", "default")
|
||||
Namespace = GetEnvDefault("NAMESPACE", "default")
|
||||
AppType = SAppType(GetEnvDefault("APP_TYPE", string(AppTypeAPI)))
|
||||
}
|
||||
|
||||
var AppName string
|
||||
var Namespace string
|
||||
var AppType SAppType
|
||||
|
||||
type SAppType string
|
||||
|
||||
const (
|
||||
AppTypeAPI = SAppType("api") // api应用类型
|
||||
AppTypeService = SAppType("service") // service应用类型
|
||||
)
|
||||
|
||||
func GetEnvDefault(key, defVal string) string {
|
||||
val, ex := os.LookupEnv(key)
|
||||
|
@ -10,3 +30,8 @@ func GetEnvDefault(key, defVal string) string {
|
|||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// GetAppNameWithType 获取带应用类型的应用名
|
||||
func GetAppNameWithType() string {
|
||||
return fmt.Sprintf("%s-%s", AppType, AppName)
|
||||
}
|
||||
|
|
|
@ -11,8 +11,8 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
EndPoints = "endpoints"
|
||||
EndAddress = "etcd:2379"
|
||||
EndPoints = "ENDPOINTS"
|
||||
EndAddress = "etcd1:2379"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -40,11 +40,11 @@ func GetValue(key string) (string, error) {
|
|||
}
|
||||
kv := clientV3.NewKV(client)
|
||||
defer client.Close()
|
||||
ctx, cancel := context.WithTimeout(context.TODO(), time.Second*3)
|
||||
ctx, cancel := context.WithTimeout(context.TODO(), time.Minute*3)
|
||||
defer cancel()
|
||||
if getResp, err := kv.Get(ctx, key, clientV3.WithPrefix()); err == nil {
|
||||
for _, v := range getResp.Kvs {
|
||||
return string(v.Value), nil
|
||||
if len(getResp.Kvs) > 0 {
|
||||
return string(getResp.Kvs[0].Value), nil
|
||||
}
|
||||
} else {
|
||||
return "", errors.New("etcd 连接超时")
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package orm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.icechen.cn/monorepo/backend/pkg/config"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var DB *gorm.DB
|
||||
|
||||
func init() {
|
||||
dsn, err := config.GetMysql()
|
||||
if err != nil {
|
||||
fmt.Println("init db error: ", err)
|
||||
return
|
||||
}
|
||||
DB, err = gorm.Open(mysql.Open(dsn))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue