confctl 1.0.0
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 +7 -0
- data/.editorconfig +11 -0
- data/.gitignore +8 -0
- data/.overcommit.yml +6 -0
- data/.rubocop.yml +67 -0
- data/.rubocop_todo.yml +5 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +2 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +674 -0
- data/README.md +522 -0
- data/Rakefile +40 -0
- data/bin/confctl +4 -0
- data/confctl.gemspec +33 -0
- data/example/.gitignore +2 -0
- data/example/README.md +38 -0
- data/example/cluster/cluster.nix +7 -0
- data/example/cluster/module-list.nix +3 -0
- data/example/cluster/nixos-machine/config.nix +15 -0
- data/example/cluster/nixos-machine/hardware.nix +4 -0
- data/example/cluster/nixos-machine/module.nix +8 -0
- data/example/cluster/vpsadminos-container/config.nix +22 -0
- data/example/cluster/vpsadminos-container/module.nix +8 -0
- data/example/cluster/vpsadminos-machine/config.nix +22 -0
- data/example/cluster/vpsadminos-machine/hardware.nix +4 -0
- data/example/cluster/vpsadminos-machine/module.nix +8 -0
- data/example/cluster/vpsfreecz-vps/config.nix +25 -0
- data/example/cluster/vpsfreecz-vps/module.nix +8 -0
- data/example/configs/confctl.nix +10 -0
- data/example/configs/swpins.nix +28 -0
- data/example/data/default.nix +5 -0
- data/example/data/ssh-keys.nix +7 -0
- data/example/environments/base.nix +13 -0
- data/example/modules/module-list.nix +13 -0
- data/example/shell.nix +11 -0
- data/example/swpins/channels/nixos-unstable.json +35 -0
- data/example/swpins/channels/vpsadminos-staging.json +35 -0
- data/lib/confctl/cli/app.rb +551 -0
- data/lib/confctl/cli/attr_filters.rb +51 -0
- data/lib/confctl/cli/cluster.rb +1248 -0
- data/lib/confctl/cli/command.rb +206 -0
- data/lib/confctl/cli/configuration.rb +296 -0
- data/lib/confctl/cli/gen_data.rb +97 -0
- data/lib/confctl/cli/generation.rb +335 -0
- data/lib/confctl/cli/log_view.rb +267 -0
- data/lib/confctl/cli/output_formatter.rb +288 -0
- data/lib/confctl/cli/swpins/base.rb +40 -0
- data/lib/confctl/cli/swpins/channel.rb +73 -0
- data/lib/confctl/cli/swpins/cluster.rb +80 -0
- data/lib/confctl/cli/swpins/core.rb +86 -0
- data/lib/confctl/cli/swpins/utils.rb +55 -0
- data/lib/confctl/cli/swpins.rb +5 -0
- data/lib/confctl/cli/tag_filters.rb +30 -0
- data/lib/confctl/cli.rb +5 -0
- data/lib/confctl/conf_cache.rb +105 -0
- data/lib/confctl/conf_dir.rb +88 -0
- data/lib/confctl/erb_template.rb +37 -0
- data/lib/confctl/exceptions.rb +3 -0
- data/lib/confctl/gcroot.rb +30 -0
- data/lib/confctl/generation/build.rb +145 -0
- data/lib/confctl/generation/build_list.rb +106 -0
- data/lib/confctl/generation/host.rb +35 -0
- data/lib/confctl/generation/host_list.rb +81 -0
- data/lib/confctl/generation/unified.rb +117 -0
- data/lib/confctl/generation/unified_list.rb +63 -0
- data/lib/confctl/git_repo_mirror.rb +79 -0
- data/lib/confctl/health_checks/base.rb +66 -0
- data/lib/confctl/health_checks/run_command.rb +179 -0
- data/lib/confctl/health_checks/systemd/properties.rb +84 -0
- data/lib/confctl/health_checks/systemd/property_check.rb +31 -0
- data/lib/confctl/health_checks/systemd/property_list.rb +20 -0
- data/lib/confctl/health_checks.rb +5 -0
- data/lib/confctl/hook.rb +35 -0
- data/lib/confctl/line_buffer.rb +53 -0
- data/lib/confctl/logger.rb +151 -0
- data/lib/confctl/machine.rb +107 -0
- data/lib/confctl/machine_control.rb +172 -0
- data/lib/confctl/machine_list.rb +108 -0
- data/lib/confctl/machine_status.rb +135 -0
- data/lib/confctl/module_options.rb +95 -0
- data/lib/confctl/nix.rb +382 -0
- data/lib/confctl/nix_build.rb +108 -0
- data/lib/confctl/nix_collect_garbage.rb +64 -0
- data/lib/confctl/nix_copy.rb +49 -0
- data/lib/confctl/nix_format.rb +124 -0
- data/lib/confctl/nix_literal_expression.rb +15 -0
- data/lib/confctl/parallel_executor.rb +43 -0
- data/lib/confctl/pattern.rb +9 -0
- data/lib/confctl/settings.rb +50 -0
- data/lib/confctl/std_line_buffer.rb +40 -0
- data/lib/confctl/swpins/change_set.rb +151 -0
- data/lib/confctl/swpins/channel.rb +62 -0
- data/lib/confctl/swpins/channel_list.rb +47 -0
- data/lib/confctl/swpins/cluster_name.rb +94 -0
- data/lib/confctl/swpins/cluster_name_list.rb +15 -0
- data/lib/confctl/swpins/core.rb +137 -0
- data/lib/confctl/swpins/deployed_info.rb +23 -0
- data/lib/confctl/swpins/spec.rb +20 -0
- data/lib/confctl/swpins/specs/base.rb +184 -0
- data/lib/confctl/swpins/specs/directory.rb +51 -0
- data/lib/confctl/swpins/specs/git.rb +135 -0
- data/lib/confctl/swpins/specs/git_rev.rb +24 -0
- data/lib/confctl/swpins.rb +17 -0
- data/lib/confctl/system_command.rb +10 -0
- data/lib/confctl/user_script.rb +13 -0
- data/lib/confctl/user_scripts.rb +41 -0
- data/lib/confctl/utils/file.rb +21 -0
- data/lib/confctl/version.rb +3 -0
- data/lib/confctl.rb +43 -0
- data/man/man8/confctl-options.nix.8 +1334 -0
- data/man/man8/confctl-options.nix.8.md +1340 -0
- data/man/man8/confctl.8 +660 -0
- data/man/man8/confctl.8.md +654 -0
- data/nix/evaluator.nix +160 -0
- data/nix/lib/default.nix +83 -0
- data/nix/lib/machine/default.nix +74 -0
- data/nix/lib/machine/info.nix +5 -0
- data/nix/lib/swpins/eval.nix +71 -0
- data/nix/lib/swpins/options.nix +94 -0
- data/nix/machines.nix +31 -0
- data/nix/modules/cluster/default.nix +459 -0
- data/nix/modules/confctl/cli.nix +21 -0
- data/nix/modules/confctl/generations.nix +84 -0
- data/nix/modules/confctl/nix.nix +28 -0
- data/nix/modules/confctl/swpins.nix +55 -0
- data/nix/modules/module-list.nix +19 -0
- data/shell.nix +42 -0
- data/template/confctl-options.nix/main.erb +45 -0
- data/template/confctl-options.nix/options.erb +15 -0
- metadata +353 -0
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
require 'rainbow'
|
|
2
|
+
|
|
3
|
+
module ConfCtl::Cli
|
|
4
|
+
class OutputFormatter
|
|
5
|
+
def self.to_s(*args)
|
|
6
|
+
f = new(*args)
|
|
7
|
+
f.to_s
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def self.print(*args, **kwargs)
|
|
11
|
+
f = new(*args, **kwargs)
|
|
12
|
+
f.print
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def initialize(objects, cols = nil, header: true, sort: nil, layout: nil, empty: '-', color: false)
|
|
16
|
+
@objects = objects
|
|
17
|
+
@header = header
|
|
18
|
+
@sort = sort
|
|
19
|
+
@layout = layout
|
|
20
|
+
@empty = empty
|
|
21
|
+
@color = color
|
|
22
|
+
|
|
23
|
+
if @layout.nil?
|
|
24
|
+
@layout = if many?
|
|
25
|
+
:columns
|
|
26
|
+
|
|
27
|
+
else
|
|
28
|
+
:rows
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
if cols
|
|
33
|
+
@cols = parse_cols(cols)
|
|
34
|
+
|
|
35
|
+
elsif @objects.is_a?(::Array)
|
|
36
|
+
if @objects.count == 0
|
|
37
|
+
@cols = []
|
|
38
|
+
else
|
|
39
|
+
@cols ||= parse_cols(@objects.first.keys)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
elsif @objects.is_a?(::Hash) # Single item
|
|
43
|
+
@cols ||= parse_cols(@objects.keys)
|
|
44
|
+
|
|
45
|
+
else
|
|
46
|
+
raise "unsupported type #{@objects.class}"
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def to_s
|
|
51
|
+
@out = ''
|
|
52
|
+
generate
|
|
53
|
+
@out
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def print
|
|
57
|
+
@out = nil
|
|
58
|
+
generate
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
protected
|
|
62
|
+
|
|
63
|
+
def parse_cols(cols)
|
|
64
|
+
ret = []
|
|
65
|
+
|
|
66
|
+
cols.each do |c|
|
|
67
|
+
base = {
|
|
68
|
+
align: 'left'
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if c.is_a?(::String) || c.is_a?(::Symbol)
|
|
72
|
+
base.update({
|
|
73
|
+
name: c,
|
|
74
|
+
label: c.to_s.upcase
|
|
75
|
+
})
|
|
76
|
+
ret << base
|
|
77
|
+
|
|
78
|
+
elsif c.is_a?(::Hash)
|
|
79
|
+
base.update(c)
|
|
80
|
+
ret << base
|
|
81
|
+
|
|
82
|
+
else
|
|
83
|
+
raise "unsupported column type #{c.class}"
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
ret
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def generate
|
|
91
|
+
return if @cols.empty?
|
|
92
|
+
|
|
93
|
+
prepare
|
|
94
|
+
|
|
95
|
+
case @layout
|
|
96
|
+
when :columns
|
|
97
|
+
columns
|
|
98
|
+
|
|
99
|
+
when :rows
|
|
100
|
+
rows
|
|
101
|
+
|
|
102
|
+
else
|
|
103
|
+
raise "unsupported layout '#{@layout}'"
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Each object is printed on one line, it's parameters aligned into columns.
|
|
108
|
+
def columns
|
|
109
|
+
# Calculate column widths
|
|
110
|
+
@cols.each_with_index do |c, i|
|
|
111
|
+
c[:width] = col_width(i, c)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Print header
|
|
115
|
+
if @header
|
|
116
|
+
line(@cols.map.with_index do |c, i|
|
|
117
|
+
fmt =
|
|
118
|
+
if i == (@cols.count - 1)
|
|
119
|
+
'%s'
|
|
120
|
+
elsif c[:align].to_sym == :right
|
|
121
|
+
"%#{c[:width]}s"
|
|
122
|
+
else
|
|
123
|
+
"%-#{c[:width]}s"
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
format(fmt, c[:label])
|
|
127
|
+
end.join(' '))
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Print data
|
|
131
|
+
@str_objects.each do |o|
|
|
132
|
+
line(@cols.map.with_index do |c, i|
|
|
133
|
+
s = o[i].to_s
|
|
134
|
+
|
|
135
|
+
if @color
|
|
136
|
+
# If there are colors in the string, they affect the string size
|
|
137
|
+
# and thus sprintf formatting. sprintf is working with characters
|
|
138
|
+
# that the terminal will consume and not display (escape sequences).
|
|
139
|
+
# The format string needs to be changed to accomodate for those
|
|
140
|
+
# unprintable characters.
|
|
141
|
+
s_nocolor = Rainbow::StringUtils.uncolor(s)
|
|
142
|
+
|
|
143
|
+
w = if s_nocolor.length == s.length
|
|
144
|
+
c[:width]
|
|
145
|
+
|
|
146
|
+
else
|
|
147
|
+
c[:width] + (s.length - s_nocolor.length)
|
|
148
|
+
end
|
|
149
|
+
else
|
|
150
|
+
w = c[:width]
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
fmt =
|
|
154
|
+
if i == (@cols.count - 1)
|
|
155
|
+
'%s'
|
|
156
|
+
elsif c[:align].to_sym == :right
|
|
157
|
+
"%#{w}s"
|
|
158
|
+
else
|
|
159
|
+
"%-#{w}s"
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
format(fmt, s)
|
|
163
|
+
end.join(' '))
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Each object is printed on multiple lines, one parameter per line.
|
|
168
|
+
def rows
|
|
169
|
+
w = heading_width if @header
|
|
170
|
+
|
|
171
|
+
@str_objects.each do |o|
|
|
172
|
+
@cols.each_index do |i|
|
|
173
|
+
c = @cols[i]
|
|
174
|
+
|
|
175
|
+
unless @header
|
|
176
|
+
line o[i]
|
|
177
|
+
next
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
if o[i].is_a?(::String) && o[i].index("\n")
|
|
181
|
+
lines = o[i].split("\n")
|
|
182
|
+
v = ([lines.first] + lines[1..].map { |l| (' ' * (w + 3)) + l }).join("\n")
|
|
183
|
+
|
|
184
|
+
else
|
|
185
|
+
v = o[i]
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# rubocop:disable Lint/FormatParameterMismatch
|
|
189
|
+
line format("%#{w}s: %s", c[:label], v)
|
|
190
|
+
# rubocop:enable Lint/FormatParameterMismatch
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
line
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def line(str = '')
|
|
198
|
+
if @out
|
|
199
|
+
@out += "#{str}\n"
|
|
200
|
+
|
|
201
|
+
else
|
|
202
|
+
puts str
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def prepare
|
|
207
|
+
@str_objects = []
|
|
208
|
+
|
|
209
|
+
each_object do |o|
|
|
210
|
+
arr = []
|
|
211
|
+
|
|
212
|
+
@cols.each do |c|
|
|
213
|
+
v = o[c[:name]]
|
|
214
|
+
str = (c[:display] ? c[:display].call(v, o) : v)
|
|
215
|
+
str = @empty if !str || (str.is_a?(::String) && str.empty?)
|
|
216
|
+
|
|
217
|
+
arr << str
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
@str_objects << arr
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
if @sort
|
|
224
|
+
col_indexes = @sort.map do |s|
|
|
225
|
+
i = @cols.index { |c| c[:name] == s }
|
|
226
|
+
raise "unknown sort column '#{s}'" unless i
|
|
227
|
+
|
|
228
|
+
i
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
@str_objects.sort! do |a, b|
|
|
232
|
+
a_vals = col_indexes.map { |i| a[i] }
|
|
233
|
+
b_vals = col_indexes.map { |i| b[i] }
|
|
234
|
+
cmp = a_vals <=> b_vals
|
|
235
|
+
next(cmp) if cmp
|
|
236
|
+
|
|
237
|
+
next(-1) if [nil, @empty].detect { |v| a_vals.include?(v) }
|
|
238
|
+
next(1) if [nil, @empty].detect { |v| b_vals.include?(v) }
|
|
239
|
+
|
|
240
|
+
0
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
@str_objects
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def col_width(i, c)
|
|
248
|
+
w = c[:label].to_s.length
|
|
249
|
+
|
|
250
|
+
@str_objects.each do |o|
|
|
251
|
+
len = if @color
|
|
252
|
+
Rainbow::StringUtils.uncolor(o[i].to_s).length
|
|
253
|
+
else
|
|
254
|
+
o[i].to_s.length
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
w = len if len > w
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
w + 1
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
def heading_width
|
|
264
|
+
w = @cols.first[:label].to_s.length
|
|
265
|
+
|
|
266
|
+
@cols.each do |c|
|
|
267
|
+
len = c[:label].to_s.length
|
|
268
|
+
|
|
269
|
+
w = len if len > w
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
w + 1
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
def each_object(&)
|
|
276
|
+
if @objects.is_a?(::Array)
|
|
277
|
+
@objects.each(&)
|
|
278
|
+
|
|
279
|
+
else
|
|
280
|
+
yield(@objects)
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def many?
|
|
285
|
+
@objects.is_a?(::Array) && @objects.size > 1
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require 'confctl/cli/command'
|
|
2
|
+
require 'confctl/cli/swpins/utils'
|
|
3
|
+
|
|
4
|
+
module ConfCtl::Cli
|
|
5
|
+
class Swpins::Base < Command
|
|
6
|
+
include Swpins::Utils
|
|
7
|
+
|
|
8
|
+
def update
|
|
9
|
+
run_command(Swpins::Core, :update)
|
|
10
|
+
run_command(Swpins::Channel, :update)
|
|
11
|
+
run_command(Swpins::Cluster, :update)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def reconfigure
|
|
15
|
+
each_channel('*') do |chan|
|
|
16
|
+
if chan.valid?
|
|
17
|
+
puts "Reconfiguring channel #{chan.name}"
|
|
18
|
+
chan.save
|
|
19
|
+
else
|
|
20
|
+
puts "Channel #{chan.name} needs update"
|
|
21
|
+
chan.specs.each do |name, s|
|
|
22
|
+
puts " update #{name}" unless s.valid?
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
each_cluster_name('*') do |cn|
|
|
28
|
+
if cn.valid?
|
|
29
|
+
puts "Reconfiguring machine #{cn.name}"
|
|
30
|
+
cn.save
|
|
31
|
+
else
|
|
32
|
+
puts "Machine #{cn.name} needs update"
|
|
33
|
+
cn.specs.each do |name, s|
|
|
34
|
+
puts " update #{name}" unless s.valid?
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
require 'confctl/cli/command'
|
|
2
|
+
require 'confctl/cli/swpins/utils'
|
|
3
|
+
|
|
4
|
+
module ConfCtl::Cli
|
|
5
|
+
class Swpins::Channel < Command
|
|
6
|
+
include Swpins::Utils
|
|
7
|
+
|
|
8
|
+
def list
|
|
9
|
+
rows = []
|
|
10
|
+
|
|
11
|
+
each_channel_spec(args[0] || '*', args[1] || '*') do |chan, spec|
|
|
12
|
+
rows << {
|
|
13
|
+
channel: chan.name,
|
|
14
|
+
sw: spec.name,
|
|
15
|
+
type: spec.type,
|
|
16
|
+
pin: spec.status
|
|
17
|
+
}
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
OutputFormatter.print(
|
|
21
|
+
rows,
|
|
22
|
+
%i[channel sw type pin],
|
|
23
|
+
layout: :columns
|
|
24
|
+
)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def set
|
|
28
|
+
require_args!('channel-pattern', 'sw-pattern', 'version...', strict: false)
|
|
29
|
+
channels = []
|
|
30
|
+
change_set = ConfCtl::Swpins::ChangeSet.new
|
|
31
|
+
|
|
32
|
+
each_channel_spec(args[0], args[1]) do |chan, spec|
|
|
33
|
+
change_set.add(chan, spec)
|
|
34
|
+
spec_set_msg(chan, spec) { spec.prefetch_set(args[2..]) }
|
|
35
|
+
channels << chan unless channels.include?(chan)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
channels.each(&:save)
|
|
39
|
+
|
|
40
|
+
return unless opts[:commit]
|
|
41
|
+
|
|
42
|
+
change_set.commit(
|
|
43
|
+
type: opts[:downgrade] ? :downgrade : :upgrade,
|
|
44
|
+
changelog: opts[:changelog]
|
|
45
|
+
)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def update
|
|
49
|
+
require_args!(optional: %w[channel-pattern sw-pattern])
|
|
50
|
+
channels = []
|
|
51
|
+
change_set = ConfCtl::Swpins::ChangeSet.new
|
|
52
|
+
|
|
53
|
+
each_channel_spec(args[0] || '*', args[1] || '*') do |chan, spec|
|
|
54
|
+
if spec.can_update?
|
|
55
|
+
change_set.add(chan, spec)
|
|
56
|
+
spec_update_msg(chan, spec) { spec.prefetch_update }
|
|
57
|
+
channels << chan unless channels.include?(chan)
|
|
58
|
+
else
|
|
59
|
+
puts "#{spec.name} not configured for update"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
channels.each(&:save)
|
|
64
|
+
|
|
65
|
+
return unless opts[:commit]
|
|
66
|
+
|
|
67
|
+
change_set.commit(
|
|
68
|
+
type: opts[:downgrade] ? :downgrade : :upgrade,
|
|
69
|
+
changelog: opts[:changelog]
|
|
70
|
+
)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
require 'confctl/cli/command'
|
|
2
|
+
require 'confctl/cli/swpins/utils'
|
|
3
|
+
|
|
4
|
+
module ConfCtl::Cli
|
|
5
|
+
class Swpins::Cluster < Command
|
|
6
|
+
include Swpins::Utils
|
|
7
|
+
|
|
8
|
+
def list
|
|
9
|
+
rows = []
|
|
10
|
+
|
|
11
|
+
each_cluster_name_spec(args[0] || '*', args[1] || '*') do |cn, spec|
|
|
12
|
+
rows << {
|
|
13
|
+
cluster_name: cn.name,
|
|
14
|
+
sw: spec.name,
|
|
15
|
+
channel: spec.channel,
|
|
16
|
+
type: spec.type,
|
|
17
|
+
pin: spec.status
|
|
18
|
+
}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
OutputFormatter.print(
|
|
22
|
+
rows,
|
|
23
|
+
%i[cluster_name sw channel type pin],
|
|
24
|
+
layout: :columns
|
|
25
|
+
)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def set
|
|
29
|
+
require_args!('cluster-name', 'sw', 'version...', strict: false)
|
|
30
|
+
cluster_names = []
|
|
31
|
+
change_set = ConfCtl::Swpins::ChangeSet.new
|
|
32
|
+
|
|
33
|
+
each_cluster_name_spec(args[0], args[1]) do |cluster_name, spec|
|
|
34
|
+
if spec.from_channel?
|
|
35
|
+
puts "Skipping #{spec.name} as it comes from channel #{spec.channel}"
|
|
36
|
+
else
|
|
37
|
+
change_set.add(cluster_name, spec)
|
|
38
|
+
spec_set_msg(cluster_name, spec) { spec.prefetch_set(args[2..]) }
|
|
39
|
+
cluster_names << cluster_name unless cluster_names.include?(cluster_name)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
cluster_names.each(&:save)
|
|
44
|
+
|
|
45
|
+
return unless opts[:commit]
|
|
46
|
+
|
|
47
|
+
change_set.commit(
|
|
48
|
+
type: opts[:downgrade] ? :downgrade : :upgrade,
|
|
49
|
+
changelog: opts[:changelog]
|
|
50
|
+
)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def update
|
|
54
|
+
require_args!(optional: %w[cluster-name sw])
|
|
55
|
+
cluster_names = []
|
|
56
|
+
change_set = ConfCtl::Swpins::ChangeSet.new
|
|
57
|
+
|
|
58
|
+
each_cluster_name_spec(args[0] || '*', args[1] || '*') do |cluster_name, spec|
|
|
59
|
+
if spec.from_channel?
|
|
60
|
+
puts "Skipping #{spec.name} as it comes from channel #{spec.channel}"
|
|
61
|
+
elsif spec.can_update?
|
|
62
|
+
change_set.add(cluster_name, spec)
|
|
63
|
+
spec_update_msg(cluster_name, spec) { spec.prefetch_update }
|
|
64
|
+
cluster_names << cluster_name unless cluster_names.include?(cluster_name)
|
|
65
|
+
else
|
|
66
|
+
puts "#{spec.name} not configured for update"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
cluster_names.each(&:save)
|
|
71
|
+
|
|
72
|
+
return unless opts[:commit]
|
|
73
|
+
|
|
74
|
+
change_set.commit(
|
|
75
|
+
type: opts[:downgrade] ? :downgrade : :upgrade,
|
|
76
|
+
changelog: opts[:changelog]
|
|
77
|
+
)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
require 'confctl/cli/command'
|
|
2
|
+
require 'confctl/cli/swpins/utils'
|
|
3
|
+
|
|
4
|
+
module ConfCtl::Cli
|
|
5
|
+
class Swpins::Core < Command
|
|
6
|
+
include Swpins::Utils
|
|
7
|
+
|
|
8
|
+
def list
|
|
9
|
+
core = ConfCtl::Swpins::Core.get
|
|
10
|
+
|
|
11
|
+
rows = []
|
|
12
|
+
|
|
13
|
+
core.specs.each do |name, spec|
|
|
14
|
+
next if args[0] && !ConfCtl::Pattern.match(args[0], name)
|
|
15
|
+
|
|
16
|
+
rows << {
|
|
17
|
+
sw: spec.name,
|
|
18
|
+
channel: spec.channel,
|
|
19
|
+
type: spec.type,
|
|
20
|
+
pin: spec.status
|
|
21
|
+
}
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
OutputFormatter.print(
|
|
25
|
+
rows,
|
|
26
|
+
%i[sw channel type pin],
|
|
27
|
+
layout: :columns
|
|
28
|
+
)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def set
|
|
32
|
+
require_args!('sw', 'version...', strict: false)
|
|
33
|
+
|
|
34
|
+
core = ConfCtl::Swpins::Core.get
|
|
35
|
+
change_set = ConfCtl::Swpins::ChangeSet.new
|
|
36
|
+
|
|
37
|
+
core.specs.each_value do |spec|
|
|
38
|
+
if spec.from_channel?
|
|
39
|
+
puts "Skipping #{spec.name} as it comes from channel #{spec.channel}"
|
|
40
|
+
else
|
|
41
|
+
change_set.add(core, spec)
|
|
42
|
+
spec_set_msg(core, spec) { spec.prefetch_set(args[1..]) }
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
core.save
|
|
47
|
+
core.pre_evaluate
|
|
48
|
+
|
|
49
|
+
return unless opts[:commit]
|
|
50
|
+
|
|
51
|
+
change_set.commit(
|
|
52
|
+
type: opts[:downgrade] ? :downgrade : :upgrade,
|
|
53
|
+
changelog: opts[:changelog]
|
|
54
|
+
)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def update
|
|
58
|
+
require_args!(optional: %w[sw])
|
|
59
|
+
core = ConfCtl::Swpins::Core.get
|
|
60
|
+
change_set = ConfCtl::Swpins::ChangeSet.new
|
|
61
|
+
|
|
62
|
+
core.specs.each do |name, spec|
|
|
63
|
+
next if args[0] && !ConfCtl::Pattern.match(args[0], name)
|
|
64
|
+
|
|
65
|
+
if spec.from_channel?
|
|
66
|
+
puts "Skipping #{spec.name} as it comes from channel #{spec.channel}"
|
|
67
|
+
elsif spec.can_update?
|
|
68
|
+
change_set.add(core, spec)
|
|
69
|
+
spec_update_msg(core, spec) { spec.prefetch_update }
|
|
70
|
+
else
|
|
71
|
+
puts "#{spec.name} not configured for update"
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
core.save
|
|
76
|
+
core.pre_evaluate
|
|
77
|
+
|
|
78
|
+
return unless opts[:commit]
|
|
79
|
+
|
|
80
|
+
change_set.commit(
|
|
81
|
+
type: opts[:downgrade] ? :downgrade : :upgrade,
|
|
82
|
+
changelog: opts[:changelog]
|
|
83
|
+
)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module ConfCtl::Cli
|
|
2
|
+
module Swpins::Utils
|
|
3
|
+
def cluster_name_list(pattern)
|
|
4
|
+
ConfCtl::Swpins::ClusterNameList.new(pattern:)
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def each_cluster_name(cn_pattern)
|
|
8
|
+
cluster_name_list(cn_pattern).each do |cn|
|
|
9
|
+
cn.parse
|
|
10
|
+
yield(cn)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def each_cluster_name_spec(cn_pattern, sw_pattern)
|
|
15
|
+
each_cluster_name(cn_pattern) do |cn|
|
|
16
|
+
cn.specs.each do |name, spec|
|
|
17
|
+
yield(cn, spec) if ConfCtl::Pattern.match?(sw_pattern, name)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def channel_list(pattern)
|
|
23
|
+
ConfCtl::Swpins::ChannelList.pattern(pattern)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def each_channel(chan_pattern)
|
|
27
|
+
channel_list(chan_pattern).each do |chan|
|
|
28
|
+
chan.parse
|
|
29
|
+
yield(chan)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def each_channel_spec(chan_pattern, sw_pattern)
|
|
34
|
+
each_channel(chan_pattern) do |chan|
|
|
35
|
+
chan.specs.each do |name, spec|
|
|
36
|
+
yield(chan, spec) if ConfCtl::Pattern.match?(sw_pattern, name)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def spec_set_msg(parent, spec)
|
|
42
|
+
$stdout.write("Configuring #{spec.name} in #{parent.name}")
|
|
43
|
+
$stdout.flush
|
|
44
|
+
yield
|
|
45
|
+
puts " -> #{spec.version}"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def spec_update_msg(parent, spec)
|
|
49
|
+
$stdout.write("Updating #{spec.name} in #{parent.name}")
|
|
50
|
+
$stdout.flush
|
|
51
|
+
yield
|
|
52
|
+
puts " -> #{spec.version}"
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module ConfCtl::Cli
|
|
2
|
+
class TagFilters
|
|
3
|
+
# @param str_tags [Array<String>]
|
|
4
|
+
def initialize(str_tags)
|
|
5
|
+
@must = []
|
|
6
|
+
@cant = []
|
|
7
|
+
parse_all(str_tags)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# @param machine [ConfCtl::Machine]
|
|
11
|
+
def pass?(machine)
|
|
12
|
+
must.all? { |t| machine['tags'].include?(t) } \
|
|
13
|
+
&& cant.all? { |t| !machine['tags'].include?(t) }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
protected
|
|
17
|
+
|
|
18
|
+
attr_reader :must, :cant
|
|
19
|
+
|
|
20
|
+
def parse_all(str_tags)
|
|
21
|
+
str_tags.each do |t|
|
|
22
|
+
if t.start_with?('^')
|
|
23
|
+
cant << t[1..]
|
|
24
|
+
else
|
|
25
|
+
must << t
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|