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,221 @@
|
|
|
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
|
+
# A version/patch as used by xadm.
|
|
16
|
+
# This adds cli and walkthru UI, as well as
|
|
17
|
+
# an interface to the Xolo Server for Title
|
|
18
|
+
# objects.
|
|
19
|
+
class Version < Xolo::Core::BaseClasses::Version
|
|
20
|
+
|
|
21
|
+
# This is the server path for dealing with titles
|
|
22
|
+
# POST to add a new one
|
|
23
|
+
# GET to get a list of versions for a title
|
|
24
|
+
# GET .../<version> to get the data for a single version
|
|
25
|
+
# PUT .../<version> to update a version with new data
|
|
26
|
+
# DELETE .../<version> to delete a version from the title
|
|
27
|
+
SERVER_ROUTE = "/titles/#{Xolo::Admin::Title::TARGET_TITLE_PLACEHOLDER}/versions"
|
|
28
|
+
|
|
29
|
+
# Server route for uploading packages
|
|
30
|
+
UPLOAD_PKG_ROUTE = 'pkg'
|
|
31
|
+
|
|
32
|
+
# Modification of the ATTRIBUTES constant for how they are handled
|
|
33
|
+
# in the admin app
|
|
34
|
+
ATTRIBUTES[:min_os][:default] = proc { Xolo::Admin::Options.default_min_os }
|
|
35
|
+
|
|
36
|
+
# Class Methods
|
|
37
|
+
#############################
|
|
38
|
+
#############################
|
|
39
|
+
|
|
40
|
+
# @return [Hash{Symbol: Hash}] The ATTRIBUTES that are available as CLI & walkthru options
|
|
41
|
+
def self.cli_opts
|
|
42
|
+
@cli_opts ||= ATTRIBUTES.select { |_k, v| v[:cli] }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# get the server route to a specific version (or the version list) for a title
|
|
46
|
+
# @param title [String] the title
|
|
47
|
+
# @param version [String] the version to fetch
|
|
48
|
+
# @param cnx [Faraday::Connection] The connection to use, must be logged in already
|
|
49
|
+
# @return [Xolo::Admin::Title]
|
|
50
|
+
####################
|
|
51
|
+
def self.server_route(title, version = nil)
|
|
52
|
+
route = SERVER_ROUTE.sub(Xolo::Admin::Title::TARGET_TITLE_PLACEHOLDER, title)
|
|
53
|
+
route << "/#{version}" if version
|
|
54
|
+
route
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# @return [Array<String>] The currently known versions of a title on the server
|
|
58
|
+
#############################
|
|
59
|
+
def self.all_versions(title, cnx)
|
|
60
|
+
resp = cnx.get server_route(title)
|
|
61
|
+
resp.body
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# @return [Array<Xolo::Admin::Version>] The currently known versions of a title on the server
|
|
65
|
+
#############################
|
|
66
|
+
def self.all_version_objects(title, cnx)
|
|
67
|
+
resp = cnx.get server_route(title)
|
|
68
|
+
resp.body.map { |vd| Xolo::Admin::Version.new vd }
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Does a version of a title exist on the server?
|
|
72
|
+
# @param title [String] the title
|
|
73
|
+
# @param version [String] the version
|
|
74
|
+
# @param cnx [Faraday::Connection] The connection to use, must be logged in already
|
|
75
|
+
# @return [Boolean]
|
|
76
|
+
#############################
|
|
77
|
+
def self.exist?(title, version, cnx)
|
|
78
|
+
all_versions(title, cnx).include? version
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Fetch a version of a title from the server
|
|
82
|
+
# @param title [String] the title
|
|
83
|
+
# @param version [String] the version to fetch
|
|
84
|
+
# @param cnx [Faraday::Connection] The connection to use, must be logged in already
|
|
85
|
+
# @return [Xolo::Admin::Title]
|
|
86
|
+
####################
|
|
87
|
+
def self.fetch(title, version, cnx)
|
|
88
|
+
resp = cnx.get server_route(title, version)
|
|
89
|
+
new resp.body
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Deploy a version to desired computers and groups via MDM
|
|
93
|
+
#
|
|
94
|
+
# @param cnx [Faraday::Connection] The connection to use, must be logged in already
|
|
95
|
+
# @param groups [Array<String, Integer>] The groups to deploy to
|
|
96
|
+
# @param computers [Array<String, Integer>] The computers to deploy to
|
|
97
|
+
#
|
|
98
|
+
# @return [Hash] The response from the server
|
|
99
|
+
####################
|
|
100
|
+
def self.deploy(title, version, cnx, groups: [], computers: [])
|
|
101
|
+
raise ArgumentError, 'Must provide at least one group or computer' if groups.pix_empty? && computers.pix_empty?
|
|
102
|
+
|
|
103
|
+
route = "#{server_route(title, version)}/deploy"
|
|
104
|
+
content = { groups: groups, computers: computers }
|
|
105
|
+
resp = cnx.post(route) { |req| req.body = content }
|
|
106
|
+
resp.body
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Delete a version of a title from the server
|
|
110
|
+
# @param title [String] the title
|
|
111
|
+
# @param version [String] the version to delete
|
|
112
|
+
# @param cnx [Faraday::Connection] The connection to use, must be logged in already
|
|
113
|
+
# @return [Hash] the response body, parsed JSON
|
|
114
|
+
####################
|
|
115
|
+
def self.delete(title, version, cnx)
|
|
116
|
+
resp = cnx.delete server_route(title, version)
|
|
117
|
+
resp.body
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Attributes
|
|
121
|
+
######################
|
|
122
|
+
######################
|
|
123
|
+
|
|
124
|
+
# Constructor
|
|
125
|
+
######################
|
|
126
|
+
######################
|
|
127
|
+
|
|
128
|
+
# Instance Methods
|
|
129
|
+
#############################
|
|
130
|
+
#############################
|
|
131
|
+
|
|
132
|
+
# The server route for this version, after it exists on the server
|
|
133
|
+
|
|
134
|
+
# Add this version to the server
|
|
135
|
+
# @param cnx [Faraday::Connection] The connection to use, must be logged in already
|
|
136
|
+
# @return [Hash] the response from the server
|
|
137
|
+
####################
|
|
138
|
+
def add(cnx)
|
|
139
|
+
resp = cnx.post self.class.server_route(title), to_h
|
|
140
|
+
resp.body
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Update this version to the server
|
|
144
|
+
# @param cnx [Faraday::Connection] The connection to use, must be logged in already
|
|
145
|
+
# @return [Hash] the response from the server
|
|
146
|
+
####################
|
|
147
|
+
def update(cnx)
|
|
148
|
+
resp = cnx.put self.class.server_route(title, version), to_h
|
|
149
|
+
resp.body
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Repair this version
|
|
153
|
+
# @param cnx [Faraday::Connection] The connection to use, must be logged in already
|
|
154
|
+
# @return [Hash] the response body from the server
|
|
155
|
+
####################
|
|
156
|
+
def repair(cnx)
|
|
157
|
+
resp = cnx.post "#{self.class.server_route(title, version)}/repair"
|
|
158
|
+
resp.body
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Delete this title from the server
|
|
162
|
+
# @param cnx [Faraday::Connection] The connection to use, must be logged in already
|
|
163
|
+
# @return [Hash] the response from the server
|
|
164
|
+
####################
|
|
165
|
+
def delete(cnx)
|
|
166
|
+
self.class.delete title, version, cnx
|
|
167
|
+
# already returns resp.body
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Fetch a hash of URLs for the GUI pages for this title
|
|
171
|
+
# @param cnx [Faraday::Connection] The connection to use, must be logged in already
|
|
172
|
+
# @return [Hash{String => String}] page_name => url
|
|
173
|
+
####################
|
|
174
|
+
def gui_urls(cnx)
|
|
175
|
+
resp = cnx.get "#{self.class.server_route(title, version)}/urls"
|
|
176
|
+
resp.body
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# Upload a .pkg (or zipped bundle pkg) for this version
|
|
180
|
+
# At this point, the jamf_pkg_file attribute
|
|
181
|
+
# will containt the local file path.
|
|
182
|
+
#
|
|
183
|
+
# @param upload_cnx [Xolo::Admin::Connection] The server connection
|
|
184
|
+
#
|
|
185
|
+
# @return [Faraday::Response] The server response
|
|
186
|
+
##################################
|
|
187
|
+
def upload_pkg(upload_cnx)
|
|
188
|
+
return unless pkg_to_upload.is_a? Pathname
|
|
189
|
+
|
|
190
|
+
# route = "#{UPLOAD_PKG_ROUTE}/#{title}/#{version}"
|
|
191
|
+
route = "#{self.class.server_route(title, version)}/#{UPLOAD_PKG_ROUTE}"
|
|
192
|
+
|
|
193
|
+
# TODO: Update this to the more modern correct class
|
|
194
|
+
# upfile = Faraday::UploadIO.new(
|
|
195
|
+
# pkg_to_upload.to_s,
|
|
196
|
+
# 'application/octet-stream',
|
|
197
|
+
# pkg_to_upload.basename.to_s
|
|
198
|
+
# )
|
|
199
|
+
|
|
200
|
+
upfile = Faraday::Multipart::FilePart.new(pkg_to_upload.expand_path.to_s, 'application/octet-stream')
|
|
201
|
+
|
|
202
|
+
content = { file: upfile }
|
|
203
|
+
upload_cnx.post(route) { |req| req.body = content }
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# Get the Patch Report data for this version
|
|
207
|
+
# It's the JPAPI report data with each hash having a frozen: key added
|
|
208
|
+
#
|
|
209
|
+
# @param cnx [Faraday::Connection] The connection to use, must be logged in already
|
|
210
|
+
# @return [Array<Hash>] Data for each computer with this version of this title installed
|
|
211
|
+
##################################
|
|
212
|
+
def patch_report_data(cnx)
|
|
213
|
+
resp = cnx.get "#{self.class.server_route(title, version)}/patch_report"
|
|
214
|
+
resp.body
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
end # class Title
|
|
218
|
+
|
|
219
|
+
end # module Admin
|
|
220
|
+
|
|
221
|
+
end # module Xolo
|
data/lib/xolo/admin.rb
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
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
|
+
# Requires
|
|
10
|
+
#########################################
|
|
11
|
+
|
|
12
|
+
# This file is the entry point for loading the Xolo Admin code
|
|
13
|
+
#
|
|
14
|
+
# You can and should require the convenience file 'xolo-admin.rb'
|
|
15
|
+
#
|
|
16
|
+
# require 'xolo-admin'
|
|
17
|
+
#
|
|
18
|
+
|
|
19
|
+
# Standard Libraries
|
|
20
|
+
######
|
|
21
|
+
require 'openssl'
|
|
22
|
+
|
|
23
|
+
# Monkeypatch OpenSSL::SSL::SSLContext to ignore unexpected EOF errors
|
|
24
|
+
# happens with openssl v3 ??
|
|
25
|
+
# see https://stackoverflow.com/questions/76183622/since-a-ruby-container-upgrade-we-expirience-a-lot-of-opensslsslsslerror
|
|
26
|
+
if OpenSSL::SSL.const_defined?(:OP_IGNORE_UNEXPECTED_EOF)
|
|
27
|
+
OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options] |= OpenSSL::SSL::OP_IGNORE_UNEXPECTED_EOF
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
require 'openssl'
|
|
31
|
+
require 'faraday'
|
|
32
|
+
require 'faraday/multipart'
|
|
33
|
+
require 'highline'
|
|
34
|
+
|
|
35
|
+
# Monkeypatch OpenSSL::SSL::SSLContext to ignore unexpected EOF errors
|
|
36
|
+
# happens with openssl v3 ??
|
|
37
|
+
# see https://stackoverflow.com/questions/76183622/since-a-ruby-container-upgrade-we-expirience-a-lot-of-opensslsslsslerror
|
|
38
|
+
if OpenSSL::SSL.const_defined?(:OP_IGNORE_UNEXPECTED_EOF)
|
|
39
|
+
OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options] |= OpenSSL::SSL::OP_IGNORE_UNEXPECTED_EOF
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Yes we're using a OpenStruct for our @opts, even though it's very slow.
|
|
43
|
+
# It isn't so slow that it's a problem for processing a CLI tool.
|
|
44
|
+
# The benefit is being able to use either Hash-style references
|
|
45
|
+
# e.g. opts[key] or method-style when you know the key e.g. opts.title
|
|
46
|
+
require 'ostruct'
|
|
47
|
+
require 'open3'
|
|
48
|
+
require 'singleton'
|
|
49
|
+
require 'yaml'
|
|
50
|
+
require 'shellwords'
|
|
51
|
+
require 'tempfile'
|
|
52
|
+
require 'readline'
|
|
53
|
+
require 'io/console'
|
|
54
|
+
|
|
55
|
+
# Use optimist for CLI option processing
|
|
56
|
+
# https://rubygems.org/gems/optimist
|
|
57
|
+
#
|
|
58
|
+
# This version modified to allow 'insert_blanks' which
|
|
59
|
+
# puts blank lines between each option in the help output.
|
|
60
|
+
# See comments in the required file for details.
|
|
61
|
+
#
|
|
62
|
+
require 'optimist_with_insert_blanks'
|
|
63
|
+
|
|
64
|
+
# Xolo Admin code - order matters here
|
|
65
|
+
# more loaded below
|
|
66
|
+
require 'xolo/core'
|
|
67
|
+
require 'xolo/admin/configuration'
|
|
68
|
+
|
|
69
|
+
module Xolo
|
|
70
|
+
|
|
71
|
+
module Admin
|
|
72
|
+
|
|
73
|
+
# Constants
|
|
74
|
+
##########################
|
|
75
|
+
##########################
|
|
76
|
+
|
|
77
|
+
EXECUTABLE_FILENAME = 'xadm'
|
|
78
|
+
|
|
79
|
+
# if a streaming line contains this text, we bail out instead of
|
|
80
|
+
# continuing any processing
|
|
81
|
+
STREAMING_OUTPUT_ERROR = 'ERROR'
|
|
82
|
+
|
|
83
|
+
# Module Methods
|
|
84
|
+
##########################
|
|
85
|
+
##########################
|
|
86
|
+
|
|
87
|
+
# when this module is included
|
|
88
|
+
def self.included(includer)
|
|
89
|
+
Xolo.verbose_include includer, self
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# @return [Xolo::Admin::Configuration] our config, available via the module
|
|
93
|
+
########################
|
|
94
|
+
def self.config
|
|
95
|
+
Xolo::Admin::Configuration.instance
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Instance Methods
|
|
99
|
+
##########################
|
|
100
|
+
##########################
|
|
101
|
+
|
|
102
|
+
# @return [String] the usage
|
|
103
|
+
########################
|
|
104
|
+
def usage
|
|
105
|
+
@usage ||= "#{EXECUTABLE_FILENAME} [global-options] command [target] [command-options]"
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# @return [Xolo::Admin::Configuration] our config available via the admin app instance
|
|
109
|
+
########################
|
|
110
|
+
def config
|
|
111
|
+
Xolo::Admin::Configuration.instance
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# the rest of the Xolo Admin code - order matters here
|
|
119
|
+
require 'xolo/admin/credentials'
|
|
120
|
+
|
|
121
|
+
require 'xolo/admin/title'
|
|
122
|
+
require 'xolo/admin/version'
|
|
123
|
+
|
|
124
|
+
require 'xolo/admin/options'
|
|
125
|
+
require 'xolo/admin/interactive'
|
|
126
|
+
require 'xolo/admin/command_line'
|
|
127
|
+
require 'xolo/admin/processing'
|
|
128
|
+
require 'xolo/admin/progress_history'
|
|
129
|
+
require 'xolo/admin/validate'
|
|
130
|
+
|
|
131
|
+
require 'xolo/admin/connection'
|
|
132
|
+
require 'xolo/admin/cookie_jar'
|
|
133
|
+
require 'xolo/admin/jamf_pro'
|
|
134
|
+
require 'xolo/admin/title_editor'
|
|
135
|
+
|
|
136
|
+
# A small monkeypatch that allows Readline completion
|
|
137
|
+
# of Highline.ask to optionally use a prompt and be
|
|
138
|
+
# case insensitive
|
|
139
|
+
require 'xolo/admin/highline_terminal'
|
data/lib/xolo-admin.rb
ADDED
metadata
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: xolo-admin
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Chris Lasell
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2025-09-28 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: faraday
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '2.8'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '2.8'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: faraday-multipart
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '1.0'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '1.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: pixar-ruby-extensions
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '1.11'
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '1.11'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: highline
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '2.1'
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '2.1'
|
|
69
|
+
description: |
|
|
70
|
+
== Xolo
|
|
71
|
+
Xolo (sorta pronounced 'show-low') is an HTTPS server and set of command-line tools for macOS that provide automatable access to the software deployment and patch management aspects of {Jamf Pro}[https://www.jamf.com/products/jamf-pro/] and the {Jamf Title Editor}[https://learn.jamf.com/en-US/bundle/title-editor/page/About_Title_Editor.html]. It enhances Jamf Pro's abilities in many ways:
|
|
72
|
+
|
|
73
|
+
- Management of titles and versions/patches is scriptable and automatable, allowing developers and admins to integrate with CI/CD workflows.
|
|
74
|
+
- Simplifies and standardizes the complex, multistep manual process of managing titles and patches using the Title Editor and Patch Management web interfaces.
|
|
75
|
+
- Client installs can be performed by remotely via ssh and/or MDM
|
|
76
|
+
- Automated pre-release piloting of new versions/patches
|
|
77
|
+
- Titles can be expired (auto-uninstalled) after a period of disuse, reclaiming unused licenses.
|
|
78
|
+
- And more!
|
|
79
|
+
|
|
80
|
+
"Xolo" is the short name for the Mexican hairless dog breed {'xoloitzcuintle'}[https://en.wikipedia.org/wiki/Xoloitzcuintle] (show-low-itz-kwint-leh), as personified by Dante in the 2017 Pixar film _Coco_.
|
|
81
|
+
|
|
82
|
+
The xolo-admin gem packages the code needed to run 'xadm', the command-line tool for system administrators to deploy and maintain software titles using Xolo.
|
|
83
|
+
email: xolo@pixar.com
|
|
84
|
+
executables:
|
|
85
|
+
- xadm
|
|
86
|
+
extensions: []
|
|
87
|
+
extra_rdoc_files:
|
|
88
|
+
- README.md
|
|
89
|
+
- LICENSE.txt
|
|
90
|
+
files:
|
|
91
|
+
- LICENSE.txt
|
|
92
|
+
- README.md
|
|
93
|
+
- bin/xadm
|
|
94
|
+
- lib/xolo-admin.rb
|
|
95
|
+
- lib/xolo/admin.rb
|
|
96
|
+
- lib/xolo/admin/command_line.rb
|
|
97
|
+
- lib/xolo/admin/configuration.rb
|
|
98
|
+
- lib/xolo/admin/connection.rb
|
|
99
|
+
- lib/xolo/admin/cookie_jar.rb
|
|
100
|
+
- lib/xolo/admin/credentials.rb
|
|
101
|
+
- lib/xolo/admin/highline_terminal.rb
|
|
102
|
+
- lib/xolo/admin/interactive.rb
|
|
103
|
+
- lib/xolo/admin/jamf_pro.rb
|
|
104
|
+
- lib/xolo/admin/options.rb
|
|
105
|
+
- lib/xolo/admin/processing.rb
|
|
106
|
+
- lib/xolo/admin/progress_history.rb
|
|
107
|
+
- lib/xolo/admin/title.rb
|
|
108
|
+
- lib/xolo/admin/title_editor.rb
|
|
109
|
+
- lib/xolo/admin/validate.rb
|
|
110
|
+
- lib/xolo/admin/version.rb
|
|
111
|
+
homepage: https://pixaranimationstudios.github.io/xolo-home/
|
|
112
|
+
licenses:
|
|
113
|
+
- LicenseRef-LICENSE.txt
|
|
114
|
+
metadata: {}
|
|
115
|
+
post_install_message:
|
|
116
|
+
rdoc_options:
|
|
117
|
+
- "--title"
|
|
118
|
+
- Xolo-Admin
|
|
119
|
+
- "--line-numbers"
|
|
120
|
+
- "--main"
|
|
121
|
+
- README.md
|
|
122
|
+
require_paths:
|
|
123
|
+
- lib
|
|
124
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
125
|
+
requirements:
|
|
126
|
+
- - ">="
|
|
127
|
+
- !ruby/object:Gem::Version
|
|
128
|
+
version: 2.6.3
|
|
129
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
130
|
+
requirements:
|
|
131
|
+
- - ">="
|
|
132
|
+
- !ruby/object:Gem::Version
|
|
133
|
+
version: '0'
|
|
134
|
+
requirements: []
|
|
135
|
+
rubygems_version: 3.3.11
|
|
136
|
+
signing_key:
|
|
137
|
+
specification_version: 4
|
|
138
|
+
summary: Automation and Standardization for Jamf Pro Patch Management
|
|
139
|
+
test_files: []
|