mirror of https://github.com/openspug/spug
update pipeline module
parent
09ccd4982f
commit
23f92230ae
|
@ -131,7 +131,7 @@ class NodeExecutor:
|
|||
node.source = source = AttrDict(node.source)
|
||||
node.destination = destination = AttrDict(node.destination)
|
||||
host = Host.objects.get(pk=source.target)
|
||||
local_dir = local_path = os.path.join(settings.TRANSFER_DIR, uuid4().hex)
|
||||
local_dir = os.path.join(settings.TRANSFER_DIR, uuid4().hex)
|
||||
os.makedirs(local_dir)
|
||||
remote_dir = f'{host.username}@{host.hostname}:{source.path}'
|
||||
with host.get_ssh() as ssh:
|
||||
|
@ -139,6 +139,8 @@ class NodeExecutor:
|
|||
if code == 0:
|
||||
remote_dir = f'{host.username}@{host.hostname}:{os.path.dirname(source.path)}'
|
||||
local_path = os.path.join(local_dir, os.path.basename(source.path))
|
||||
else:
|
||||
local_path = local_dir + '/'
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode='w') as fp:
|
||||
fp.write(host.pkey or AppSetting.get('private_key'))
|
||||
|
@ -192,7 +194,7 @@ class NodeExecutor:
|
|||
threads = []
|
||||
with futures.ThreadPoolExecutor(max_workers=self.max_workers) as executor:
|
||||
for host in Host.objects.filter(id__in=node.targets):
|
||||
t = executor.submit(self._data_transfer, node, host, f'{local_path}{os.sep}', node.path)
|
||||
t = executor.submit(self._data_transfer, node, host, f'{local_path}/', node.path)
|
||||
threads.append(t)
|
||||
results = [x.result() for x in futures.as_completed(threads)]
|
||||
shutil.rmtree(local_path)
|
||||
|
|
|
@ -110,10 +110,10 @@ class DoView(View):
|
|||
else:
|
||||
latest_history = pipe.pipehistory_set.first()
|
||||
ordinal = latest_history.ordinal + 1 if latest_history else 1
|
||||
history = PipeHistory.objects.create(pipeline=pipe, ordinal=ordinal, created_by=request.user)
|
||||
PipeHistory.objects.create(pipeline=pipe, ordinal=ordinal, created_by=request.user)
|
||||
|
||||
rds = get_redis_connection()
|
||||
executor = NodeExecutor(rds, history.deploy_key, json.loads(pipe.nodes))
|
||||
executor = NodeExecutor(rds, token, json.loads(pipe.nodes))
|
||||
Thread(target=executor.run).start()
|
||||
response = AttrDict(token=token, nodes=nodes)
|
||||
return json_response(response)
|
||||
|
|
|
@ -96,7 +96,6 @@ function Body() {
|
|||
}, [S.node])
|
||||
|
||||
function handleTabChange(v) {
|
||||
S.node._id = `${S.node.id}.${v}`
|
||||
S.node._host_id = v
|
||||
S.node = Object.assign({}, S.node)
|
||||
}
|
||||
|
|
|
@ -14,12 +14,6 @@ import css from './sider.module.less';
|
|||
function Sider() {
|
||||
function handleClick(node) {
|
||||
node = lds.cloneDeep(node)
|
||||
if (['ssh_exec', 'data_transfer', 'data_upload'].includes(node.module)) {
|
||||
node._host_id = node._targets[0].id
|
||||
node._id = `${node.id}.${node._host_id}`
|
||||
} else if (node.module === 'build') {
|
||||
node._host_id = node.target
|
||||
}
|
||||
S.node = node
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ import { observable, computed } from 'mobx';
|
|||
import { transfer } from '../utils';
|
||||
|
||||
class Store {
|
||||
host_id = null;
|
||||
@observable token = null;
|
||||
@observable record = null;
|
||||
@observable node = {};
|
||||
|
@ -16,7 +15,13 @@ class Store {
|
|||
@observable dynamicParams = null;
|
||||
|
||||
@computed get nodeID() {
|
||||
return this.node._id ?? this.node.id
|
||||
if (['ssh_exec', 'data_transfer', 'data_upload'].includes(this.node.module)) {
|
||||
if (!this.node._host_id) this.node._host_id = this.node._targets[0].id
|
||||
return `${this.node.id}.${this.node._host_id}`
|
||||
} else if (this.node.module === 'build') {
|
||||
this._host_id = this.node.target
|
||||
}
|
||||
return this.node.id
|
||||
}
|
||||
|
||||
@computed get matrixNodes() {
|
||||
|
|
|
@ -31,7 +31,8 @@ function DataTransfer(props) {
|
|||
<Form.Item required name="name" label="节点名称">
|
||||
<Input placeholder="请输入节点名称"/>
|
||||
</Form.Item>
|
||||
<Form.Item required name="condition" label="执行条件" tooltip="当该节点为流程的起始节点时(无上游节点),该条件将会被忽略。">
|
||||
<Form.Item required name="condition" label="执行条件"
|
||||
tooltip="当该节点为流程的起始节点时(无上游节点),该条件将会被忽略。">
|
||||
<Radio.Group>
|
||||
<Radio.Button value="success">上游执行成功时</Radio.Button>
|
||||
<Radio.Button value="error">上游执行失败时</Radio.Button>
|
||||
|
@ -39,7 +40,8 @@ function DataTransfer(props) {
|
|||
</Radio.Group>
|
||||
</Form.Item>
|
||||
<Card type="inner" title="数据源" style={{margin: '24px 0'}} bodyStyle={{paddingBottom: 0}}>
|
||||
<Form.Item required name={['source', 'path']} label="数据源路径">
|
||||
<Form.Item required name={['source', 'path']} label="数据源路径"
|
||||
tooltip="当数据源是目录时,则同步目录下的所有文件至目标路径">
|
||||
<Input placeholder="请输入数据源路径"/>
|
||||
</Form.Item>
|
||||
<Form.Item required name={['source', 'target']} label="数据源主机">
|
||||
|
@ -47,7 +49,8 @@ function DataTransfer(props) {
|
|||
</Form.Item>
|
||||
</Card>
|
||||
<Card type="inner" title="传输目标" style={{margin: '24px 0'}} bodyStyle={{paddingBottom: 0}}>
|
||||
<Form.Item required name={['destination', 'path']} label="目标路径">
|
||||
<Form.Item required name={['destination', 'path']} label="目标路径"
|
||||
tooltip="当数据源是文件时,此路径以 / 结尾则同步文件至该路径下(新建或覆盖路径下的同名文件),否则该路径即为同步之后的文件路径(可理解为把源文件同步后重命名)">
|
||||
<Input placeholder="请输入目标路径"/>
|
||||
</Form.Item>
|
||||
<Form.Item required name={['destination', 'targets']} label="目标主机">
|
||||
|
|
|
@ -41,10 +41,10 @@ function DataUpload(props) {
|
|||
<Radio.Button value="always">总是执行</Radio.Button>
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
<Form.Item required name="targets" label="选择主机" tooltip="数据将会上传到选择的主机上">
|
||||
<Form.Item required name="targets" label="选择上传目标主机" tooltip="数据将会上传到选择的主机上">
|
||||
<HostSelector type="button"/>
|
||||
</Form.Item>
|
||||
<Form.Item required name="path" label="上传路径(目录)" tooltip="文件将会上传到该目录下,同名文件将会被覆盖">
|
||||
<Form.Item required name="path" label="上传路径(目录)" tooltip="文件将会上传到所选择主机的该目录下,同名文件将会被覆盖">
|
||||
<Input placeholder="请输入上传路径"/>
|
||||
</Form.Item>
|
||||
<Form.Item name="accept" label="文件类型限制" tooltip="限制上传的文件类型,">
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
.formTips {
|
||||
margin-bottom: 16px;
|
||||
padding: 4px;
|
||||
padding: 4px 4px 0 4px;
|
||||
|
||||
.content {
|
||||
font-size: 13px;
|
||||
font-size: 12px;
|
||||
margin: 0;
|
||||
color: #ff4d4f;
|
||||
white-space: pre-line;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import { computed, observable } from 'mobx';
|
|||
import { http, includes } from 'libs';
|
||||
import { message } from 'antd';
|
||||
import S from './console/store';
|
||||
import lds from 'lodash';
|
||||
|
||||
class Store {
|
||||
@observable records = [];
|
||||
|
@ -51,7 +52,7 @@ class Store {
|
|||
S.record = record
|
||||
S.token = res.token
|
||||
S.nodes = res.nodes
|
||||
S.node = res.nodes[0]
|
||||
S.node = lds.cloneDeep(res.nodes[0])
|
||||
S.outputs = {}
|
||||
S.dynamicParams = res.dynamic_params ? res.dynamic_params : null
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue