kdeploy 1.2.41 → 1.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +53 -1
- data/README_EN.md +86 -2
- data/lib/kdeploy/{cli.rb → cli/cli.rb} +74 -7
- data/lib/kdeploy/{help_formatter.rb → cli/help_formatter.rb} +5 -0
- data/lib/kdeploy/{configuration.rb → config/configuration.rb} +25 -1
- data/lib/kdeploy/{dsl.rb → dsl/dsl.rb} +9 -7
- data/lib/kdeploy/{initializer.rb → dsl/initializer.rb} +3 -3
- data/lib/kdeploy/errors.rb +7 -0
- data/lib/kdeploy/executor/command_executor.rb +155 -0
- data/lib/kdeploy/{executor.rb → executor/executor.rb} +151 -20
- data/lib/kdeploy/{output_formatter.rb → output/output_formatter.rb} +1 -0
- data/lib/kdeploy/{runner.rb → runner/runner.rb} +114 -43
- data/lib/kdeploy/{template.rb → template/template.rb} +25 -2
- data/lib/kdeploy/version.rb +1 -1
- data/lib/kdeploy.rb +12 -12
- metadata +14 -15
- data/lib/kdeploy/command_executor.rb +0 -102
- data/r.md +0 -1
- /data/lib/kdeploy/{file_filter.rb → executor/file_filter.rb} +0 -0
- /data/lib/kdeploy/{output.rb → output/output.rb} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bd3c4b1e7ad1dc2062bfa0e732144b64f0c3c81655320dc96defeaed10816392
|
|
4
|
+
data.tar.gz: 2ac13e3f6b7093042d4a313c139ad997e59e06b1fa2d6dc7372dc33919f3eebc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f224afb29cf1d419a80aa7797841b1fd935030841c0f80ad403e25573635e45956b8779c6518f6c37b4150c110c19f200baa1247ea03353e442ba6e0a5061a65
|
|
7
|
+
data.tar.gz: d6cae91436717b81f3a527707f7bed7e93107d868bf457b3ec9e62d859b42b241103f8600315155fd5e9409a09671319f487f7e0e4ea0f276d9dd8a48cd3ec2a
|
data/README.md
CHANGED
|
@@ -207,6 +207,10 @@ kdeploy execute deploy.rb deploy_web
|
|
|
207
207
|
- `--format FORMAT`: 输出格式(`text`|`json`,默认 `text`)
|
|
208
208
|
- `--retries N`: 网络相关操作重试次数(默认 `0`)
|
|
209
209
|
- `--retry-delay SECONDS`: 每次重试间隔秒数(默认 `1`)
|
|
210
|
+
- `--retry-on-nonzero`: 非零退出码重试开关(默认 `false`)
|
|
211
|
+
- `--timeout SECONDS`: 单 host 执行超时(秒,默认不启用)
|
|
212
|
+
- `--step-timeout SECONDS`: 单 step 执行超时(秒,默认不启用)
|
|
213
|
+
- `--retry-policy JSON`: 重试策略 JSON(覆盖 `.kdeploy.yml`)
|
|
210
214
|
|
|
211
215
|
**示例:**
|
|
212
216
|
```bash
|
|
@@ -228,6 +232,21 @@ kdeploy execute deploy.rb deploy_web --format json --no-banner
|
|
|
228
232
|
# 重试网络抖动导致的失败
|
|
229
233
|
kdeploy execute deploy.rb deploy_web --retries 3 --retry-delay 1
|
|
230
234
|
|
|
235
|
+
# 对非零退出码进行重试
|
|
236
|
+
kdeploy execute deploy.rb deploy_web --retries 2 --retry-on-nonzero
|
|
237
|
+
|
|
238
|
+
# 设置单 host 超时(秒)
|
|
239
|
+
kdeploy execute deploy.rb deploy_web --timeout 120
|
|
240
|
+
|
|
241
|
+
# 设置单 step 超时(秒)
|
|
242
|
+
kdeploy execute deploy.rb deploy_web --step-timeout 30
|
|
243
|
+
|
|
244
|
+
# 使用 CLI 覆盖重试策略(JSON)
|
|
245
|
+
kdeploy execute deploy.rb deploy_web --retry-policy '{"run":{"retries":2,"retry_on_exit_codes":[2]}}'
|
|
246
|
+
|
|
247
|
+
# 使用文件覆盖重试策略(JSON)
|
|
248
|
+
kdeploy execute deploy.rb deploy_web --retry-policy-file ./retry_policy.example.json
|
|
249
|
+
|
|
231
250
|
# 组合选项
|
|
232
251
|
kdeploy execute deploy.rb deploy_web --limit web01 --parallel 3 --dry-run
|
|
233
252
|
```
|
|
@@ -501,6 +520,14 @@ sync "./app", "/var/www/app",
|
|
|
501
520
|
# 排除特定文件(与 ignore 相同,但语义更清晰)
|
|
502
521
|
sync "./config", "/etc/app",
|
|
503
522
|
exclude: ["*.example", "*.bak", ".env.local"]
|
|
523
|
+
|
|
524
|
+
# 启用快速同步(本地/远端均有 rsync 时优先使用)
|
|
525
|
+
sync "./app", "/var/www/app",
|
|
526
|
+
fast: true
|
|
527
|
+
|
|
528
|
+
# 设置同步并行度
|
|
529
|
+
sync "./app", "/var/www/app",
|
|
530
|
+
parallel: 4
|
|
504
531
|
```
|
|
505
532
|
|
|
506
533
|
**参数:**
|
|
@@ -509,6 +536,8 @@ sync "./config", "/etc/app",
|
|
|
509
536
|
- `ignore`: 要忽略的文件/目录模式数组(支持 .gitignore 风格的通配符)
|
|
510
537
|
- `exclude`: 与 `ignore` 相同,用于语义清晰
|
|
511
538
|
- `delete`: 布尔值,是否删除远程目录中不存在于源目录的文件(默认: false)
|
|
539
|
+
- `fast`: 布尔值,启用快速同步路径(优先 rsync,默认: false)
|
|
540
|
+
- `parallel`: 上传并行度(默认: 1)
|
|
512
541
|
|
|
513
542
|
**忽略模式支持:**
|
|
514
543
|
- `*.log` - 匹配所有 .log 文件
|
|
@@ -682,10 +711,24 @@ export KDEPLOY_SSH_TIMEOUT=60
|
|
|
682
711
|
parallel: 5
|
|
683
712
|
ssh_timeout: 60
|
|
684
713
|
verify_host_key: true
|
|
714
|
+
retries: 2
|
|
715
|
+
retry_delay: 1
|
|
716
|
+
retry_on_nonzero: false
|
|
717
|
+
step_timeout: 30
|
|
718
|
+
sync_fast: false
|
|
719
|
+
sync_parallel: 4
|
|
720
|
+
retry_policy:
|
|
721
|
+
run:
|
|
722
|
+
retries: 2
|
|
723
|
+
retry_on_exit_codes: [2, 255]
|
|
724
|
+
upload:
|
|
725
|
+
retries: 0
|
|
685
726
|
```
|
|
686
727
|
|
|
687
728
|
配置文件会自动从当前目录向上查找,直到找到 `.kdeploy.yml` 文件。
|
|
688
729
|
|
|
730
|
+
**重试策略示例文件**: `retry_policy.example.json`
|
|
731
|
+
|
|
689
732
|
## 🔧 高级用法
|
|
690
733
|
|
|
691
734
|
### 条件执行
|
|
@@ -702,6 +745,16 @@ task :deploy do
|
|
|
702
745
|
end
|
|
703
746
|
```
|
|
704
747
|
|
|
748
|
+
### 重试策略示例
|
|
749
|
+
|
|
750
|
+
你可以通过文件覆盖重试策略:
|
|
751
|
+
|
|
752
|
+
```bash
|
|
753
|
+
kdeploy execute deploy.rb deploy_web --retry-policy-file ./retry_policy.example.json
|
|
754
|
+
```
|
|
755
|
+
|
|
756
|
+
示例文件见:`retry_policy.example.json` / `retry_policy.example.yml`
|
|
757
|
+
|
|
705
758
|
### 循环主机
|
|
706
759
|
|
|
707
760
|
```ruby
|
|
@@ -1141,4 +1194,3 @@ end
|
|
|
1141
1194
|
---
|
|
1142
1195
|
|
|
1143
1196
|
**为 DevOps 社区用 ❤️ 制作**
|
|
1144
|
-
|
data/README_EN.md
CHANGED
|
@@ -206,6 +206,11 @@ kdeploy execute deploy.rb deploy_web
|
|
|
206
206
|
- `--format FORMAT`: Output format (`text`|`json`, default `text`)
|
|
207
207
|
- `--retries N`: Retry count for network operations (default `0`)
|
|
208
208
|
- `--retry-delay SECONDS`: Delay between retries in seconds (default `1`)
|
|
209
|
+
- `--retry-on-nonzero`: Retry commands on nonzero exit status (default `false`)
|
|
210
|
+
- `--timeout SECONDS`: Per-host execution timeout in seconds (default: none)
|
|
211
|
+
- `--step-timeout SECONDS`: Per-step execution timeout in seconds (default: none)
|
|
212
|
+
- `--retry-policy JSON`: Retry policy JSON (overrides `.kdeploy.yml`)
|
|
213
|
+
- `--retry-policy-file PATH`: Retry policy JSON file (overrides `.kdeploy.yml`)
|
|
209
214
|
|
|
210
215
|
**Examples:**
|
|
211
216
|
```bash
|
|
@@ -227,6 +232,21 @@ kdeploy execute deploy.rb deploy_web --format json --no-banner
|
|
|
227
232
|
# Retry transient network failures
|
|
228
233
|
kdeploy execute deploy.rb deploy_web --retries 3 --retry-delay 1
|
|
229
234
|
|
|
235
|
+
# Retry on nonzero exit status
|
|
236
|
+
kdeploy execute deploy.rb deploy_web --retries 2 --retry-on-nonzero
|
|
237
|
+
|
|
238
|
+
# Set per-host timeout (seconds)
|
|
239
|
+
kdeploy execute deploy.rb deploy_web --timeout 120
|
|
240
|
+
|
|
241
|
+
# Set per-step timeout (seconds)
|
|
242
|
+
kdeploy execute deploy.rb deploy_web --step-timeout 30
|
|
243
|
+
|
|
244
|
+
# Override retry policy via CLI JSON
|
|
245
|
+
kdeploy execute deploy.rb deploy_web --retry-policy '{"run":{"retries":2,"retry_on_exit_codes":[2]}}'
|
|
246
|
+
|
|
247
|
+
# Override retry policy via file
|
|
248
|
+
kdeploy execute deploy.rb deploy_web --retry-policy-file ./retry_policy.example.json
|
|
249
|
+
|
|
230
250
|
# Combine options
|
|
231
251
|
kdeploy execute deploy.rb deploy_web --limit web01 --parallel 3 --dry-run
|
|
232
252
|
```
|
|
@@ -480,6 +500,45 @@ upload_template "./config/nginx.conf.erb", "/etc/nginx/nginx.conf",
|
|
|
480
500
|
- `destination`: Remote file path
|
|
481
501
|
- `variables`: Hash of variables for template rendering
|
|
482
502
|
|
|
503
|
+
#### `sync` - Directory Sync
|
|
504
|
+
|
|
505
|
+
Recursively sync a local directory to a remote server with filtering options.
|
|
506
|
+
|
|
507
|
+
```ruby
|
|
508
|
+
# Basic sync
|
|
509
|
+
sync "./app", "/var/www/app"
|
|
510
|
+
|
|
511
|
+
# Ignore specific files/dirs
|
|
512
|
+
sync "./app", "/var/www/app",
|
|
513
|
+
ignore: [".git", "*.log", "node_modules", "*.tmp"]
|
|
514
|
+
|
|
515
|
+
# Delete remote files not present locally
|
|
516
|
+
sync "./app", "/var/www/app",
|
|
517
|
+
ignore: [".git", "*.log"],
|
|
518
|
+
delete: true
|
|
519
|
+
|
|
520
|
+
# Exclude files (alias of ignore)
|
|
521
|
+
sync "./config", "/etc/app",
|
|
522
|
+
exclude: ["*.example", "*.bak", ".env.local"]
|
|
523
|
+
|
|
524
|
+
# Fast sync (prefer rsync when available)
|
|
525
|
+
sync "./app", "/var/www/app",
|
|
526
|
+
fast: true
|
|
527
|
+
|
|
528
|
+
# Parallel sync uploads
|
|
529
|
+
sync "./app", "/var/www/app",
|
|
530
|
+
parallel: 4
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
**Parameters:**
|
|
534
|
+
- `source`: Local source directory path
|
|
535
|
+
- `destination`: Remote destination directory path
|
|
536
|
+
- `ignore`: Patterns to ignore (gitignore-style)
|
|
537
|
+
- `exclude`: Same as `ignore` for clarity
|
|
538
|
+
- `delete`: Delete remote files not present locally (default: false)
|
|
539
|
+
- `fast`: Enable fast sync path (prefer rsync when available, default: false)
|
|
540
|
+
- `parallel`: Upload concurrency for sync (default: 1)
|
|
541
|
+
|
|
483
542
|
### Chef-Style Resource DSL
|
|
484
543
|
|
|
485
544
|
Kdeploy provides a declarative resource DSL similar to Chef, which can replace or mix with low-level primitives (`run`, `upload`, `upload_template`).
|
|
@@ -639,7 +698,21 @@ For project-specific configuration, create a `.kdeploy.yml`:
|
|
|
639
698
|
parallel: 5
|
|
640
699
|
ssh_timeout: 60
|
|
641
700
|
verify_host_key: true
|
|
642
|
-
|
|
701
|
+
retries: 2
|
|
702
|
+
retry_delay: 1
|
|
703
|
+
retry_on_nonzero: false
|
|
704
|
+
step_timeout: 30
|
|
705
|
+
sync_fast: false
|
|
706
|
+
sync_parallel: 4
|
|
707
|
+
retry_policy:
|
|
708
|
+
run:
|
|
709
|
+
retries: 2
|
|
710
|
+
retry_on_exit_codes: [2, 255]
|
|
711
|
+
upload:
|
|
712
|
+
retries: 0
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
**Retry policy example file**: `retry_policy.example.json`
|
|
643
716
|
|
|
644
717
|
## 🔧 Advanced Usage
|
|
645
718
|
|
|
@@ -657,6 +730,16 @@ task :deploy do
|
|
|
657
730
|
end
|
|
658
731
|
```
|
|
659
732
|
|
|
733
|
+
### Retry Policy Example
|
|
734
|
+
|
|
735
|
+
You can override retry policy via file:
|
|
736
|
+
|
|
737
|
+
```bash
|
|
738
|
+
kdeploy execute deploy.rb deploy_web --retry-policy-file ./retry_policy.example.json
|
|
739
|
+
```
|
|
740
|
+
|
|
741
|
+
Example files: `retry_policy.example.json` / `retry_policy.example.yml`
|
|
742
|
+
|
|
660
743
|
### Looping Over Hosts
|
|
661
744
|
|
|
662
745
|
```ruby
|
|
@@ -1123,7 +1206,8 @@ end
|
|
|
1123
1206
|
task :deploy_app, roles: :web do
|
|
1124
1207
|
sync "./app", "/var/www/app",
|
|
1125
1208
|
ignore: [".git", "*.log", "node_modules", ".env.local", "*.tmp"],
|
|
1126
|
-
delete: true
|
|
1209
|
+
delete: true,
|
|
1210
|
+
fast: true # prefer rsync when available
|
|
1127
1211
|
sync "./config", "/etc/app", exclude: ["*.example", "*.bak"]
|
|
1128
1212
|
service "app", action: :restart
|
|
1129
1213
|
end
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require 'thor'
|
|
4
4
|
require 'json'
|
|
5
|
+
require 'yaml'
|
|
5
6
|
require 'pastel'
|
|
6
7
|
require 'tty-table'
|
|
7
8
|
require 'tty-box'
|
|
@@ -51,6 +52,11 @@ module Kdeploy
|
|
|
51
52
|
method_option :format, type: :string, default: 'text', desc: 'Output format (text|json)'
|
|
52
53
|
method_option :retries, type: :numeric, desc: 'Retry count for network operations (default: 0)'
|
|
53
54
|
method_option :retry_delay, type: :numeric, desc: 'Retry delay seconds (default: 1)'
|
|
55
|
+
method_option :retry_on_nonzero, type: :boolean, desc: 'Retry commands on nonzero exit status (default: false)'
|
|
56
|
+
method_option :timeout, type: :numeric, desc: 'Per-host execution timeout seconds (default: none)'
|
|
57
|
+
method_option :step_timeout, type: :numeric, desc: 'Per-step execution timeout seconds (default: none)'
|
|
58
|
+
method_option :retry_policy, type: :string, desc: 'Retry policy JSON to override config file'
|
|
59
|
+
method_option :retry_policy_file, type: :string, desc: 'Retry policy JSON file to override config file'
|
|
54
60
|
def execute(task_file, task_name = nil)
|
|
55
61
|
load_config_file
|
|
56
62
|
show_banner_once
|
|
@@ -75,7 +81,7 @@ module Kdeploy
|
|
|
75
81
|
|
|
76
82
|
def load_task_file(file)
|
|
77
83
|
validate_task_file(file)
|
|
78
|
-
#
|
|
84
|
+
# Use module_eval with top-level binding to keep heredoc compatible
|
|
79
85
|
self.class.module_eval(File.read(file), file)
|
|
80
86
|
rescue StandardError => e
|
|
81
87
|
raise FileNotFoundError, file if e.message.include?('not found')
|
|
@@ -267,6 +273,11 @@ module Kdeploy
|
|
|
267
273
|
debug_mode = options[:debug] || false
|
|
268
274
|
retries = options[:retries].nil? ? Configuration.default_retries : options[:retries]
|
|
269
275
|
retry_delay = options[:retry_delay].nil? ? Configuration.default_retry_delay : options[:retry_delay]
|
|
276
|
+
retry_on_nonzero =
|
|
277
|
+
options[:retry_on_nonzero].nil? ? Configuration.default_retry_on_nonzero : options[:retry_on_nonzero]
|
|
278
|
+
host_timeout = options[:timeout].nil? ? Configuration.default_host_timeout : options[:timeout]
|
|
279
|
+
step_timeout = options[:step_timeout].nil? ? Configuration.default_step_timeout : options[:step_timeout]
|
|
280
|
+
retry_policy = resolve_retry_policy
|
|
270
281
|
base_dir = @task_file_dir
|
|
271
282
|
runner = Runner.new(
|
|
272
283
|
hosts, self.class.kdeploy_tasks,
|
|
@@ -275,7 +286,11 @@ module Kdeploy
|
|
|
275
286
|
debug: debug_mode,
|
|
276
287
|
base_dir: base_dir,
|
|
277
288
|
retries: retries,
|
|
278
|
-
retry_delay: retry_delay
|
|
289
|
+
retry_delay: retry_delay,
|
|
290
|
+
retry_on_nonzero: retry_on_nonzero,
|
|
291
|
+
host_timeout: host_timeout,
|
|
292
|
+
step_timeout: step_timeout,
|
|
293
|
+
retry_policy: retry_policy
|
|
279
294
|
)
|
|
280
295
|
results = runner.run(task)
|
|
281
296
|
if options[:format] == 'json'
|
|
@@ -363,13 +378,13 @@ module Kdeploy
|
|
|
363
378
|
duration: step[:duration]
|
|
364
379
|
}
|
|
365
380
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
if options[:debug] && step[:type] == :run && step[:output].is_a?(Hash)
|
|
381
|
+
if step[:output].is_a?(Hash)
|
|
369
382
|
out[:stdout] = step[:output][:stdout]
|
|
370
383
|
out[:stderr] = step[:output][:stderr]
|
|
384
|
+
out[:exit_status] = step[:output][:exit_status]
|
|
371
385
|
end
|
|
372
386
|
|
|
387
|
+
out[:result] = step[:result] if step[:type] == :sync
|
|
373
388
|
out
|
|
374
389
|
end
|
|
375
390
|
|
|
@@ -388,7 +403,9 @@ module Kdeploy
|
|
|
388
403
|
destination: cmd[:destination],
|
|
389
404
|
ignore: cmd[:ignore] || [],
|
|
390
405
|
exclude: cmd[:exclude] || [],
|
|
391
|
-
delete: cmd[:delete] || false
|
|
406
|
+
delete: cmd[:delete] || false,
|
|
407
|
+
fast: cmd[:fast],
|
|
408
|
+
parallel: cmd[:parallel]
|
|
392
409
|
}
|
|
393
410
|
else
|
|
394
411
|
{ type: cmd[:type].to_s }
|
|
@@ -400,11 +417,61 @@ module Kdeploy
|
|
|
400
417
|
|
|
401
418
|
if result[:output].is_a?(Array)
|
|
402
419
|
result[:output].map do |o|
|
|
403
|
-
|
|
420
|
+
next unless o.is_a?(Hash)
|
|
421
|
+
|
|
422
|
+
err = o[:output]
|
|
423
|
+
next unless err.is_a?(Hash)
|
|
424
|
+
|
|
425
|
+
pieces = []
|
|
426
|
+
pieces << "command=#{err[:command]}" if err[:command]
|
|
427
|
+
pieces << "exit_status=#{err[:exit_status]}" if err[:exit_status]
|
|
428
|
+
pieces << "stderr=#{err[:stderr]}" if err[:stderr]
|
|
429
|
+
pieces.join(' ')
|
|
404
430
|
end.compact.join("\n")
|
|
405
431
|
else
|
|
406
432
|
result[:output].to_s
|
|
407
433
|
end
|
|
408
434
|
end
|
|
435
|
+
|
|
436
|
+
def parse_retry_policy(raw)
|
|
437
|
+
policy = JSON.parse(raw)
|
|
438
|
+
raise ArgumentError, 'retry_policy must be a JSON object' unless policy.is_a?(Hash)
|
|
439
|
+
|
|
440
|
+
policy
|
|
441
|
+
rescue JSON::ParserError => e
|
|
442
|
+
raise ArgumentError, "retry_policy JSON parse error: #{e.message}"
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
def resolve_retry_policy
|
|
446
|
+
if options[:retry_policy_file]
|
|
447
|
+
path = options[:retry_policy_file]
|
|
448
|
+
unless File.exist?(path)
|
|
449
|
+
raise ArgumentError,
|
|
450
|
+
"retry_policy file not found: #{path} (examples: retry_policy.example.json / retry_policy.example.yml)"
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
return parse_retry_policy_file(path)
|
|
454
|
+
end
|
|
455
|
+
return parse_retry_policy(options[:retry_policy]) if options[:retry_policy]
|
|
456
|
+
|
|
457
|
+
Configuration.default_retry_policy
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
def parse_retry_policy_file(path)
|
|
461
|
+
ext = File.extname(path).downcase
|
|
462
|
+
raw = File.read(path)
|
|
463
|
+
policy =
|
|
464
|
+
case ext
|
|
465
|
+
when '.yml', '.yaml'
|
|
466
|
+
YAML.safe_load(raw) || {}
|
|
467
|
+
else
|
|
468
|
+
JSON.parse(raw)
|
|
469
|
+
end
|
|
470
|
+
raise ArgumentError, 'retry_policy must be a JSON/YAML object' unless policy.is_a?(Hash)
|
|
471
|
+
|
|
472
|
+
policy
|
|
473
|
+
rescue JSON::ParserError, Psych::SyntaxError => e
|
|
474
|
+
raise ArgumentError, "retry_policy parse error: #{e.message}"
|
|
475
|
+
end
|
|
409
476
|
end
|
|
410
477
|
end
|
|
@@ -34,6 +34,11 @@ module Kdeploy
|
|
|
34
34
|
#{@pastel.dim(' --format FORMAT')} Output format (text|json)
|
|
35
35
|
#{@pastel.dim(' --retries N')} Retry count for network operations (default: 0; overridden by .kdeploy.yml)
|
|
36
36
|
#{@pastel.dim(' --retry-delay SECONDS')} Retry delay seconds (default: 1; overridden by .kdeploy.yml)
|
|
37
|
+
#{@pastel.dim(' --retry-on-nonzero')} Retry commands on nonzero exit status (default: false; overridden by .kdeploy.yml)
|
|
38
|
+
#{@pastel.dim(' --timeout SECONDS')} Per-host execution timeout seconds (default: none; overridden by .kdeploy.yml)
|
|
39
|
+
#{@pastel.dim(' --step-timeout SECONDS')} Per-step execution timeout seconds (default: none; overridden by .kdeploy.yml)
|
|
40
|
+
#{@pastel.dim(' --retry-policy JSON')} Retry policy JSON (overrides .kdeploy.yml)
|
|
41
|
+
#{@pastel.dim(' --retry-policy-file PATH')} Retry policy JSON file (overrides .kdeploy.yml)
|
|
37
42
|
|
|
38
43
|
#{@pastel.bright_yellow('🆕')} #{@pastel.bright_white('init [DIR]')} Initialize new deployment project
|
|
39
44
|
#{@pastel.bright_yellow('ℹ️')} #{@pastel.bright_white('version')} Show version information
|
|
@@ -10,6 +10,12 @@ module Kdeploy
|
|
|
10
10
|
DEFAULT_VERIFY_HOST_KEY = :never
|
|
11
11
|
DEFAULT_RETRIES = 0
|
|
12
12
|
DEFAULT_RETRY_DELAY = 1
|
|
13
|
+
DEFAULT_HOST_TIMEOUT = nil
|
|
14
|
+
DEFAULT_RETRY_ON_NONZERO = false
|
|
15
|
+
DEFAULT_SYNC_FAST = false
|
|
16
|
+
DEFAULT_STEP_TIMEOUT = nil
|
|
17
|
+
DEFAULT_RETRY_POLICY = nil
|
|
18
|
+
DEFAULT_SYNC_PARALLEL = 1
|
|
13
19
|
CONFIG_FILE_NAME = '.kdeploy.yml'
|
|
14
20
|
|
|
15
21
|
class << self
|
|
@@ -17,7 +23,13 @@ module Kdeploy
|
|
|
17
23
|
:default_ssh_timeout,
|
|
18
24
|
:default_verify_host_key,
|
|
19
25
|
:default_retries,
|
|
20
|
-
:default_retry_delay
|
|
26
|
+
:default_retry_delay,
|
|
27
|
+
:default_host_timeout,
|
|
28
|
+
:default_retry_on_nonzero,
|
|
29
|
+
:default_sync_fast,
|
|
30
|
+
:default_step_timeout,
|
|
31
|
+
:default_retry_policy,
|
|
32
|
+
:default_sync_parallel
|
|
21
33
|
|
|
22
34
|
def reset
|
|
23
35
|
@default_parallel = DEFAULT_PARALLEL
|
|
@@ -25,6 +37,12 @@ module Kdeploy
|
|
|
25
37
|
@default_verify_host_key = DEFAULT_VERIFY_HOST_KEY
|
|
26
38
|
@default_retries = DEFAULT_RETRIES
|
|
27
39
|
@default_retry_delay = DEFAULT_RETRY_DELAY
|
|
40
|
+
@default_host_timeout = DEFAULT_HOST_TIMEOUT
|
|
41
|
+
@default_retry_on_nonzero = DEFAULT_RETRY_ON_NONZERO
|
|
42
|
+
@default_sync_fast = DEFAULT_SYNC_FAST
|
|
43
|
+
@default_step_timeout = DEFAULT_STEP_TIMEOUT
|
|
44
|
+
@default_retry_policy = DEFAULT_RETRY_POLICY
|
|
45
|
+
@default_sync_parallel = DEFAULT_SYNC_PARALLEL
|
|
28
46
|
end
|
|
29
47
|
|
|
30
48
|
def load_from_file(config_path = nil)
|
|
@@ -64,6 +82,12 @@ module Kdeploy
|
|
|
64
82
|
@default_verify_host_key = parse_verify_host_key(config['verify_host_key']) if config.key?('verify_host_key')
|
|
65
83
|
@default_retries = config['retries'] if config.key?('retries')
|
|
66
84
|
@default_retry_delay = config['retry_delay'] if config.key?('retry_delay')
|
|
85
|
+
@default_host_timeout = config['host_timeout'] if config.key?('host_timeout')
|
|
86
|
+
@default_retry_on_nonzero = config['retry_on_nonzero'] if config.key?('retry_on_nonzero')
|
|
87
|
+
@default_sync_fast = config['sync_fast'] if config.key?('sync_fast')
|
|
88
|
+
@default_step_timeout = config['step_timeout'] if config.key?('step_timeout')
|
|
89
|
+
@default_retry_policy = config['retry_policy'] if config.key?('retry_policy')
|
|
90
|
+
@default_sync_parallel = config['sync_parallel'] if config.key?('sync_parallel')
|
|
67
91
|
end
|
|
68
92
|
|
|
69
93
|
def parse_verify_host_key(value)
|
|
@@ -161,7 +161,7 @@ module Kdeploy
|
|
|
161
161
|
}
|
|
162
162
|
end
|
|
163
163
|
|
|
164
|
-
def sync(source, destination, ignore: [], delete: false, exclude: [])
|
|
164
|
+
def sync(source, destination, ignore: [], delete: false, exclude: [], fast: nil, parallel: nil)
|
|
165
165
|
@kdeploy_commands ||= []
|
|
166
166
|
@kdeploy_commands << {
|
|
167
167
|
type: :sync,
|
|
@@ -169,7 +169,9 @@ module Kdeploy
|
|
|
169
169
|
destination: destination,
|
|
170
170
|
ignore: Array(ignore),
|
|
171
171
|
exclude: Array(exclude),
|
|
172
|
-
delete: delete
|
|
172
|
+
delete: delete,
|
|
173
|
+
fast: fast,
|
|
174
|
+
parallel: parallel
|
|
173
175
|
}
|
|
174
176
|
end
|
|
175
177
|
|
|
@@ -177,14 +179,14 @@ module Kdeploy
|
|
|
177
179
|
# Chef-style resource DSL (compiles to run/upload/upload_template)
|
|
178
180
|
# -------------------------------------------------------------------------
|
|
179
181
|
|
|
180
|
-
#
|
|
182
|
+
# Install a system package. Defaults to apt; supports platform: :yum.
|
|
181
183
|
def package(name, version: nil, platform: :apt)
|
|
182
184
|
@kdeploy_commands ||= []
|
|
183
185
|
cmd = build_package_command(name, version, platform)
|
|
184
186
|
@kdeploy_commands << { type: :run, command: cmd, sudo: true }
|
|
185
187
|
end
|
|
186
188
|
|
|
187
|
-
#
|
|
189
|
+
# Manage a systemd service. action supports :start, :stop, :restart, :reload, :enable, :disable.
|
|
188
190
|
def service(name, action: :start)
|
|
189
191
|
@kdeploy_commands ||= []
|
|
190
192
|
actions = Array(action)
|
|
@@ -194,7 +196,7 @@ module Kdeploy
|
|
|
194
196
|
end
|
|
195
197
|
end
|
|
196
198
|
|
|
197
|
-
#
|
|
199
|
+
# Deploy an ERB template to a remote path. Supports block and keyword args.
|
|
198
200
|
def template(destination, source: nil, variables: nil, &block)
|
|
199
201
|
@kdeploy_commands ||= []
|
|
200
202
|
if block
|
|
@@ -211,13 +213,13 @@ module Kdeploy
|
|
|
211
213
|
upload_template(src, destination, vars)
|
|
212
214
|
end
|
|
213
215
|
|
|
214
|
-
#
|
|
216
|
+
# Upload a local file to a remote path.
|
|
215
217
|
def file(destination, source:)
|
|
216
218
|
@kdeploy_commands ||= []
|
|
217
219
|
upload(source, destination)
|
|
218
220
|
end
|
|
219
221
|
|
|
220
|
-
#
|
|
222
|
+
# Ensure a remote directory exists. Supports mode option.
|
|
221
223
|
def directory(path, mode: nil)
|
|
222
224
|
@kdeploy_commands ||= []
|
|
223
225
|
cmd = "mkdir -p #{Shellwords.escape(path.to_s)}"
|
|
@@ -96,11 +96,11 @@ module Kdeploy
|
|
|
96
96
|
end
|
|
97
97
|
|
|
98
98
|
def create_config_files
|
|
99
|
-
#
|
|
99
|
+
# Create config directory
|
|
100
100
|
config_dir = File.join(@target_dir, 'config')
|
|
101
101
|
FileUtils.mkdir_p(config_dir)
|
|
102
102
|
|
|
103
|
-
#
|
|
103
|
+
# Create Nginx ERB template
|
|
104
104
|
File.write(File.join(config_dir, 'nginx.conf.erb'), <<~CONF)
|
|
105
105
|
user nginx;
|
|
106
106
|
worker_processes <%= worker_processes %>;
|
|
@@ -152,7 +152,7 @@ module Kdeploy
|
|
|
152
152
|
}
|
|
153
153
|
CONF
|
|
154
154
|
|
|
155
|
-
#
|
|
155
|
+
# Create static config file example
|
|
156
156
|
File.write(File.join(config_dir, 'app.conf'), <<~CONF)
|
|
157
157
|
location /api {
|
|
158
158
|
proxy_pass http://localhost:3000;
|
data/lib/kdeploy/errors.rb
CHANGED
|
@@ -52,6 +52,13 @@ module Kdeploy
|
|
|
52
52
|
attr_reader :original_error
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
+
# Raised when a step exceeds configured timeout
|
|
56
|
+
class StepTimeoutError < Error
|
|
57
|
+
def initialize(message)
|
|
58
|
+
super("Step timeout: #{message}")
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
55
62
|
# Raised when configuration is invalid
|
|
56
63
|
class ConfigurationError < Error
|
|
57
64
|
def initialize(message)
|