forked from Trustie/forgeplus
ADD 个人中心添加devops管理功能
This commit is contained in:
parent
731c06185b
commit
562d0b7b07
181
README.md
181
README.md
|
@ -2424,7 +2424,7 @@ http://localhost:3000/api/jasder/forgeplus/ci_authorize.json | jq
|
||||||
|
|
||||||
|参数名|类型|说明|
|
|参数名|类型|说明|
|
||||||
|-|-|-|
|
|-|-|-|
|
||||||
|step |int|初始化devops流程步骤; 0: 标识未开启devops,1: 标识用户已填写了云服务器相关信息,但并未开启认证, 2: 标识用户已开启了CI服务端的认证, 3: 标识用户ci服务已初始化|
|
|step |int|初始化devops流程步骤; 0: 标识未开启devops,1: 标识用户已填写了云服务器相关信息,但并未开启认证, 2: 标识用户已开启了CI服务端的认证|
|
||||||
|account |string|你的云服务器帐号|
|
|account |string|你的云服务器帐号|
|
||||||
|ip |string|你的云服务器帐号ip|
|
|ip |string|你的云服务器帐号ip|
|
||||||
|secret |string|你的云服务器登录密码|
|
|secret |string|你的云服务器登录密码|
|
||||||
|
@ -3108,3 +3108,182 @@ http://localhost:3000/api/dev_ops/builds/2/logs/1/1 | jq
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
---
|
---
|
||||||
|
|
||||||
|
#### 获取CI服务器配置信息
|
||||||
|
```
|
||||||
|
GET /api/users/ci/cloud_account
|
||||||
|
```
|
||||||
|
|
||||||
|
*示例*
|
||||||
|
```
|
||||||
|
curl -X GET \
|
||||||
|
http://localhost:3000/api/users/ci/cloud_account | jq
|
||||||
|
```
|
||||||
|
|
||||||
|
*返回参数说明:*
|
||||||
|
|
||||||
|
|参数名|类型|说明|
|
||||||
|
|-|-|-|
|
||||||
|
|step |int|0: 未绑定;1: 未认证(已绑定),2: 已认证|
|
||||||
|
|ip |string|ci服务器ip|
|
||||||
|
|redirect_url |string|认证地址|
|
||||||
|
|
||||||
|
返回值
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"step": 0,
|
||||||
|
"cloud_account": {
|
||||||
|
"ip": "xxx.xxx.xxx.x",
|
||||||
|
"redirect_url": "http://localhost:3000/login",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 绑定CI服务器
|
||||||
|
```
|
||||||
|
POST /api/users/ci/cloud_account/bind
|
||||||
|
```
|
||||||
|
|
||||||
|
*示例*
|
||||||
|
```
|
||||||
|
curl -X POST \
|
||||||
|
-d "account=xx" \
|
||||||
|
-d "secret=xxx" \
|
||||||
|
-d "ip_num=xx.xx.xx.xx" \
|
||||||
|
https://localhost:3000/api/users/ci/cloud_account/bind.json | jq
|
||||||
|
```
|
||||||
|
|
||||||
|
*请求参数说明:*
|
||||||
|
|
||||||
|
|参数名|必选|类型|说明|
|
||||||
|
|-|-|-|-|
|
||||||
|
|account |是|string |云服务器ssh连接登录用户名 |
|
||||||
|
|secret |是|string |云服务器ssh连接登录秘密 |
|
||||||
|
|ip_num |否|string |云服务器公网IP |
|
||||||
|
|
||||||
|
*返回参数说明:*
|
||||||
|
|
||||||
|
|参数名|类型|说明|
|
||||||
|
|-|-|-|
|
||||||
|
|step |int|0: 未绑定;1: 未认证(已绑定),2: 已认证|
|
||||||
|
|ip |string|ci服务器ip|
|
||||||
|
|redirect_url |string|认证地址|
|
||||||
|
|
||||||
|
返回值
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"step": 0,
|
||||||
|
"cloud_account": {
|
||||||
|
"ip": "xxx.xxx.xxx.x",
|
||||||
|
"redirect_url": "http://localhost:3000/login",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
### 解除CI服务器绑定
|
||||||
|
```
|
||||||
|
DELETE /api/users/ci/cloud_account/unbind
|
||||||
|
```
|
||||||
|
|
||||||
|
*示例*
|
||||||
|
```
|
||||||
|
curl -X DELETE \
|
||||||
|
http://localhost:3000/api/users/ci/cloud_account/unbind.json | jq
|
||||||
|
```
|
||||||
|
|
||||||
|
*返回参数说明:*
|
||||||
|
|
||||||
|
|参数名|类型|说明|
|
||||||
|
|-|-|-|
|
||||||
|
|status |int|状态码, 0: 成功,-1: 失败|
|
||||||
|
|message |string|返回信息说明|
|
||||||
|
|
||||||
|
返回值
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": 0,
|
||||||
|
"message": "success"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
|
### 项目列表
|
||||||
|
```
|
||||||
|
GET /api/users/:login/projects
|
||||||
|
```
|
||||||
|
|
||||||
|
*示例*
|
||||||
|
```
|
||||||
|
curl -X GET \
|
||||||
|
-d "page=1" \
|
||||||
|
-d "limit=20" \
|
||||||
|
http://localhost:3000/api/users/Jason/projects.json | jq
|
||||||
|
```
|
||||||
|
|
||||||
|
*请求参数说明:*
|
||||||
|
|
||||||
|
|参数名|必选|类型|说明|
|
||||||
|
|-|-|-|-|
|
||||||
|
|page |否|int |页数,第几页 |
|
||||||
|
|limit |否|int |每页多少条数据,默认20条 |
|
||||||
|
|
||||||
|
*返回参数说明:*
|
||||||
|
|
||||||
|
|参数名|类型|说明|
|
||||||
|
|-|-|-|
|
||||||
|
|total_count |int |项目总条数 |
|
||||||
|
|id |string |项目id |
|
||||||
|
|name |string|项目名称|
|
||||||
|
|description |string|项目简介|
|
||||||
|
|open_devops |boolean|激活状态,true: 激活; false:未激活|
|
||||||
|
|visits |int|流量数|
|
||||||
|
|forked_count |int|被fork的数量|
|
||||||
|
|praises_count |int|star数量|
|
||||||
|
|is_public |boolean|是否公开, true:公开,false:未公开|
|
||||||
|
|mirror_url |string|镜像url|
|
||||||
|
|last_update_time|int|最后更新时间,为UNIX格式的时间戳|
|
||||||
|
|author |object|项目创建者|
|
||||||
|
|-- name |string|用户名,也是用户标识|
|
||||||
|
|category |object|项目类别|
|
||||||
|
|-- id |int|项目类型id|
|
||||||
|
|-- name |string|项目类型名称|
|
||||||
|
|language |object|项目语言|
|
||||||
|
|-- id |int|项目语言id|
|
||||||
|
|-- name |string|项目语言名称|
|
||||||
|
|
||||||
|
|
||||||
|
返回值
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"total_count": 3096,
|
||||||
|
"projects": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "hnfl_demo1",
|
||||||
|
"description": "my first project",
|
||||||
|
"visits": 0,
|
||||||
|
"praises_count": 0,
|
||||||
|
"forked_count": 0,
|
||||||
|
"is_public": true,
|
||||||
|
"mirror_url": null,
|
||||||
|
"last_update_time": 1577697461,
|
||||||
|
"author": {
|
||||||
|
"name": "18816895620",
|
||||||
|
"image_url": "avatars/User/b"
|
||||||
|
},
|
||||||
|
"category": {
|
||||||
|
"id": 1,
|
||||||
|
"name": "大数据"
|
||||||
|
},
|
||||||
|
"language": {
|
||||||
|
"id": 2,
|
||||||
|
"name": "C"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
|
@ -10,52 +10,12 @@ class Ci::CloudAccountsController < Ci::BaseController
|
||||||
ActiveRecord::Base.transaction do
|
ActiveRecord::Base.transaction do
|
||||||
Ci::CreateCloudAccountForm.new(devops_params).validate!
|
Ci::CreateCloudAccountForm.new(devops_params).validate!
|
||||||
|
|
||||||
# 1. 保存华为云服务器帐号
|
@cloud_account = bind_account(current_user)
|
||||||
create_params = devops_params.merge(ip_num: IPAddr.new(devops_params[:ip_num]).to_i, secret: Ci::CloudAccount.encrypted_secret(devops_params[:secret]))
|
if @cloud_account.blank?
|
||||||
if current_user&.ci_cloud_account.present?
|
|
||||||
return render_error('该仓库已绑定了云帐号.')
|
|
||||||
else
|
|
||||||
cloud_account = Ci::CloudAccount.new(create_params)
|
|
||||||
cloud_account.user = current_user
|
|
||||||
cloud_account.save!
|
|
||||||
end
|
|
||||||
|
|
||||||
# 2. 生成oauth2应用程序的client_id和client_secrete
|
|
||||||
gitea_oauth = Gitea::Oauth2::CreateService.call(current_user.gitea_token, {name: "pipeline", redirect_uris: ["#{cloud_account.drone_url}/login"]})
|
|
||||||
logger.info "######### gitea_oauth: #{gitea_oauth}"
|
|
||||||
oauth = Oauth.new(client_id: gitea_oauth['client_id'],
|
|
||||||
client_secret: gitea_oauth['client_secret'],
|
|
||||||
redirect_uri: gitea_oauth['redirect_uris'],
|
|
||||||
gitea_oauth_id: gitea_oauth['id'],
|
|
||||||
user_id: current_user.id,
|
|
||||||
project_id: @project.id)
|
|
||||||
oauth.save
|
|
||||||
|
|
||||||
rpc_secret = SecureRandom.hex 16
|
|
||||||
logger.info "######### rpc_secret: #{rpc_secret}"
|
|
||||||
|
|
||||||
# 3. 创建drone server
|
|
||||||
drone_server_cmd = Ci::Drone::Server.new(oauth.client_id, oauth.client_secret, cloud_account.drone_host, rpc_secret).generate_cmd
|
|
||||||
logger.info "######### drone_server_cmd: #{drone_server_cmd}"
|
|
||||||
|
|
||||||
# 4. 创建drone client
|
|
||||||
drone_client_cmd = Ci::Drone::Client.new(oauth.client_id, cloud_account.drone_ip, rpc_secret).generate_cmd
|
|
||||||
logger.info "######### drone_client_cmd: #{drone_client_cmd}"
|
|
||||||
|
|
||||||
# 5. 登录远程服务器,启动drone服务
|
|
||||||
result = Ci::Drone::Start.new(cloud_account.account, cloud_account.visible_secret, cloud_account.drone_ip, drone_server_cmd, drone_client_cmd).run
|
|
||||||
logger.info "######### result: #{result}"
|
|
||||||
|
|
||||||
|
|
||||||
redirect_url = "#{cloud_account.drone_url}/login"
|
|
||||||
logger.info "######### redirect_url: #{redirect_url}"
|
|
||||||
|
|
||||||
if result && !result.blank?
|
|
||||||
current_user.set_drone_step!(User::DEVOPS_UNVERIFIED)
|
|
||||||
render_ok(redirect_url: redirect_url)
|
|
||||||
else
|
|
||||||
render_error('激活失败, 请检查你的云服务器信息是否正确.')
|
render_error('激活失败, 请检查你的云服务器信息是否正确.')
|
||||||
raise ActiveRecord::Rollback
|
raise ActiveRecord::Rollback
|
||||||
|
else
|
||||||
|
current_user.set_drone_step!(User::DEVOPS_UNVERIFIED)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
rescue Exception => ex
|
rescue Exception => ex
|
||||||
|
@ -79,6 +39,37 @@ class Ci::CloudAccountsController < Ci::BaseController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
@cloud_account = current_user.ci_cloud_account
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def bind
|
||||||
|
Ci::CreateCloudAccountForm.new(devops_params).validate!
|
||||||
|
|
||||||
|
ActiveRecord::Base.transaction do
|
||||||
|
@cloud_account = bind_account(current_user)
|
||||||
|
if @cloud_account.blank?
|
||||||
|
render_error('激活失败, 请检查你的云服务器信息是否正确.')
|
||||||
|
raise ActiveRecord::Rollback
|
||||||
|
else
|
||||||
|
current_user.set_drone_step!(User::DEVOPS_UNVERIFIED)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
rescue Exception => ex
|
||||||
|
render_error(ex.message)
|
||||||
|
end
|
||||||
|
|
||||||
|
def unbind
|
||||||
|
ActiveRecord::Base.transaction do
|
||||||
|
unbind_account!(current_user)
|
||||||
|
render_ok
|
||||||
|
end
|
||||||
|
rescue Exception => ex
|
||||||
|
render_error(ex.message)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
private
|
private
|
||||||
def devops_params
|
def devops_params
|
||||||
params.permit(:account, :secret, :ip_num)
|
params.permit(:account, :secret, :ip_num)
|
||||||
|
@ -87,4 +78,61 @@ class Ci::CloudAccountsController < Ci::BaseController
|
||||||
def find_cloud_account
|
def find_cloud_account
|
||||||
@cloud_account = Ci::CloudAccount.find params[:id]
|
@cloud_account = Ci::CloudAccount.find params[:id]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def bind_account(user)
|
||||||
|
# 1. 保存华为云服务器帐号
|
||||||
|
create_params = devops_params.merge(ip_num: IPAddr.new(devops_params[:ip_num]).to_i, secret: Ci::CloudAccount.encrypted_secret(devops_params[:secret]))
|
||||||
|
|
||||||
|
return render_error('你已绑定了云帐号.') if user.ci_cloud_account.blank?
|
||||||
|
|
||||||
|
cloud_account = Ci::CloudAccount.new(create_params)
|
||||||
|
cloud_account.user = user
|
||||||
|
cloud_account.save!
|
||||||
|
|
||||||
|
# 2. 生成oauth2应用程序的client_id和client_secrete
|
||||||
|
gitea_oauth = Gitea::Oauth2::CreateService.call(user.gitea_token, {name: "pipeline", redirect_uris: ["#{cloud_account.drone_url}/login"]})
|
||||||
|
logger.info "######### gitea_oauth: #{gitea_oauth}"
|
||||||
|
oauth = Oauth.new(client_id: gitea_oauth['client_id'],
|
||||||
|
client_secret: gitea_oauth['client_secret'],
|
||||||
|
redirect_uri: gitea_oauth['redirect_uris'],
|
||||||
|
gitea_oauth_id: gitea_oauth['id'],
|
||||||
|
user_id: current_user.id)
|
||||||
|
oauth.save
|
||||||
|
|
||||||
|
rpc_secret = SecureRandom.hex 16
|
||||||
|
logger.info "######### rpc_secret: #{rpc_secret}"
|
||||||
|
|
||||||
|
# 3. 创建drone server
|
||||||
|
drone_server_cmd = Ci::Drone::Server.new(oauth.client_id, oauth.client_secret, cloud_account.drone_host, rpc_secret).generate_cmd
|
||||||
|
logger.info "######### drone_server_cmd: #{drone_server_cmd}"
|
||||||
|
|
||||||
|
# 4. 创建drone client
|
||||||
|
drone_client_cmd = Ci::Drone::Client.new(oauth.client_id, cloud_account.drone_ip, rpc_secret).generate_cmd
|
||||||
|
logger.info "######### drone_client_cmd: #{drone_client_cmd}"
|
||||||
|
|
||||||
|
# 5. 登录远程服务器,启动drone服务
|
||||||
|
result = Ci::Drone::Start.new(cloud_account.account, cloud_account.visible_secret, cloud_account.drone_ip, drone_server_cmd, drone_client_cmd).run
|
||||||
|
logger.info "######### result: #{result}"
|
||||||
|
|
||||||
|
|
||||||
|
redirect_url = "#{cloud_account.drone_url}/login"
|
||||||
|
logger.info "######### redirect_url: #{redirect_url}"
|
||||||
|
|
||||||
|
result && !result.blank? ? cloud_account : nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def unbind_account!(user)
|
||||||
|
cloud_account = user.ci_cloud_account
|
||||||
|
|
||||||
|
case user.devops_step
|
||||||
|
when User::DEVOPS_UNINIT
|
||||||
|
return render_error('你还未绑定CI服务器')
|
||||||
|
when User::DEVOPS_UNVERIFIED
|
||||||
|
cloud_account.destroy
|
||||||
|
when User::DEVOPS_CERTIFICATION
|
||||||
|
cloud_account.ci_user.destroy
|
||||||
|
end
|
||||||
|
user.projects.update_all(open_devops: false)
|
||||||
|
user.set_drone_step!(User::DEVOPS_UNINIT)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
class Ci::CloudAccount < Ci::LocalBase
|
class Ci::CloudAccount < Ci::LocalBase
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
|
belongs_to :ci_user, class_name: 'Ci::User', foreign_key: :ci_user_id
|
||||||
|
|
||||||
def drone_host
|
def drone_host
|
||||||
[drone_ip, ":80"].join
|
[drone_ip, ":80"].join
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
class Ci::Log < Ci::RemoteBase
|
||||||
|
self.primary_key = 'log_id'
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,4 @@
|
||||||
|
class Ci::Perm < Ci::RemoteBase
|
||||||
|
belongs_to :user, foreign_key: :perm_user_id
|
||||||
|
|
||||||
|
end
|
|
@ -2,5 +2,7 @@ class Ci::User < Ci::RemoteBase
|
||||||
self.primary_key = 'user_id'
|
self.primary_key = 'user_id'
|
||||||
|
|
||||||
has_many :repos, foreign_key: "repo_user_id", dependent: :destroy
|
has_many :repos, foreign_key: "repo_user_id", dependent: :destroy
|
||||||
|
has_many :perms, foreign_key: "perm_user_id", dependent: :destroy
|
||||||
|
has_one :ci_cloud_account, class_name: 'Ci::CloudAccount', foreign_key: :ci_user_id
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# for oauth2 application
|
# for oauth2 application
|
||||||
class Oauth < ApplicationRecord
|
class Oauth < ApplicationRecord
|
||||||
belongs_to :project
|
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,9 +10,10 @@ class User < ApplicationRecord
|
||||||
# include Searchable::Dependents::User
|
# include Searchable::Dependents::User
|
||||||
|
|
||||||
# devops step
|
# devops step
|
||||||
# devops_step column: 0: 未填写服务器信息;1: 已填写服务器信息(未认证);
|
# devops_step column: 0: 未填写服务器信息;1: 已填写服务器信息(未认证);2: 已认证
|
||||||
DEVOPS_UNINIT = 0
|
DEVOPS_UNINIT = 0
|
||||||
DEVOPS_UNVERIFIED = 1
|
DEVOPS_UNVERIFIED = 1
|
||||||
|
DEVOPS_CERTIFICATION = 2
|
||||||
|
|
||||||
# Account statuses
|
# Account statuses
|
||||||
STATUS_ANONYMOUS = 0
|
STATUS_ANONYMOUS = 0
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
json.step current_user.devops_step
|
||||||
|
json.cloud_account do
|
||||||
|
if @cloud_account && !current_user.devops_uninit?
|
||||||
|
json.ip @cloud_account.drone_ip
|
||||||
|
json.redirect_url "#{@cloud_account.drone_url}/login" if current_user.devops_unverified?
|
||||||
|
else
|
||||||
|
json.nil!
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,9 @@
|
||||||
|
json.step current_user.devops_step
|
||||||
|
json.cloud_account do
|
||||||
|
if @cloud_account && !current_user.devops_uninit?
|
||||||
|
json.ip @cloud_account.drone_ip
|
||||||
|
json.redirect_url "#{@cloud_account.drone_url}/login" if current_user.devops_unverified?
|
||||||
|
else
|
||||||
|
json.nil!
|
||||||
|
end
|
||||||
|
end
|
|
@ -16,6 +16,7 @@ json.type project&.numerical_for_project_type
|
||||||
json.last_update_time render_unix_time(project.updated_on)
|
json.last_update_time render_unix_time(project.updated_on)
|
||||||
json.time_ago time_from_now(project.updated_on)
|
json.time_ago time_from_now(project.updated_on)
|
||||||
json.forked_from_project_id project.forked_from_project_id
|
json.forked_from_project_id project.forked_from_project_id
|
||||||
|
json.open_devops project.open_devops?
|
||||||
json.author do
|
json.author do
|
||||||
json.name user.try(:show_real_name)
|
json.name user.try(:show_real_name)
|
||||||
json.login user.login
|
json.login user.login
|
||||||
|
|
|
@ -26,6 +26,7 @@ Rails.application.routes.draw do
|
||||||
get :common
|
get :common
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# resources :repos, only: :index do
|
# resources :repos, only: :index do
|
||||||
# collection do
|
# collection do
|
||||||
# get 'get_trustie_pipeline', to: 'builds#get_trustie_pipeline', as: 'get_trustie_pipeline'
|
# get 'get_trustie_pipeline', to: 'builds#get_trustie_pipeline', as: 'get_trustie_pipeline'
|
||||||
|
@ -144,6 +145,28 @@ Rails.application.routes.draw do
|
||||||
post :sync_salt
|
post :sync_salt
|
||||||
get :trustie_projects
|
get :trustie_projects
|
||||||
get :trustie_related_projects
|
get :trustie_related_projects
|
||||||
|
|
||||||
|
scope '/ci', module: :ci do
|
||||||
|
scope do
|
||||||
|
post(
|
||||||
|
'/cloud_account/bind',
|
||||||
|
to: 'cloud_accounts#bind',
|
||||||
|
as: :bind_cloud_acclount
|
||||||
|
)
|
||||||
|
|
||||||
|
get(
|
||||||
|
'/cloud_account',
|
||||||
|
to: 'cloud_accounts#show',
|
||||||
|
as: :get_cloud_account
|
||||||
|
)
|
||||||
|
|
||||||
|
delete(
|
||||||
|
'/cloud_account/unbind',
|
||||||
|
to: 'cloud_accounts#unbind',
|
||||||
|
as: :unbind_cloud_acclount
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
scope module: :users do
|
scope module: :users do
|
||||||
|
|
Loading…
Reference in New Issue