* [Fix] Relocate User Permanent SSH Public Key queries to DevcontainerService Layer * [Fix] Add Unix Timestamps in DB table `devstar_devcontainer` * [Feature] Tencent NAT port forwarding * [Doc] k8s Operator RBAC: ServiceAccount, ClusterRole, ClusterRoleBinding, etc. * [fix] k8s Operator Reconciler error while converting YAML to JSON * [Doc] Added DevStar API Doc * [fix] detailed errors while listing user devcontainers * [fix] Invalid metadata.labels: value must be no more than 63 characters
84 lines
3.2 KiB
Go
84 lines
3.2 KiB
Go
package api_services
|
||
|
||
import (
|
||
"code.gitea.io/gitea/models/db"
|
||
"code.gitea.io/gitea/models/repo"
|
||
DevcontainersVO "code.gitea.io/gitea/routers/api/devcontainer/vo"
|
||
gitea_web_context "code.gitea.io/gitea/services/context"
|
||
DevcontainersService "code.gitea.io/gitea/services/devstar_devcontainer"
|
||
devcontainer_service_errors "code.gitea.io/gitea/services/devstar_devcontainer/errors"
|
||
devcontainer_service_options "code.gitea.io/gitea/services/devstar_devcontainer/options"
|
||
"context"
|
||
"regexp"
|
||
)
|
||
|
||
// CreateDevcontainerAPIService API专用创建 DevContainer Service
|
||
func CreateDevcontainerAPIService(ctx *gitea_web_context.Context, opts *devcontainer_service_options.CreateDevcontainerOptions) error {
|
||
// 0. 检查用户传入参数
|
||
if ctx == nil || opts == nil || opts.Actor == nil || opts.RepoId <= 0 {
|
||
return devcontainer_service_errors.ErrIllegalParams{
|
||
FieldNameList: []string{"ctx", "opts", "opts.Actor", "opts.RepoId"},
|
||
}
|
||
}
|
||
|
||
// sanitize user-input SSH Public Key List
|
||
regexpInvalidSSHPublicKey := regexp.MustCompile(`[\r]`)
|
||
for _, publicKey := range opts.SSHPublicKeyList {
|
||
if len(publicKey) <= 4 || publicKey[0:4] != "ssh-" || regexpInvalidSSHPublicKey.MatchString(publicKey) {
|
||
// 遇到可能无效的 SSH Public Key,或者导致 k8s Operator YAML 解码失败的字符: `\r`,报错返回
|
||
// ERROR Reconciler error:
|
||
// {
|
||
// "controller": "devcontainerapp",
|
||
// "controllerGroup": "devcontainer.devstar.cn",
|
||
// "controllerKind": "DevcontainerApp",
|
||
// "DevcontainerApp": {
|
||
// "name": "leviyanx-16-4834a4c88c4511ef9c1a4e1bce2a7080",
|
||
// "namespace": "devstar-studio-ns"
|
||
// },
|
||
// "namespace": "devstar-studio-ns",
|
||
// "name": "leviyanx-16-4834a4c88c4511ef9c1a4e1bce2a7080",
|
||
// "reconcileID": "6af51347-7aae-4542-a5cf-2f9b57a202e6",
|
||
// "error": "panic: error converting YAML to JSON: yaml: line 46: could not find expected ':' [recovered]"
|
||
// }
|
||
return devcontainer_service_errors.ErrIllegalParams{
|
||
FieldNameList: []string{"SSHPublicKeyList"},
|
||
}
|
||
}
|
||
}
|
||
|
||
// 1. 开启事务
|
||
errTxn := db.WithTx(ctx, func(ctx context.Context) error {
|
||
|
||
// 1.1 调用 model层,查询数据库,将 repoId 变换为 Repository 对象
|
||
repositoryInDB, err := repo.GetRepositoryByID(ctx, opts.RepoId)
|
||
if err != nil || repositoryInDB == nil {
|
||
return devcontainer_service_errors.ErrIllegalParams{
|
||
FieldNameList: []string{"opts.RepoId"},
|
||
}
|
||
}
|
||
|
||
// 1.2 检查该用户在该仓库 是否已经创建过 DevContainer
|
||
optsRepoDevcontainer := &DevcontainersVO.RepoDevcontainerOptions{
|
||
Actor: opts.Actor,
|
||
Repository: repositoryInDB,
|
||
}
|
||
devcontainerDetails, err := DevcontainersService.GetRepoDevcontainerDetails(ctx, optsRepoDevcontainer)
|
||
if err != nil || devcontainerDetails.DevContainerId > 0 {
|
||
return devcontainer_service_errors.ErrDevcontainerAlreadyCreated{
|
||
Actor: opts.Actor,
|
||
Repository: repositoryInDB,
|
||
}
|
||
}
|
||
|
||
// 1.3 调用 DevContainer Service 创建 DevContainer
|
||
optsCreateDevcontainer := &DevcontainersVO.CreateRepoDevcontainerOptions{
|
||
Actor: opts.Actor,
|
||
Repository: repositoryInDB,
|
||
SSHPublicKeyList: opts.SSHPublicKeyList,
|
||
}
|
||
return DevcontainersService.CreateRepoDevcontainer(ctx, optsCreateDevcontainer)
|
||
})
|
||
|
||
return errTxn
|
||
}
|