xolo-admin 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/LICENSE.txt +177 -0
- data/README.md +5 -0
- data/bin/xadm +114 -0
- data/lib/xolo/admin/command_line.rb +432 -0
- data/lib/xolo/admin/configuration.rb +196 -0
- data/lib/xolo/admin/connection.rb +191 -0
- data/lib/xolo/admin/cookie_jar.rb +81 -0
- data/lib/xolo/admin/credentials.rb +212 -0
- data/lib/xolo/admin/highline_terminal.rb +81 -0
- data/lib/xolo/admin/interactive.rb +762 -0
- data/lib/xolo/admin/jamf_pro.rb +75 -0
- data/lib/xolo/admin/options.rb +1139 -0
- data/lib/xolo/admin/processing.rb +1329 -0
- data/lib/xolo/admin/progress_history.rb +117 -0
- data/lib/xolo/admin/title.rb +285 -0
- data/lib/xolo/admin/title_editor.rb +57 -0
- data/lib/xolo/admin/validate.rb +1032 -0
- data/lib/xolo/admin/version.rb +221 -0
- data/lib/xolo/admin.rb +139 -0
- data/lib/xolo-admin.rb +8 -0
- metadata +139 -0
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
# Copyright 2025 Pixar
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the terms set forth in the LICENSE.txt file available at
|
|
4
|
+
# at the root of this project.
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
# frozen_string_literal: true
|
|
8
|
+
|
|
9
|
+
module Xolo
|
|
10
|
+
|
|
11
|
+
module Admin
|
|
12
|
+
|
|
13
|
+
# Module for parsing and validating the xadm options from the commandline
|
|
14
|
+
module CommandLine
|
|
15
|
+
|
|
16
|
+
# Module Methods
|
|
17
|
+
##########################
|
|
18
|
+
##########################
|
|
19
|
+
|
|
20
|
+
# when this module is included
|
|
21
|
+
def self.included(includer)
|
|
22
|
+
Xolo.verbose_include includer, self
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Instance Methods
|
|
26
|
+
##########################
|
|
27
|
+
##########################
|
|
28
|
+
|
|
29
|
+
# Parse ARGV.
|
|
30
|
+
#
|
|
31
|
+
# First we use Optimist to parse the global opts and populate
|
|
32
|
+
# the OpenStruct Xolo::Admin::Options.global_opts
|
|
33
|
+
#
|
|
34
|
+
# Then we look at the next arguments on the command line
|
|
35
|
+
# (things without a - or -- ) and
|
|
36
|
+
# populate the OpenStruct Xolo::Admin::Options.cli_cmd
|
|
37
|
+
#
|
|
38
|
+
# Then we use Optimist again to look at any remaining
|
|
39
|
+
# options, which apply to the command, and populate
|
|
40
|
+
# the OpenStruct Xolo::Admin::Options.cli_cmd_opts
|
|
41
|
+
#
|
|
42
|
+
################################################
|
|
43
|
+
def parse_cli
|
|
44
|
+
# if we ask for help at all, we never do walkthru
|
|
45
|
+
if ARGV.include?(Xolo::Admin::Options::HELP_OPT) || ARGV.include?(Xolo::Admin::Options::HELP_CMD)
|
|
46
|
+
ARGV.delete '-w'
|
|
47
|
+
ARGV.delete '--walkthru'
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# save the global opts hash from optimist into our OpenStruct
|
|
51
|
+
parse_global_cli.each { |k, v| global_opts[k] = v }
|
|
52
|
+
|
|
53
|
+
# Now parse the rest of the command line, getting the
|
|
54
|
+
# command its its args into cli_cmd, and the opts for them
|
|
55
|
+
# into cli_cmd_opts
|
|
56
|
+
parse_command_cli
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Use Optimist to parse the global opts, stopping when it hits a known command
|
|
60
|
+
# This also generates the top level --help output
|
|
61
|
+
#
|
|
62
|
+
# @return [Hash] The global opts from the command line, parsed by optimist
|
|
63
|
+
################################################
|
|
64
|
+
def parse_global_cli
|
|
65
|
+
# set this so its available inside the optimist options block
|
|
66
|
+
executable_file = Xolo::Admin::EXECUTABLE_FILENAME
|
|
67
|
+
usage_line = usage
|
|
68
|
+
|
|
69
|
+
Optimist.options do
|
|
70
|
+
banner 'Name:'
|
|
71
|
+
banner " #{executable_file}, A command-line tool for managing Software Titles and Versions in Xolo."
|
|
72
|
+
|
|
73
|
+
banner "\nUsage:"
|
|
74
|
+
banner " #{usage_line}"
|
|
75
|
+
|
|
76
|
+
banner "\nGlobal Options:"
|
|
77
|
+
|
|
78
|
+
# add a blank line between each of the cli options in the help output
|
|
79
|
+
# NOTE: chrisl added this to the optimist.rb included in this project.
|
|
80
|
+
insert_blanks
|
|
81
|
+
|
|
82
|
+
version Xolo::VERSION
|
|
83
|
+
|
|
84
|
+
# The global opts
|
|
85
|
+
## manually set :version and :help here, or they appear at the bottom of the help
|
|
86
|
+
opt :version, 'Print version and exit'
|
|
87
|
+
opt :help, 'Show this help and exit'
|
|
88
|
+
|
|
89
|
+
# This actually sets the optimist global options and their help blurbs
|
|
90
|
+
#
|
|
91
|
+
Xolo::Admin::Options::GLOBAL_OPTIONS.each do |opt_key, deets|
|
|
92
|
+
type = deets[:type] ? :string : :boolean
|
|
93
|
+
opt opt_key, deets[:desc], short: deets[:cli], type: type
|
|
94
|
+
end
|
|
95
|
+
stop_on Xolo::Admin::Options::COMMANDS.keys
|
|
96
|
+
|
|
97
|
+
# everything below is just more help output
|
|
98
|
+
|
|
99
|
+
banner "\nCommands:"
|
|
100
|
+
Xolo::Admin::Options::COMMANDS.each do |cmd, deets|
|
|
101
|
+
banner format(' %-20s %s', cmd, deets[:desc])
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
banner "\nCommand Targets:"
|
|
105
|
+
banner Xolo::Admin::Options::DFT_CMD_TITLE_ARG_BANNER
|
|
106
|
+
banner Xolo::Admin::Options::DFT_CMD_VERSION_ARG_BANNER
|
|
107
|
+
|
|
108
|
+
banner "\nCommand Options:"
|
|
109
|
+
banner " Use '#{executable_file} help command' or '#{executable_file} command #{Xolo::Admin::Options::HELP_OPT}' to see command-specific help."
|
|
110
|
+
|
|
111
|
+
banner "\nExamples:"
|
|
112
|
+
banner " #{executable_file} add-title google-chrome <options...>"
|
|
113
|
+
banner " Add a new title 'google-chrome' to Xolo,"
|
|
114
|
+
banner ' specifying all options on the command line'
|
|
115
|
+
|
|
116
|
+
banner "\n #{executable_file} --walkthru add-title google-chrome"
|
|
117
|
+
banner " Add a new title 'google-chrome' to Xolo,"
|
|
118
|
+
banner ' providing options interactively'
|
|
119
|
+
|
|
120
|
+
banner "\n #{executable_file} edit-title google-chrome <options...>"
|
|
121
|
+
banner " Edit the existing title 'google-chrome',"
|
|
122
|
+
banner ' specifying all options on the command line'
|
|
123
|
+
|
|
124
|
+
banner "\n #{executable_file} delete-title google-chrome"
|
|
125
|
+
banner " Delete the existing title 'google-chrome' from Xolo,"
|
|
126
|
+
banner ' along with all of its versions.'
|
|
127
|
+
|
|
128
|
+
banner "\n #{executable_file} add-version google-chrome 95.144.21194 <options...>"
|
|
129
|
+
banner " Add a new version number 95.144.21194 to the title 'google-chrome'"
|
|
130
|
+
banner ' specifying all options on the command line.'
|
|
131
|
+
banner ' Options not provided are inherited from the previous version, if available.'
|
|
132
|
+
|
|
133
|
+
banner "\n #{executable_file} edit-version google-chrome 95.144.21194 <options...>"
|
|
134
|
+
banner " Edit version number 95.144.21194 of the title 'google-chrome'"
|
|
135
|
+
banner ' specifying all options on the command line'
|
|
136
|
+
|
|
137
|
+
banner "\n #{executable_file} delete-version google-chrome 95.144.21194"
|
|
138
|
+
banner " Delete version 95.144.21194 from the title 'google-chrome'"
|
|
139
|
+
|
|
140
|
+
banner "\n #{executable_file} search chrome"
|
|
141
|
+
banner " List all titles that contain the string 'chrome'"
|
|
142
|
+
banner ' and its available versions'
|
|
143
|
+
|
|
144
|
+
banner "\n #{executable_file} report google-chrome"
|
|
145
|
+
banner " Report computers with any version of title 'google-chrome' installed"
|
|
146
|
+
|
|
147
|
+
banner "\n #{executable_file} report google-chrome 95.144.21194"
|
|
148
|
+
banner " Report computers with version 95.144.21194 of title 'google-chrome' installed"
|
|
149
|
+
|
|
150
|
+
banner "\n #{executable_file} list-groups"
|
|
151
|
+
banner ' List all computer groups in Jamf Pro'
|
|
152
|
+
end # Optimist.options
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Once we run this, the global opts have been parsed
|
|
156
|
+
# and ARGV should contain our command, any args it takes,
|
|
157
|
+
# and then any options for that command and args.
|
|
158
|
+
#
|
|
159
|
+
# e.g. the command might be 'edit-version'
|
|
160
|
+
# and the args are a title, and a version to edit.
|
|
161
|
+
# Anything after that are the options for doing the editing
|
|
162
|
+
# (unless we are using --walkthru)
|
|
163
|
+
#
|
|
164
|
+
# @return [void]
|
|
165
|
+
################################################
|
|
166
|
+
def parse_command_cli
|
|
167
|
+
# This gets the command (like config or add-title) and any args
|
|
168
|
+
# like a title and/or a version
|
|
169
|
+
# putting them into cli_cmd
|
|
170
|
+
parse_cmd_and_args # unless cli_cmd.command
|
|
171
|
+
|
|
172
|
+
# if we are using --walkthru, all remaining command options are ignored,
|
|
173
|
+
# so just return.
|
|
174
|
+
# The walkthru_cmd_opts will be populated by the interactive
|
|
175
|
+
# process
|
|
176
|
+
return if walkthru?
|
|
177
|
+
|
|
178
|
+
# parse_cmd_opts uses Optimist to get the --options that go
|
|
179
|
+
# with the command and its args.
|
|
180
|
+
# we loop thru them (its a hash) and save them into our
|
|
181
|
+
# cli_cmd_opts OpenStruct
|
|
182
|
+
optimist_hash = parse_cmd_opts
|
|
183
|
+
optimist_hash.each { |k, v| cli_cmd_opts[k] = v }
|
|
184
|
+
|
|
185
|
+
# Now merge in current_opt_values for anything not given on the cli
|
|
186
|
+
# This is how we inherit values, or apply defaults
|
|
187
|
+
current_opt_values.to_h.each do |k, v|
|
|
188
|
+
next if cli_cmd_opts["#{k}_given"]
|
|
189
|
+
|
|
190
|
+
cli_cmd_opts[k] = v unless v.pix_empty?
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# Validate the options given on the commandline
|
|
194
|
+
validate_cli_cmd_opts
|
|
195
|
+
|
|
196
|
+
# now cli_cmd_opts contains all the data for
|
|
197
|
+
# processing whatever we're processing, so do the internal consistency checks
|
|
198
|
+
validate_internal_consistency cli_cmd_opts
|
|
199
|
+
|
|
200
|
+
# If we got here, everything in Xolo::Admin::Options.cli_cmd_opts is good to go
|
|
201
|
+
# and can be sent to the server for processing.
|
|
202
|
+
end # parse_command_cli
|
|
203
|
+
|
|
204
|
+
# Get the xadm command, and its args (title, maybe version, etc)
|
|
205
|
+
# from the Command Line.
|
|
206
|
+
# They get stored in the cli_cmd OpenStruct.
|
|
207
|
+
#
|
|
208
|
+
# We don't use optimist for this, we just examine the first items of
|
|
209
|
+
# ARGV until we hit one starting with a dash.
|
|
210
|
+
#
|
|
211
|
+
##################################################################
|
|
212
|
+
def parse_cmd_and_args
|
|
213
|
+
# next item will be the command we are executing
|
|
214
|
+
cli_cmd.command = ARGV.shift
|
|
215
|
+
|
|
216
|
+
# if there is no command, treat it like `xadm --help`
|
|
217
|
+
return if reparse_global_cli_for_help?
|
|
218
|
+
|
|
219
|
+
# we have a command, validate it
|
|
220
|
+
validate_cli_command
|
|
221
|
+
|
|
222
|
+
# Some commands, like 'config', always do walkthru
|
|
223
|
+
global_opts.walkthru = true if cli_cmd.command == Xolo::Admin::Options::CONFIG_CMD
|
|
224
|
+
|
|
225
|
+
# if the command is 'help'
|
|
226
|
+
# then
|
|
227
|
+
# 'xadm [globalOpts] help' becomes 'xadm --help'
|
|
228
|
+
# and
|
|
229
|
+
# 'xadm [globalOpts] help command' becomes 'xadm [globalOpts] command --help'
|
|
230
|
+
#
|
|
231
|
+
# in those forms, Optimist will deal with displaying the help.
|
|
232
|
+
#
|
|
233
|
+
if cli_cmd.command == Xolo::Admin::Options::HELP_CMD
|
|
234
|
+
|
|
235
|
+
# 'xadm [globalOpts] help' becomes 'xadm --help' (via the reparse method)
|
|
236
|
+
cli_cmd.command = ARGV.shift
|
|
237
|
+
return if reparse_global_cli_for_help?
|
|
238
|
+
|
|
239
|
+
# we have a new command, for which we are getting help. Validate it
|
|
240
|
+
validate_cli_command
|
|
241
|
+
|
|
242
|
+
# 'xadm [globalOpts] help command' becomes 'xadm [globalOpts] command --help'
|
|
243
|
+
ARGV.unshift Xolo::Admin::Options::HELP_OPT
|
|
244
|
+
end
|
|
245
|
+
# if we are here and any part of ARGV is --help, nothing more to do.
|
|
246
|
+
return if ARGV.include?(Xolo::Admin::Options::HELP_OPT)
|
|
247
|
+
|
|
248
|
+
# if we are saving the client code, we don't need to log in
|
|
249
|
+
return if cli_cmd.command == Xolo::Admin::Options::SAVE_CLIENT_CODE_CMD
|
|
250
|
+
|
|
251
|
+
# log in now, cuz we need the server to validate the rest of the
|
|
252
|
+
# command line
|
|
253
|
+
#
|
|
254
|
+
# TODO: Be pickier about which commands actually need the server, and
|
|
255
|
+
# only log in for them.
|
|
256
|
+
#################
|
|
257
|
+
login
|
|
258
|
+
|
|
259
|
+
# What kind of command do we have, since we know it isn't 'help' if we
|
|
260
|
+
# are here.
|
|
261
|
+
if title_command?
|
|
262
|
+
# the next item is the title
|
|
263
|
+
cli_cmd.title = ARGV.shift
|
|
264
|
+
validate_cli_title
|
|
265
|
+
|
|
266
|
+
elsif version_command?
|
|
267
|
+
# the next item is the title and the one after that might be a version
|
|
268
|
+
cli_cmd.title = ARGV.shift
|
|
269
|
+
validate_cli_title
|
|
270
|
+
|
|
271
|
+
cli_cmd.version = ARGV.shift
|
|
272
|
+
validate_cli_version
|
|
273
|
+
|
|
274
|
+
elsif title_or_version_command?
|
|
275
|
+
# the next item is the title and the one after that might be a version
|
|
276
|
+
cli_cmd.title = ARGV.shift
|
|
277
|
+
validate_cli_title
|
|
278
|
+
|
|
279
|
+
cli_cmd.version = ARGV.shift unless ARGV.first.to_s.start_with? Xolo::DASH
|
|
280
|
+
validate_cli_version if cli_cmd.version
|
|
281
|
+
|
|
282
|
+
end # if
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
# Are we showing the full help? If so, re-parse the global opts
|
|
286
|
+
##################################################################
|
|
287
|
+
def reparse_global_cli_for_help?
|
|
288
|
+
cmdstr = cli_cmd.command.to_s
|
|
289
|
+
return false unless cmdstr.empty? || cmdstr.start_with?(Xolo::DASH)
|
|
290
|
+
|
|
291
|
+
ARGV.unshift Xolo::Admin::Options::HELP_OPT
|
|
292
|
+
parse_global_cli
|
|
293
|
+
true
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
# Are we doing mandatory walkthru? If so, re-parse the global opts
|
|
297
|
+
##################################################################
|
|
298
|
+
# def reparse_global_cli_for_mandatory_walkthru?
|
|
299
|
+
# return false if @reparsed_global_cli_for_mandatory_walkthru
|
|
300
|
+
# return false if ARGV.include? Xolo::Admin::Options::HELP_OPT
|
|
301
|
+
# return false unless cli_cmd.command == Xolo::Admin::Options::CONFIG_CMD
|
|
302
|
+
|
|
303
|
+
# ARGV.clear
|
|
304
|
+
# ARGV << '--walkthru'
|
|
305
|
+
# ARGV << '--debug' if global_opts.debug
|
|
306
|
+
# ARGV << '--auto-confirm' if global_opts.auto_confirm
|
|
307
|
+
# ARGV << Xolo::Admin::Options::CONFIG_CMD
|
|
308
|
+
|
|
309
|
+
# parse_cli
|
|
310
|
+
# @reparsed_global_cli_for_mandatory_walkthru = true
|
|
311
|
+
# true
|
|
312
|
+
# end
|
|
313
|
+
|
|
314
|
+
# Parse the options for the command.
|
|
315
|
+
# This returns a hash from Optimist
|
|
316
|
+
# @return [Hash] the optimist hash
|
|
317
|
+
##################################################################
|
|
318
|
+
def parse_cmd_opts
|
|
319
|
+
cmd = cli_cmd.command
|
|
320
|
+
return if cmd == Xolo::Admin::Options::HELP_CMD || cmd.to_s.empty?
|
|
321
|
+
|
|
322
|
+
# set these for use inside the optimist options block
|
|
323
|
+
###
|
|
324
|
+
executable_file = Xolo::Admin::EXECUTABLE_FILENAME
|
|
325
|
+
cmd_desc = Xolo::Admin::Options::COMMANDS.dig cmd, :desc
|
|
326
|
+
cmd_long_desc = Xolo::Admin::Options::COMMANDS.dig cmd, :long_desc
|
|
327
|
+
cmd_long_desc &&= format_multiline_indent(cmd_long_desc, indent: 2)
|
|
328
|
+
cmd_usage = Xolo::Admin::Options::COMMANDS.dig cmd, :usage
|
|
329
|
+
cmd_display = Xolo::Admin::Options::COMMANDS.dig cmd, :display
|
|
330
|
+
cmd_opts = Xolo::Admin::Options::COMMANDS.dig cmd, :opts
|
|
331
|
+
|
|
332
|
+
title_command?
|
|
333
|
+
vers_cmd = version_command?
|
|
334
|
+
title_or_vers_command = title_or_version_command?
|
|
335
|
+
add_command = add_command?
|
|
336
|
+
edit_command?
|
|
337
|
+
arg_banner = Xolo::Admin::Options::COMMANDS.dig(cmd, :arg_banner)
|
|
338
|
+
arg_banner ||= Xolo::Admin::Options::DFT_CMD_TITLE_ARG_BANNER
|
|
339
|
+
|
|
340
|
+
# The optimist parser and help generator
|
|
341
|
+
# for the command options
|
|
342
|
+
Optimist.options do
|
|
343
|
+
# NOTE: extra newlines are added to the front of strings, cuz
|
|
344
|
+
# optimist's 'banner' method chomps the ends.
|
|
345
|
+
banner 'Command:'
|
|
346
|
+
banner " #{cmd}, #{cmd_desc}"
|
|
347
|
+
if cmd_long_desc
|
|
348
|
+
banner "\nDescription:"
|
|
349
|
+
banner " #{cmd_long_desc}"
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
banner "\nUsage:"
|
|
353
|
+
usage = cmd_usage || "#{executable_file} [global options] #{cmd_display} [options]"
|
|
354
|
+
banner " #{usage}"
|
|
355
|
+
|
|
356
|
+
unless arg_banner == :none
|
|
357
|
+
banner "\nArguments:"
|
|
358
|
+
banner arg_banner
|
|
359
|
+
banner Xolo::Admin::Options::DFT_CMD_VERSION_ARG_BANNER if vers_cmd || title_or_vers_command
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
if cmd_opts
|
|
363
|
+
banner "\nOptions:"
|
|
364
|
+
|
|
365
|
+
# add a blank line between each of the cli options
|
|
366
|
+
# NOTE: chrisl added this to the optimist.rb included in this project.
|
|
367
|
+
insert_blanks
|
|
368
|
+
|
|
369
|
+
# create the optimist options for the command
|
|
370
|
+
cmd_opts.each do |opt_key, deets|
|
|
371
|
+
next unless deets[:cli]
|
|
372
|
+
|
|
373
|
+
# Required opts are only required when adding.
|
|
374
|
+
# when editing, they should already exist
|
|
375
|
+
required = deets[:required] && add_command
|
|
376
|
+
|
|
377
|
+
desc = deets[:desc]
|
|
378
|
+
desc = "#{desc}REQUIRED" if required
|
|
379
|
+
|
|
380
|
+
# booleans are CLI flags defaulting to false
|
|
381
|
+
# everything else is a string that we will convert as we validate later
|
|
382
|
+
type = deets[:type] == :boolean ? :boolean : :string
|
|
383
|
+
|
|
384
|
+
# here we actually set the optimist opt.
|
|
385
|
+
opt opt_key, desc, short: deets[:cli], type: type, required: required, multi: deets[:multi]
|
|
386
|
+
end # opts_to_use.each
|
|
387
|
+
end # if cmd_opts
|
|
388
|
+
end # Optimist.options
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
# @return [Boolean] does the command we're running deal with titles?
|
|
392
|
+
#######################################
|
|
393
|
+
def title_command?
|
|
394
|
+
Xolo::Admin::Options::COMMANDS[cli_cmd.command][:target] == :title
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
# @return [Boolean] does the command we're running deal with versions?
|
|
398
|
+
#######################################
|
|
399
|
+
def version_command?
|
|
400
|
+
Xolo::Admin::Options::COMMANDS[cli_cmd.command][:target] == :version
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
# @return [Boolean] does the command we're running deal with either titles or versions?
|
|
404
|
+
#######################################
|
|
405
|
+
def title_or_version_command?
|
|
406
|
+
Xolo::Admin::Options::COMMANDS[cli_cmd.command][:target] == :title_or_version
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
# @return [Boolean] does the command we're running not deal with titles or versions?
|
|
410
|
+
# e.g. 'config' or 'help'
|
|
411
|
+
#######################################
|
|
412
|
+
def no_target_command?
|
|
413
|
+
!Xolo::Admin::Options::COMMANDS[cli_cmd.command][:target]
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
# @return [Boolean] does the command we're running add a title or version to xolo?
|
|
417
|
+
#######################################
|
|
418
|
+
def add_command?
|
|
419
|
+
Xolo::Admin::Options::ADD_COMMANDS.include? cli_cmd.command
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
# @return [Boolean] does the command we're running add a title or version to xolo?
|
|
423
|
+
#######################################
|
|
424
|
+
def edit_command?
|
|
425
|
+
Xolo::Admin::Options::EDIT_COMMANDS.include? cli_cmd.command
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
end # module CommandLine
|
|
429
|
+
|
|
430
|
+
end # module Admin
|
|
431
|
+
|
|
432
|
+
end # module Xolo
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# Copyright 2025 Pixar
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the terms set forth in the LICENSE.txt file available at
|
|
4
|
+
# at the root of this project.
|
|
5
|
+
#
|
|
6
|
+
#
|
|
7
|
+
|
|
8
|
+
# frozen_string_literal: true
|
|
9
|
+
|
|
10
|
+
# main module
|
|
11
|
+
module Xolo
|
|
12
|
+
|
|
13
|
+
module Admin
|
|
14
|
+
|
|
15
|
+
# Personal prefs for users of 'xadm'
|
|
16
|
+
class Configuration < Xolo::Core::BaseClasses::Configuration
|
|
17
|
+
|
|
18
|
+
include Singleton
|
|
19
|
+
|
|
20
|
+
# Save to yaml file in ~/Library/Preferences/com.pixar.xolo.admin.prefs.yaml
|
|
21
|
+
#
|
|
22
|
+
# - hostname of xolo server
|
|
23
|
+
# - always port 443, for now
|
|
24
|
+
#
|
|
25
|
+
# Note - credentials for Xolo Server area stored in login keychain.
|
|
26
|
+
# code for that is in the Xolo::Admin::Credentials module.
|
|
27
|
+
|
|
28
|
+
# Constants
|
|
29
|
+
##############################
|
|
30
|
+
##############################
|
|
31
|
+
CONF_FILE_DIR = '~/Library/Preferences/'
|
|
32
|
+
CONF_FILENAME = 'com.pixar.xolo.admin.config.yaml'
|
|
33
|
+
|
|
34
|
+
CREDENTIALS_NEEDED = '<credentials needed>'
|
|
35
|
+
CREDENTIALS_IN_KEYCHAIN = '<stored in keychain>'
|
|
36
|
+
CREDENTIALS_STORED = '<stored>'
|
|
37
|
+
|
|
38
|
+
# See Xolo::Core::BaseClasses::Configuration for required values
|
|
39
|
+
# when used to access the config file.
|
|
40
|
+
#
|
|
41
|
+
# Also adds values used for CLI and walktru, as with the
|
|
42
|
+
# ATTRIBUTES of Xolo::Core::BaseClasses::Title and Xolo::Core::BaseClasses::Version
|
|
43
|
+
#
|
|
44
|
+
KEYS = {
|
|
45
|
+
|
|
46
|
+
# @!attribute hostname
|
|
47
|
+
# @return [String]
|
|
48
|
+
hostname: {
|
|
49
|
+
required: true,
|
|
50
|
+
label: 'Xolo Server Hostname',
|
|
51
|
+
type: :string,
|
|
52
|
+
validate: true,
|
|
53
|
+
invalid_msg: "Invalid hostname, can't connect, or not a Xolo server.",
|
|
54
|
+
desc: <<~ENDDESC
|
|
55
|
+
The hostname of the Xolo Server to interact with,
|
|
56
|
+
e.g. 'xolo.myschool.edu'
|
|
57
|
+
Enter 'x' to exit if no attempts are successful.
|
|
58
|
+
ENDDESC
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
# @!attribute admin
|
|
62
|
+
# @return [String]
|
|
63
|
+
admin: {
|
|
64
|
+
required: true,
|
|
65
|
+
label: 'Username',
|
|
66
|
+
type: :string,
|
|
67
|
+
validate: false,
|
|
68
|
+
desc: <<~ENDDESC
|
|
69
|
+
The Xolo admin username for connecting to the Xolo server.
|
|
70
|
+
The same that you would use to connect to Jamf Pro.
|
|
71
|
+
ENDDESC
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
# @!attribute pw
|
|
75
|
+
# @return [String]
|
|
76
|
+
pw: {
|
|
77
|
+
required: true,
|
|
78
|
+
label: 'Password',
|
|
79
|
+
type: :string,
|
|
80
|
+
validate: true,
|
|
81
|
+
walkthru_na: :pw_na,
|
|
82
|
+
secure_interactive_input: true,
|
|
83
|
+
invalid_msg: 'Incorrect username or password, or user not allowed.',
|
|
84
|
+
desc: <<~ENDDESC
|
|
85
|
+
The password for connecting to the Xolo server. The same that
|
|
86
|
+
you would use to connect to Jamf Pro.
|
|
87
|
+
It will be stored in your login keychain for use in your terminal or
|
|
88
|
+
other MacOS GUI applications, such as XCode.
|
|
89
|
+
|
|
90
|
+
If you are configuring a non-GUI environment, such as a CI workflow,
|
|
91
|
+
set 'Non-GUI mode' to true. See the 'Non-GUI mode' option below for details
|
|
92
|
+
|
|
93
|
+
Enter 'x' to exit if you are in an unknown password loop.
|
|
94
|
+
ENDDESC
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
# @!attribute pw
|
|
98
|
+
# @return [String]
|
|
99
|
+
no_gui: {
|
|
100
|
+
required: false,
|
|
101
|
+
label: 'Non-GUI mode',
|
|
102
|
+
type: :boolean,
|
|
103
|
+
validate: :validate_boolean,
|
|
104
|
+
walkthru_na: :pw_na,
|
|
105
|
+
secure_interactive_input: true,
|
|
106
|
+
desc: <<~ENDDESC
|
|
107
|
+
If you are configuring xadm for a non-GUI environment, such as a CI workflow,
|
|
108
|
+
set this to true. This will prevent xadm from trying to access the keychain.
|
|
109
|
+
|
|
110
|
+
The password value can then be set to:
|
|
111
|
+
- A command prefixed with '|' that will be executed to get the password from stdout.
|
|
112
|
+
This can have any CLI options and arguments you need to get the password.
|
|
113
|
+
This is useful when using a secret-storage system to manage secrets.
|
|
114
|
+
|
|
115
|
+
- A path to an executable file that returns the password to stdout.
|
|
116
|
+
No arguments are passed, the file is just executed. The file must have only
|
|
117
|
+
rwx permissions for the user running xadm, i.e. mode 0700.
|
|
118
|
+
|
|
119
|
+
- A path to a readable file containing the password, which must have only rw
|
|
120
|
+
permissions for the user running xadm, i.e. mode 0600.
|
|
121
|
+
|
|
122
|
+
- Or the password itself, which will be stored in the xadm config file
|
|
123
|
+
|
|
124
|
+
WARNING: Be careful when storing passwords in files.
|
|
125
|
+
ENDDESC
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
# @!attribute pw
|
|
129
|
+
# @return [String]
|
|
130
|
+
editor: {
|
|
131
|
+
label: 'Preferred editor',
|
|
132
|
+
type: :string,
|
|
133
|
+
validate: true,
|
|
134
|
+
invalid_msg: 'That editor does not exist, or is not executable.',
|
|
135
|
+
desc: <<~ENDDESC
|
|
136
|
+
The editor to use for interactively editing descriptions and other multi-line
|
|
137
|
+
text. Enter the full path to an editor, such as '/usr/bin/vim'. It must
|
|
138
|
+
take the name of a file to edit as an argument.
|
|
139
|
+
|
|
140
|
+
GUI editors are supported, such as /usr/local/bin/bbedit. They will be launched
|
|
141
|
+
as needed when editing multi-line text.
|
|
142
|
+
Note that you may need to provide a command line option to the editor to make
|
|
143
|
+
the cli process wait for the GUI editor to finish. For example, the -w option
|
|
144
|
+
for bbedit.
|
|
145
|
+
|
|
146
|
+
If no editor is set in your config, you will be asked to use one of a few
|
|
147
|
+
basic ones.
|
|
148
|
+
ENDDESC
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
}.freeze
|
|
152
|
+
|
|
153
|
+
# Class methods
|
|
154
|
+
##############################
|
|
155
|
+
##############################
|
|
156
|
+
|
|
157
|
+
# The KEYS that are available as CLI & walkthru options
|
|
158
|
+
# with the 'xadm config' command.
|
|
159
|
+
#
|
|
160
|
+
# @return [Hash{Symbol: Hash}]
|
|
161
|
+
#
|
|
162
|
+
####################
|
|
163
|
+
def self.cli_opts
|
|
164
|
+
KEYS
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# The help text for the 'xadm config' command.
|
|
168
|
+
# Needed because none of the options are available
|
|
169
|
+
# as CLI options.
|
|
170
|
+
#########################
|
|
171
|
+
def self.help_desc_text
|
|
172
|
+
text = +''
|
|
173
|
+
KEYS.each_value do |value|
|
|
174
|
+
text += <<~ENDDESC
|
|
175
|
+
#{value[:label]}:
|
|
176
|
+
#{value[:desc].lines.map { |l| " #{l}" }.join}
|
|
177
|
+
ENDDESC
|
|
178
|
+
end
|
|
179
|
+
text
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Public Instance methods
|
|
183
|
+
##############################
|
|
184
|
+
##############################
|
|
185
|
+
|
|
186
|
+
# @return [Pathname] The file that stores configuration values
|
|
187
|
+
#######################
|
|
188
|
+
def conf_file
|
|
189
|
+
@conf_file ||= Pathname.new("#{CONF_FILE_DIR}#{CONF_FILENAME}").expand_path
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
end # class Configuration
|
|
193
|
+
|
|
194
|
+
end # module Admin
|
|
195
|
+
|
|
196
|
+
end # module Xolo
|