Class: D3::Client
- Inherits:
-
JSS::Client
- Object
- JSS::Client
- D3::Client
- Defined in:
- lib/d3/client.rb,
lib/d3/client/cli.rb,
lib/d3/client/auth.rb,
lib/d3/client/help.rb,
lib/d3/client/lists.rb,
lib/d3/client/receipt.rb,
lib/d3/client/environment.rb,
lib/d3/client/class_methods.rb,
lib/d3/client/class_variables.rb
Overview
Client
Defined Under Namespace
Modules: Help Classes: Receipt
Constant Summary collapse
- DFT_NOTIFICATION_IMAGE_PATH =
Default notification_image_path Unless otherwise specified in /etc/d3.conf, this is the default directory that can be populated with image(s) to display randomly alongside user notifications.
D3::SUPPORT_DIR + "notification_images"
- ACTIONS =
NOTE: In Ruby 2.0 and up, Hashes are ordered in the order their elements are defined or added to the hash. So, the order here will affect the help output.
{ install: { :aka => :i, :help => "install the currently live version of the given basename(s)", :needs_admin => true, :arg => :"basename or edition", :needs_connection => true }, uninstall: { :aka => :u, :help => "uninstall the given basename(s)", :arg => :basename, :needs_connection => true }, dequeue: { :aka => :dq, :help => "remove a pending puppytime (logout) pkg. Use 'all' to clear the queue", :arg => :basename }, sync: { :aka => :s, :help => "update installed pkgs, install new auto-installed ones", :needs_connection => true }, freeze: { :aka => :f, :help => "stop auto-updates of this basename during sync", :needs_connection => false, :arg => :basename }, thaw: { :aka => :t, :help => "resume auto-updates of this basename during sync", :needs_connection => false, :arg => :basename }, forget: { :aka => :fg, :help => "Remove receipt but don't try uninstalling.", :needs_connection => false, :arg => :basename }, list_available: { :aka => :la, :help => "list all available live installers on the server", :needs_connection => true }, list_installed: { :aka => :li, :help => "list all installed d3 pkgs on this machine", :needs_root => false }, list_manual: { :aka => :lm, :help => "list all d3 pkgs on this machine not auto-installed", :needs_root => false }, list_pilots: { :aka => :lp, :help => "list pkgs currently in pilot on this machine", :needs_root => false }, list_frozen: { :aka => :lf, :help => "list pkgs currently frozen on this machine", :needs_root => false }, list_puppies: { :aka => :lq, :help => "list any queued pkgs awaiting puppytime at logout", :needs_root => false }, list_queue: { :aka => :lq, :help => "list any queued pkgs awaiting puppytime at logout", :needs_root => false }, list_details: { :aka => :ld, :help => "show detailed info about packages in d3", :arg => :"basename or edition", :needs_connection => true }, list_files: { :aka => :ls, :help => "list the files installed by the given editions", :arg => :"basename or edition" , :needs_connection => true }, query_file: { :aka => :qf, :help => "list any pkgs that install the given path(s)", :arg => :path, :needs_connection => true }, help: { :aka => :h, :help => "show this help text", :needs_root => false }, version: { :aka => :v, :help => "show the current versions of d3, and its libraries", :needs_root => false } }
- OPTIONS =
end COMMANDS
{ help: { :cli => ['--help','-H', "-h", GetoptLong::NO_ARGUMENT ], :help => "show this help text" }, version: { :cli => ['--version', '-V', GetoptLong::NO_ARGUMENT ], :help => "show the version of d3" }, quiet: { :cli => ['--quiet','-q', GetoptLong::NO_ARGUMENT ], :help => "spew less to stdout. Use up to 3 times to suppress more output." }, verbose: { :cli => ['--verbose','-v', GetoptLong::NO_ARGUMENT ], :help => "give more detail to stdout" }, puppies: { :cli => ['--puppies', '-p', GetoptLong::NO_ARGUMENT ], :help => "do puppy installs immediately, instead of queuing" }, force: { :cli => ['--force', '-f', GetoptLong::NO_ARGUMENT ], :help => "force d3 to perform unnatural acts" }, freeze: { :cli => ['--freeze', '-F', GetoptLong::NO_ARGUMENT ], :help => "with 'install', freeze receipt immediately" }, admin: { :cli => ['--admin', '-a', GetoptLong::REQUIRED_ARGUMENT ], :arg => 'admin', :help => "who is doing something with d3?" }, no_logout_notice: { :cli => ['--no-puppy-notification', '-N', GetoptLong::NO_ARGUMENT ], :help => "don't ask the user to log out for puppies" }, expiration: { :cli => ['--expiration', '-e', GetoptLong::REQUIRED_ARGUMENT ], :arg => "days", :help => "set a custom expiration period to the installed pkgs." }, debug: { :cli => ['--debug', '-d', GetoptLong::NO_ARGUMENT ], :help => "be as verbose as possible to both std and the log." } }
- ENV_STATES =
Environment Vars to set during certain processes
{ # set to 1 during a sync sync: 'D3_SYNCING', # set to 1 if --force was used force: "D3_FORCE", # set to the admin name running d3 admin: "D3_ADMIN", # set to 1 if client was set to debug mode. debug: "D3_DEBUG", # set to 1 if an install is an auto-install auto_install: "D3_AUTO_INSTALLING", # set to 1 if an install is an auto-update auto_update: "D3_AUTO_UPDATING", # set to the edition of the rcpt being UNinstalled uninstalling_before_install: "D3_UNINSTALLING_BEFORE_INSTALL", # set to the edition of the pkg being installed pre_install: "D3_RUNNING_PRE_INSTALL", # set to the edition of the pkg being installed installing: "D3_INSTALLING", # set to the status of the pkg being installed pkg_status: "D3_PKG_STATUS", # set to the edition of the pkg being installed post_install: "D3_RUNNING_POST_INSTALL", # set to the edition of the pkg being expired expiring: "D3_EXPIRING_PKG", # set to a space-separated list if editions expired, if any # when the expiration policy is runing finished_expirations: "D3_FINISHED_EXPIRATIONS", # set to the edition of the pkg being uninstalled pre_remove: "D3_RUNNING_PRE_REMOVE", # set to the edition of the pkg being uninstalled removing: "D3_UNINSTALLING", # set to the edition of the pkg being uninstalled post_remove: "D3_RUNNING_POST_REMOVE", # set to a space-separated list if editions of items in the puppy-queue # when the puppytime notification policy is running puppytime_notification: "D3_NOTIFYING_PUPPIES", # set to 1 during logout-installation of pkgs requiring reboot puppytime: "D3_RUNNING_PUPPYTIME", # set to 1 during the puppy-reboot-policy # (generally this means a logout is happening and a reboot will happen) puppytime_reboot: "D3_REBOOTING_PUPPIES" }
- @@computer_groups =
Class Variables #################
nil
- @@available_pkg_ids =
nil
- @@editions_expired =
The editions that were expired during an expiration run will be reset to [] after the expiration process is finished including running any expiration policy.
[]
- @@puppy_notification_ok_with_admin =
true
- @@cloud_dist_url =
:unknown
Class Method Summary collapse
-
.available_pkg_ids(refresh = false) ⇒ Array<Integer>
An array of package ids that are available for installing or piloting (i.e. not excluded, right OS, right cpu) for this machine.
-
.clean_doghouse ⇒ void
remove any invalid puppies from the queue invalid = id is no longer in d3, or status is missing.
-
.clean_missing_receipts ⇒ Object
remove any receipts for packages that are missing from the server.
-
.cloud_dist_point_to_use(refresh = false, pkg: nil) ⇒ String?
The cloud dist point to use for installs Returns a URL if: - current dist point isn’t reachable for downloads - D3::CONFIG.client_try_cloud_distpoint is true - a Cloud Dist Point is defined in the JSS.
-
.cloud_distribution_point_url ⇒ String?
Is a Cloud Distribution Point available for pkg downloads? If so, return the url for downloading pkg files (the filename will be appended during install).
-
.computer_groups(refresh = false) ⇒ Array<String>
An array of JSS::ComputerGroup names to which this computer belongs.
-
.connect ⇒ Object
Connect to the JSS and the DB with read-only connections The connection details must be stored in the D3 and JSS CONFIG data.
-
.connect_for_reports ⇒ Hash<String>
Reconnect to both the API and DB with a much larger timeout, and using an alternate DB server if one is defined.
-
.dequeue_puppies(puppies) ⇒ void
Remove one or more puppies from the puppy queue.
-
.disconnect ⇒ Object
Disconnect from the JSS and DB.
-
.do_auto_installs(options) ⇒ void
Install any new live pkgs scoped for autoinstall on this machine.
-
.do_expirations(verbose = false, force = D3.forced?) ⇒ void
Expire any pkgs that are due for expiration, and if any are expired, run the expiration policy.
-
.do_puppy_queue_installs_from_sync(options) ⇒ Object
Do any pending puppy installs right now, because we’re syncing and –puppies option was given.
-
.foreground_executable_path ⇒ Pathname?
get the executable path of the current foreground GUI app.
-
.forget_receipts(basenames) ⇒ void
forget one or more receipts, and their matching apple pkg receipts.
-
.freeze_receipts(basenames) ⇒ void
Freeze one or more receipts.
-
.get_admin(pkg_to_install, options) ⇒ String
Return a valid, possibly-default, admin name for installing a package.
-
.get_ro_pass(pw) ⇒ String?
Get a stored read-only password from a file or an executable.
-
.install(pkgs, options) ⇒ void
Install one or more packages from the command-line by basename, or edition (or name, filename, id).
-
.list_available(force = false) ⇒ void
list currently available packages to stdout via ‘less’.
-
.list_details(pkgs) ⇒ void
Display the details about one or more pkgs and/or receipts on the local machine.
-
.list_files(pkgs) ⇒ Object
list the files installed by one or more installers.
-
.list_frozen ⇒ Object
list all frozen pkgs.
-
.list_installed(what_to_list = :all) ⇒ void
list installed d3 items.
-
.list_manual ⇒ Object
list all manually installed pkgs.
-
.list_pending_puppies ⇒ Object
list_pending_puppies.
-
.list_pilots ⇒ Object
list all installed pilots.
-
.puppy_in_queue(basename) ⇒ Integer?
Given a basename, is any edition of it in the puppy queue? If so, return the id of the queued pkg, else return nil.
-
.puppy_notification_ok_with_admin=(bool) ⇒ void
Set the –no-puppy-notification option as given by the admin.
-
.puppy_notification_ok_with_admin? ⇒ Boolean
Was the –no-puppy-notification option given by the admin?.
-
.query_files(paths) ⇒ Object
find out which editions install one or more given files.
-
.set_env(var, value = 1) ⇒ void
Set an ENV variable to the ‘set’ state, usually ‘1’.
-
.sync(options = OpenStruct.new) ⇒ void
Sync this machine.
-
.thaw_receipts(basenames) ⇒ void
Thaw one or more receipts.
-
.uninstall(rcpts, options) ⇒ void
uninstall one or more packages from the commandline.
-
.unset_all_env ⇒ void
Unset all ENV vars.
-
.unset_env(var) ⇒ void
Unset an ENV variable.
-
.update_installed_pkgs(options) ⇒ void
Update any currently installed basenames to the currently live one skipping any basenames currently frozen.
-
.update_rcpts ⇒ void
Update any receipt data that might be changed in the matching package on the server, including: - status - pre- or post-remove scripts - removability - prohibiting processes - expiration details.
-
.validate_pkg_in_cloud(url, pkg) ⇒ Boolean
given a cloud url and a D3::Package is the pkg available at that url?.
Class Method Details
.available_pkg_ids(refresh = false) ⇒ Array<Integer>
An array of package ids that are available for installing or piloting (i.e. not excluded, right OS, right cpu) for this machine.
716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 |
# File 'lib/d3/client/class_methods.rb', line 716 def self.available_pkg_ids(refresh = false) @@available_pkg_ids = nil if refresh return @@available_pkg_ids if @@available_pkg_ids computer_groups(:refresh) if refresh my_cpu = `/usr/bin/uname -p` my_os = `/usr/bin/sw_vers -productVersion`.chomp @@available_pkg_ids = [] D3::Package.package_data.values.each do |pkg| next unless JSS.os_ok? pkg[:oses], my_os next unless JSS.processor_ok? pkg[:required_processor], my_cpu @@available_pkg_ids << pkg[:id] if (pkg[:excluded_groups] & computer_groups).empty? end # do pkg @@available_pkg_ids end |
.clean_doghouse ⇒ void
This method returns an undefined value.
remove any invalid puppies from the queue invalid = id is no longer in d3, or status is missing
360 361 362 363 364 365 366 367 368 369 370 371 372 373 |
# File 'lib/d3/client/class_methods.rb', line 360 def self.clean_doghouse D3.log 'Checking for invalid puppies in the queue', :warn D3::PUPPY_Q.pending_puppies.each do |basename, pup| unless D3::Package.all_ids.include? pup.id D3.log "Removing #{pup.edition} from puppy queue: no longer in d3", :info D3::PUPPY_Q - pup next end if D3::Package.missing_data.keys.include? pup.id D3.log "Removing #{pup.edition} from puppy queue: status is 'missing'", :info D3::PUPPY_Q - pup end end end |
.clean_missing_receipts ⇒ Object
remove any receipts for packages that are missing from the server
449 450 451 452 453 454 455 456 |
# File 'lib/d3/client/class_methods.rb', line 449 def self.clean_missing_receipts D3.log 'Checking for receipts no longer in d3', :warn D3::Client::Receipt.all.values.select { |r| r.status == :missing }.each do |mrcpt| D3.log "Removing receipt for missing edition #{mrcpt.edition}", :info D3::Client::Receipt.remove_receipt mrcpt.basename D3.log "Removed receipt for missing edition #{mrcpt.edition}", :info end end |
.cloud_dist_point_to_use(refresh = false, pkg: nil) ⇒ String?
The cloud dist point to use for installs Returns a URL if:
- current dist point isn't reachable for downloads
- D3::CONFIG.client_try_cloud_distpoint is true
- a Cloud Dist Point is defined in the JSS
otherwise nil
758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 |
# File 'lib/d3/client/class_methods.rb', line 758 def self.cloud_dist_point_to_use(refresh = false, pkg: nil) raise 'You must provide a pkg' unless pkg.is_a? D3::Package @@cloud_dist_url == :unknown if refresh mdp = JSS::DistributionPoint.my_distribution_point # Should we try a cloud distribution point if the primary is unavailable ? unless D3::CONFIG.client_try_cloud_distpoint D3.log "Config is not to try cloud, using only Distribution Point '#{mdp.name}'", :info return @@cloud_dist_url = nil end # Can we reach the primary distribution point? Return nil if true. if mdp.reachable_for_download?(get_ro_pass(:http)) || mdp.reachable_for_download?(get_ro_pass(:dist)) D3.log "Distribution Point '#{mdp.name}' is reachable, no need for cloud", :info return @@cloud_dist_url = nil end # Get the cloud distribution point defined in the JSS cloud_url = cloud_distribution_point_url unless cloud_url D3.log 'No cloud distribution URL found.', :info return @@cloud_dist_url = nil end # Make sure the package is available on the cloud distribution point pkg_available = validate_pkg_in_cloud(cloud_url, pkg) if cloud_url unless pkg_available D3.log "#{pkg.edition} is not available in the cloud", :info return @@cloud_dist_url = nil end @@cloud_dist_url = cloud_url end |
.cloud_distribution_point_url ⇒ String?
Is a Cloud Distribution Point available for pkg downloads? If so, return the url for downloading pkg files (the filename will be appended during install)
819 820 821 822 823 824 825 826 |
# File 'lib/d3/client/class_methods.rb', line 819 def self.cloud_distribution_point_url result = JSS::DB_CNX.db.query 'SELECT download_url, cdn_url FROM cloud_distribution_point' urls = result.fetch result.free return nil if urls.nil? return nil if urls[0].empty? || urls[1].empty? urls[0].empty? ? urls[1] : urls[0] end |
.computer_groups(refresh = false) ⇒ Array<String>
An array of JSS::ComputerGroup names to which this computer belongs
741 742 743 744 745 |
# File 'lib/d3/client/class_methods.rb', line 741 def self.computer_groups(refresh = false) @@computer_groups = nil if refresh return @@computer_groups if @@computer_groups @@computer_groups = JSS::Computer.fetch(udid: JSS::Client.udid).computer_groups end |
.connect ⇒ Object
Connect to the JSS and the DB with read-only connections The connection details must be stored in the D3 and JSS CONFIG data.
38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/d3/client/auth.rb', line 38 def self.connect jss_ro_user = D3::CONFIG.client_jss_ro_user jss_ro_user ||= JSS::CONFIG.api_username db_ro_user = D3::CONFIG.client_db_ro_user db_ro_user ||= JSS::CONFIG.db_username JSS::DB_CNX.connect :server => JSS::CONFIG.db_server_name, :user => db_ro_user, :pw => D3::Client.get_ro_pass(:db) JSS::API.connect :server => JSS::CONFIG.api_server_name, :user => jss_ro_user, :pw => D3::Client.get_ro_pass(:jss) D3::Database.check_schema_version end |
.connect_for_reports ⇒ Hash<String>
Reconnect to both the API and DB with a much larger timeout, and using an alternate DB server if one is defined.
307 308 309 310 311 312 313 314 315 |
# File 'lib/d3/client/lists.rb', line 307 def self.connect_for_reports jss_ro_user = D3::CONFIG.client_jss_ro_user jss_ro_user ||= JSS::CONFIG.api_username db_ro_user = D3::CONFIG.client_db_ro_user db_ro_user ||= JSS::CONFIG.db_username D3.connect_for_reports jss_ro_user, get_ro_pass(:jss), db_ro_user, get_ro_pass(:db) end |
.dequeue_puppies(puppies) ⇒ void
This method returns an undefined value.
Remove one or more puppies from the puppy queue
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'lib/d3/client/class_methods.rb', line 196 def self.dequeue_puppies(puppies) puppies = [puppies] if puppies.is_a? String puppies = D3::PUPPY_Q.pups if puppies.include? 'all' puppies.each do |pup| unless the_puppy = D3::PUPPY_Q.q[pup] D3.log "No pkg for basename '#{pup}' in the puppy queue.", :warn next end # unless begin D3.log "Removing '#{the_puppy.edition}' from the puppy queue.", :warn D3::PUPPY_Q - the_puppy rescue D3.log "Couldn't remove #{the_puppy.edition} from the puppy queue: #{$ERROR_INFO}", :error end # begin end end |
.disconnect ⇒ Object
Disconnect from the JSS and DB
52 53 54 55 |
# File 'lib/d3/client/auth.rb', line 52 def self.disconnect JSS::API.disconnect if JSS::API.connected? JSS::DB_CNX.disconnect if JSS::DB_CNX.connected? end |
.do_auto_installs(options) ⇒ void
This method returns an undefined value.
Install any new live pkgs scoped for autoinstall on this machine.
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 |
# File 'lib/d3/client/class_methods.rb', line 381 def self.do_auto_installs() verbose = .verbose force = .force || D3.forced? D3.log 'Checking for new packages to auto-install', :warn D3::Client.set_env :auto_install begin # for ensure below D3::Client::Receipt.basenames :refresh # loop through the groups for this machine auto_groups = D3::Client.computer_groups.dup auto_groups.unshift D3::STANDARD_AUTO_GROUP auto_groups.each do |group| # this is the intersection of all pkg ids that get auto-installed # for the group, and all live pkg ids... # meaning this machine should have these pkg ids. live_ids_for_group = (D3::Package.live_data.keys & D3::Package.auto_install_ids_for_group(group)) live_ids_for_group.each do |live_id| # skip those not available next unless available_pkg_ids.include? live_id auto_install_basename = D3::Package.live_data[live_id][:basename] # skip if this basename is installed already - it'll be handled with # the update_installed_pkgs method during sync. next if D3::Client::Receipt.all.keys.include? auto_install_basename new_pkg = D3::Package.fetch id: live_id if new_pkg.reboot? queued_id = puppy_in_queue new_pkg.basename if queued_id && queued_id >= new_pkg.id D3.log "Skipping auto-install of puppy-package #{new_pkg.edition}, there's a newer one in the queue already", :info next end # if queued_id && queued_id >= new_pkg.id end # if new_pkg.reboot? begin D3.log "Auto-installing #{new_pkg.basename} for group '#{group}'", :info cloud = cloud_dist_point_to_use(pkg: new_pkg) new_pkg.install( admin: D3::AUTO_INSTALL_ADMIN, verbose: verbose, force: force, puppywalk: .puppies, alt_download_url: cloud ) D3.log "Auto-installed #{new_pkg.basename}", :warn rescue JSS::MissingDataError, JSS::InvalidDataError, D3::InstallError D3.log "Skipping auto-install of #{new_pkg.edition}: #{$ERROR_INFO}", :error D3.log_backtrace rescue D3::PreInstallError D3.log "There was an error with the pre-install script for #{new_pkg.edition}: #{$ERROR_INFO}", :error D3.log_backtrace rescue D3::PostInstallError D3.log "There was an error with the post-install script for #{new_pkg.edition}: #{$ERROR_INFO} NOTE: #{new_pkg.edition} was installed, but may not work.", :error D3.log_backtrace end # begin end # live_ids_for_group.each do |live_id| end # each group ensure D3::Client.unset_env :auto_install end end |
.do_expirations(verbose = false, force = D3.forced?) ⇒ void
This method returns an undefined value.
Expire any pkgs that are due for expiration, and if any are expired, run the expiration policy.
682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 |
# File 'lib/d3/client/class_methods.rb', line 682 def self.do_expirations (verbose = false, force = D3.forced?) @@editions_expired = [] D3.log 'Starting expiration check', :warn D3::Client::Receipt.all.values.each do |rcpt| begin # rcpt.expire only does anything if expiration is appropriate. expired_edition = rcpt.expire verbose, force @@editions_expired << expired_edition if expired_edition rescue D3.log "There was an error expiring #{rcpt.edition}: #{$ERROR_INFO}", :error D3.log_backtrace end end return true if @@editions_expired.empty? D3::Client.set_env :finished_expirations, @@editions_expired.join(' ') if policy = D3::CONFIG.client_expiration_policy D3.run_policy policy, :expiration, verbose end # if D3::CONFIG.client exp policy D3::Client.unset_env :finished_expirations @@editions_expired = [] end |
.do_puppy_queue_installs_from_sync(options) ⇒ Object
Do any pending puppy installs right now, because we’re syncing and –puppies option was given
618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 |
# File 'lib/d3/client/class_methods.rb', line 618 def self.do_puppy_queue_installs_from_sync() return unless .puppies return if D3::PUPPY_Q.q.empty? D3.log 'Installing all pkgs from puppy-queue during sync with --puppies', :info D3::PUPPY_Q.q.each do |basename, puppy| begin D3.log "Installing #{puppy.edition} from puppy-queue during sync with --puppies", :debug new_pkg = D3::Package.fetch id: puppy.id cloud = cloud_dist_point_to_use(pkg: new_pkg) new_pkg.install( admin: puppy.admin, verbose: .verbose, force: puppy.force, puppywalk: true, expiration: puppy.expiration, alt_download_url: cloud ) D3::PUPPY_Q - puppy rescue JSS::NoSuchItemError D3.log "Skipping install of #{new_pkg.edition} from queue:\n no longer in d3.", :error D3.log_backtrace D3::PUPPY_Q - puppy rescue JSS::MissingDataError, JSS::InvalidDataError, D3::InstallError D3.log "Skipping install of #{new_pkg.edition} from queue: #{$ERROR_INFO}", :error D3.log_backtrace rescue D3::PreInstallError D3.log "There was an error with the pre-install script for #{new_pkg.edition}: #{$ERROR_INFO}", :error D3.log_backtrace rescue D3::PostInstallError D3.log "There was an error with the post-install script for #{new_pkg.edition}: #{$ERROR_INFO} NOTE: #{new_pkg.edition} was installed, but may not work.", :error D3.log_backtrace D3::PUPPY_Q - puppy end # begin end # each do puppy end |
.foreground_executable_path ⇒ Pathname?
get the executable path of the current foreground GUI app. NOTE, if you have fast user switching on, or multi-user screensharing, this only gets the one currenly using the physical console
847 848 849 850 851 852 853 854 855 856 857 858 859 |
# File 'lib/d3/client/class_methods.rb', line 847 def self.foreground_executable_path lsai = '/usr/bin/lsappinfo' ls_app_id = `#{lsai} front`.chomp return nil if ls_app_id == '[ NULL ] ' raw = `#{lsai} info -only executablepath '#{ls_app_id}'`.chomp return nil if raw.empty? path = raw.split(/=\s*"/).last return nil unless path path.chomp!('"') path.empty? ? nil : Pathname.new(path) end |
.forget_receipts(basenames) ⇒ void
This method returns an undefined value.
forget one or more receipts, and their matching apple pkg receipts
605 606 607 608 609 610 611 612 613 |
# File 'lib/d3/client/class_methods.rb', line 605 def self.forget_receipts(basenames) basenames.each do |bn| rcpt = D3::Client::Receipt.all[bn] next unless rcpt rcpt.apple_pkg_ids.each { |ar| system "/usr/sbin/pkgutil --forget '#{ar}'" } D3::Client::Receipt.remove_receipt bn D3.log "Receipt for #{rcpt.edition} has been forgotten", :warn end end |
.freeze_receipts(basenames) ⇒ void
This method returns an undefined value.
Freeze one or more receipts
565 566 567 568 569 570 571 572 573 574 575 576 577 |
# File 'lib/d3/client/class_methods.rb', line 565 def self.freeze_receipts(basenames) basenames.each do |bn| rcpt = D3::Client::Receipt.all[bn] next unless rcpt if rcpt.frozen D3.log "Can't freeze receipt for #{rcpt.edition}: already frozen.", :warn next end rcpt.freeze rcpt.update D3.log "Freezing receipt for #{rcpt.edition}, will not auto-update during sync", :warn end end |
.get_admin(pkg_to_install, options) ⇒ String
Return a valid, possibly-default, admin name for installing a package. Since the admin name is stored in the packages in the puppy-q, use that one if it’s there.
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/d3/client/class_methods.rb', line 170 def self.get_admin(pkg_to_install, ) # is this puppy already in the queue? If so, # the queue has our admin_name if .puppies && D3::PUPPY_Q.q[pkg_to_install.basename] admin = D3::PUPPY_Q.q[pkg_to_install.basename].admin admin ||= D3::DFT_PUPPY_ADMIN # not a puppy pkg else # start with the cli options admin = .admin # then do a lookup if no cli option admin ||= D3.admin end # if @options.puppies admin end |
.get_ro_pass(pw) ⇒ String?
Get a stored read-only password from a file or an executable.
Raises a JSS::UnsupportedError if the file isn’t owned by root with 0600 permissions.
NOTE: for slightly better security, don’t store the result in a variable, use this method as needed to retrieve the passwd every time you need it.
See also D3::Configuration
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/d3/client/auth.rb', line 75 def self.get_ro_pass (pw) raise JSS::InvalidDataError, "Arg must be one of :jss, :db, :dist, :http" unless [:jss, :db, :dist, :http].include? pw path = case pw when :jss then D3::CONFIG.client_jss_ropw_path when :db then D3::CONFIG.client_db_ropw_path when :dist then D3::CONFIG.client_distpoint_ropw_path when :http then D3::CONFIG.client_http_ropw_path end # path = case return nil unless path # if the path ends with a pipe, its a command that will # return the desired password, so remove the pipe, # execute it, and return stdout from it. if path.end_with? "|" cmd = path.chomp '|' output = `#{cmd} 2>&1`.chomp return output if $CHILD_STATUS.exitstatus.zero? raise D3::PermissionError, "can't get client password for #{pw}: #{output}" end file = Pathname.new path return nil unless file.file? stat = file.stat unless ("%o" % stat.mode).end_with? "0600" and stat.uid == 0 raise JSS::UnsupportedError, "Password file for '#{pw}' has insecure permissions, must be 0600." end # chomping an empty string removes all trailing \n's and \r\n's file.read.chomp('') end |
.install(pkgs, options) ⇒ void
This method returns an undefined value.
Install one or more packages from the command-line by basename, or edition (or name, filename, id)
This method is only used by manual installs (i.e. not automated via d3 sync)
Basenames always gets the live pkg for that basename
Editions install the package regardless of status.
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/d3/client/class_methods.rb', line 49 def self.install(pkgs, ) pkgs = [pkgs] if pkgs.is_a? String pkgs.each do |pkg_to_search| begin # get a D3::Package object desired_pkg = D3::Package.find_package(pkg_to_search) raise JSS::NoSuchItemError, "No d3 package matching #{pkg_to_search}" unless desired_pkg raise D3::InstallError, "The package for #{desired_pkg.edition} is missing from the JSS" if desired_pkg.missing? if .custom_expiration D3.log "Sorry #{desired_pkg.edition} is not expirable. A d3 admin needs to add an expiration path.", :warn if desired_pkg.expiration_paths.empty? break end curr_rcpt = D3::Client::Receipt.all[desired_pkg.basename] # If we were asked to freeze_on_install and the currently installed is # same edition, freeze it anyway. # Use force to freeze if the currently installed is newer. # if curr_rcpt && curr_rcpt.id >= desired_pkg.id && .freeze_on_install if .force || curr_rcpt.id == desired_pkg.id freeze_receipts([curr_rcpt.basename]) unless curr_rcpt.frozen? D3.log "Freezing previously installed #{curr_rcpt.edition}", :warn break end # if options.force elsif curr_rcpt.id == desired_pkg.id D3.log "Cannot freeze previously installed #{curr_rcpt.edition} (#{curr_rcpt.status}) It is newer than #{desired_pkg.edition}. Use --force if needed.", :warn break end # many things can be forced # things that are defined in the pkg itself # (exclusions, prohibiting procs, oses, cpus) # are checked in the Package#install method # These things are the responsibility of the # client. unless .force # deprecated pkgs need force for installing desired_pkg.check_for_deprecated # skipped pkgs need force for installing desired_pkg.check_for_skipped # same or newer? desired_pkg.check_for_newer_version end # unless options.force if curr_rcpt D3.log("Un-freezing #{curr_rcpt.edition} by installing #{desired_pkg.edition}", :warn) if curr_rcpt.frozen? if desired_pkg.id == curr_rcpt.id D3.log("Re-installing #{desired_pkg.edition}(#{desired_pkg.status})", :warn) elsif desired_pkg.id < curr_rcpt.id D3.log("Rolling back #{curr_rcpt.edition}(#{curr_rcpt.status}) to #{desired_pkg.edition}(#{desired_pkg.status})", :warn) else D3.log("Updating #{curr_rcpt.edition}(#{curr_rcpt.status}) to #{desired_pkg.edition}(#{desired_pkg.status})", :warn) end end # if curr rcpt cloud = cloud_dist_point_to_use(pkg: desired_pkg) desired_pkg.install( force: .force, admin: get_admin(desired_pkg, ), puppywalk: .puppies, expiration: .custom_expiration, verbose: .verbose, alt_download_url: cloud ) freeze_receipts([desired_pkg.basename]) if .freeze_on_install D3.log "Finished installing #{desired_pkg.edition}(#{desired_pkg.status})", :info rescue JSS::MissingDataError, JSS::NoSuchItemError, JSS::InvalidDataError, D3::InstallError D3.log "Skipping installation of #{pkg_to_search}: #{$ERROR_INFO}", :error D3.log_backtrace rescue D3::PreInstallError D3.log "There was an error with the pre-install script for #{desired_pkg.edition}: #{$ERROR_INFO}", :error D3.log_backtrace rescue D3::PostInstallError D3.log "There was an error with the post-install script for #{desired_pkg.edition}: #{$ERROR_INFO} NOTE: it was installed, but may have problems.", :error D3.log_backtrace end # begin end # args.each end |
.list_available(force = false) ⇒ void
This method returns an undefined value.
list currently available packages to stdout via ‘less’
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/d3/client/lists.rb', line 146 def self.list_available(force = false) # If using force, show all live pkgs if force or D3.forced? ids_to_show = D3::Package.live_ids title = "All live packages in d3 (* = installed, ^ = puppies)" # otherwise, only those available to this machine based on # excluded_groups. # (the intersection of all live, with all available to this machine, # the latter of which includes non-live) else ids_to_show = D3::Package.live_ids & D3::Client.available_pkg_ids title = "Live packages available for this machine (* = installed, ^ = puppies)" end # if force header = ["Basename", "Vers-Rev" , "Auto-installed on" ] my_rcpt_ids = D3::Client::Receipt.all.values.map{|r| r.id} lines = [] ids_to_show.each do |id| pkg = D3::Package.package_data[id] bn = pkg[:basename] bn += "*" if my_rcpt_ids.include? id bn += "^" if pkg[:reboot] auto_grps = pkg[:auto_groups].empty? ? "-" : pkg[:auto_groups].join(',') lines << [bn, "#{pkg[:version]}-#{pkg[:revision]}", auto_grps ] end lines.sort_by! {|l| l[0]} D3.less_text D3.generate_report(lines, header_row: header, title: title) return true end |
.list_details(pkgs) ⇒ void
This method returns an undefined value.
Display the details about one or more pkgs and/or receipts on the local machine
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 |
# File 'lib/d3/client/lists.rb', line 257 def self.list_details(pkgs) pkgs = [pkgs] if pkgs.is_a? String pkgs.each do |item_to_match| begin # package details server_pkg = D3::Package.find_package(item_to_match) if server_pkg puts "### Found package on the server matching '#{item_to_match}'\n" puts server_pkg.formatted_details else puts "### No package on the server matched '#{item_to_match}'" puts "### (doesn't exist, or basename has no live editions)" end # receipt details rcpt = D3::Client::Receipt.find_receipt item_to_match if rcpt puts if server_pkg if rcpt.edition == server_pkg.edition puts "### Found matching receipt for edition '#{server_pkg.edition}'\n" else puts "### Found receipt for different edition: '#{rcpt.edition}'\n" end # if rcpt.edition == server_pkg.edition else # no svr pkg puts "### Found receipt matching '#{item_to_match}'\n" end # if svr pkg puts rcpt.formatted_details else # no rcpt puts "### No receipt matched '#{item_to_match}'" end # if rcpt rescue D3.log "An error occured getting the details of #{item_to_match}:\n #{$!}", :error D3.log_backtrace next end # begin end # args.each end |
.list_files(pkgs) ⇒ Object
list the files installed by one or more installers
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'lib/d3/client/lists.rb', line 184 def self.list_files(pkgs) self.connect_for_reports pkgs.each do |pkg_to_match| begin found_pkg = D3::Package.find_package pkg_to_match unless found_pkg puts "Skipping '#{pkg_to_match}': no matching edition in d3" next end puts "Querying for files installed by '#{found_pkg.edition}'..." # because this is just a list of single strings # and doesn't need column formatting, # and mostly because it can be tens of thousands # of lines long, we're not using 'generate_report" # and just building a huge string to display. file_list = "# Files installed by #{found_pkg.edition}\n" file_list += "#==========================================================================\n" file_list += found_pkg.installed_files.join("\n") D3.less_text file_list rescue JSS::MissingDataError, JSS::InvalidDataError D3.log "Skipping #{item_to_match}:\n #{$!}", :error D3.log_backtrace end # begin end # isntallers.each end |
.list_frozen ⇒ Object
list all frozen pkgs
118 119 120 |
# File 'lib/d3/client/lists.rb', line 118 def self.list_frozen self.list_installed :frozen end |
.list_installed(what_to_list = :all) ⇒ void
This method returns an undefined value.
list installed d3 items. The arg can be used to limit what’s listed and can be one of :all, :manual, :pilot, :frozen. (anything other than :manual, :pilot, or :frozen is treated as :all)
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/d3/client/lists.rb', line 50 def self.list_installed (what_to_list = :all) case what_to_list when :manual then title = "Manually installed packages (not-uninstallable<, frozen^)" kind = "manually installed " when :pilots then title = "Packages being piloted on this machine (not-uninstallable<, frozen^)" kind = "pilot " when :frozen then title = "Packages frozen on this machine (not-uninstallable<)" kind = "frozen " else title = "All packages installed by d3 (not-uninstallable<, frozen^)" kind = "" end # case show colheaders = %w{Basename Vers-Rev Status Installed By} lines = [] D3::Client::Receipt.all.keys.sort.each do |bn| # its a d3 installer rcpt = D3::Client::Receipt.all[bn] if what_to_list == :manual next unless rcpt.manual? end # if manual if what_to_list == :pilots next unless rcpt.pilot? end if what_to_list == :frozen next unless rcpt.frozen? end basename = rcpt.basename basename += "<" unless rcpt.removable? basename += "^" if rcpt.frozen? and (not what_to_list == :frozen) date = rcpt.installed_at.strftime "%Y-%m-%d" lines << [basename, "#{rcpt.version}-#{rcpt.revision}", rcpt.status, date, rcpt.admin] end # installed_pkgs.each if lines.empty? puts "No #{kind}receipts on this computer" else D3.less_text D3.generate_report(lines, :title => title, :header_row => colheaders) end end |
.list_manual ⇒ Object
list all manually installed pkgs
106 107 108 |
# File 'lib/d3/client/lists.rb', line 106 def self.list_manual self.list_installed :manual end |
.list_pending_puppies ⇒ Object
list_pending_puppies
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/d3/client/lists.rb', line 124 def self.list_pending_puppies if D3::PUPPY_Q.q.empty? puts "# There are no puppies in the queue" return nil end title = "Puppy packages awaiting logout" colheaders = %w{Edition Status Queued-at By} lines = [] # loop through the puppies in the queue D3::PUPPY_Q.q.values.each do | pup| lines << [pup.edition, pup.status, (pup.queued_at.strftime "%b %d %Y %H:%M:%S"), pup.admin] end # do pup D3.less_text D3.generate_report(lines, :title => title, :header_row => colheaders) end |
.list_pilots ⇒ Object
list all installed pilots
112 113 114 |
# File 'lib/d3/client/lists.rb', line 112 def self.list_pilots self.list_installed :pilots end |
.puppy_in_queue(basename) ⇒ Integer?
Given a basename, is any edition of it in the puppy queue? If so, return the id of the queued pkg, else return nil
835 836 837 838 839 |
# File 'lib/d3/client/class_methods.rb', line 835 def self.puppy_in_queue(basename) pup = D3::PUPPY_Q.queue[basename] return nil unless pup pup.id end |
.puppy_notification_ok_with_admin=(bool) ⇒ void
This method returns an undefined value.
Set the –no-puppy-notification option as given by the admin
669 670 671 |
# File 'lib/d3/client/class_methods.rb', line 669 def self.puppy_notification_ok_with_admin= (bool) @@puppy_notification_ok_with_admin = bool end |
.puppy_notification_ok_with_admin? ⇒ Boolean
Was the –no-puppy-notification option given by the admin?
659 660 661 |
# File 'lib/d3/client/class_methods.rb', line 659 def self.puppy_notification_ok_with_admin? @@puppy_notification_ok_with_admin end |
.query_files(paths) ⇒ Object
find out which editions install one or more given files
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 |
# File 'lib/d3/client/lists.rb', line 215 def self.query_files (paths) self.connect_for_reports paths.each do |path| puts "Querying for packages that install '#{path}'..." path = path.chomp "/" # remove trailing slashes on dirs query = <<-ENDQ SELECT pkgs.package_id FROM #{D3::Package::P_TABLE[:table_name]} pkgs JOIN #{D3::Package::PKG_CONTENTS_TABLE} contents ON pkgs.#{D3::Package::P_FIELDS[:id][:field_name]} = contents.#{D3::Package::P_FIELDS[:id][:field_name]} WHERE contents.file = '#{Mysql.quote path}' ENDQ search_results = JSS::DB_CNX.db.query query ids = [] search_results.each{|id| ids << id[0].to_i} search_results.free if ids.empty? puts "# Nothing in d3 installs '#{path}'" else title = "Packages that install '#{path}'" colheader = %w{Edition Status Installed} lines = [] ids.each do |id| begin pkg = D3::Package.fetch id: id lines << [pkg.edition, pkg.status.to_s, (pkg.installed? ? "yes" : "no")] rescue D3.log "Couldn't get pkg for id #{id}", :error end # begin end D3.less_text D3.generate_report(lines, header_row: colheader, title: title) end # if ids.empty? end # paths each path end |
.set_env(var, value = 1) ⇒ void
This method returns an undefined value.
Set an ENV variable to the ‘set’ state, usually ‘1’
110 111 112 113 |
# File 'lib/d3/client/environment.rb', line 110 def self.set_env (var, value = 1) raise JSS::InvalidDataError, "var must be one of: :#{ENV_STATES.keys.join(' :')}" unless ENV_STATES.keys.include? var ENV[ENV_STATES[var]] = value.to_s end |
.sync(options = OpenStruct.new) ⇒ void
This method returns an undefined value.
Sync this machine
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
# File 'lib/d3/client/class_methods.rb', line 219 def self.sync( = OpenStruct.new) D3::Client.set_env :sync D3.log 'Starting sync', :warn begin # update rcpts update_rcpts # clean out any invalid puppies from the queue clean_doghouse # install puppies now? do_puppy_queue_installs_from_sync # updates/patches? update_installed_pkgs # new auto-installs? do_auto_installs # expirations do_expirations # removie receipts w/ missing packages on the server # This must happen AFTER update_installed_pkgs # so that the basename gets any updates on the server # before removing the recetip (which wouild prevent # updates) clean_missing_receipts D3.log 'Finished sync', :warn ensure D3::Client.unset_env :sync end end |
.thaw_receipts(basenames) ⇒ void
This method returns an undefined value.
Thaw one or more receipts
585 586 587 588 589 590 591 592 593 594 595 596 597 |
# File 'lib/d3/client/class_methods.rb', line 585 def self.thaw_receipts(basenames) basenames.each do |bn| rcpt = D3::Client::Receipt.all[bn] next unless rcpt unless rcpt.frozen D3.log "Can't thaw receipt for #{rcpt.edition}: not frozen.", :warn next end rcpt.thaw rcpt.update D3.log "Thawing receipt for #{rcpt.edition}, will resume auto-update during sync", :warn end end |
.uninstall(rcpts, options) ⇒ void
This method returns an undefined value.
uninstall one or more packages from the commandline
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/d3/client/class_methods.rb', line 141 def self.uninstall(rcpts, ) rcpts = [rcpts] if rcpts.is_a? String rcpts.each do |rcpt_to_remove| begin rcpt = D3::Client::Receipt.find_receipt rcpt_to_remove raise D3::UninstallError, "No receipt for '#{rcpt_to_remove}', can't uninstall." unless rcpt D3.log "Uninstalling #{rcpt.edition}...", :info rcpt.uninstall .verbose, .force D3.log "Finished uninstalling #{rcpt.edition}.", :info rescue JSS::MissingDataError, D3::UninstallError, JSS::InvalidDataError D3.log "Skipping uninstall of #{rcpt_to_remove}: #{$ERROR_INFO}", :error D3.log_backtrace next end # begin end # rcpts.each end |
.unset_all_env ⇒ void
This method returns an undefined value.
Unset all ENV vars
130 131 132 |
# File 'lib/d3/client/environment.rb', line 130 def self.unset_all_env ENV_STATES.keys.each{|v| ENV[ENV_STATES[v]] = nil } end |
.unset_env(var) ⇒ void
This method returns an undefined value.
Unset an ENV variable
121 122 123 124 |
# File 'lib/d3/client/environment.rb', line 121 def self.unset_env (var) raise JSS::InvalidDataError, "var must be one of: :#{ENV_STATES.keys.join(' :')}" unless ENV_STATES.keys.include? var ENV[ENV_STATES[var]] = nil end |
.update_installed_pkgs(options) ⇒ void
This method returns an undefined value.
Update any currently installed basenames to the currently live one skipping any basenames currently frozen
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 |
# File 'lib/d3/client/class_methods.rb', line 465 def self.update_installed_pkgs() verbose = .verbose force = .force || D3.forced? D3.log 'Checking for updates to installed packages', :warn D3::Client.set_env :auto_update begin # see ensure below # get the current list of live basenames and the ids of the live editions live_basenames_to_ids = D3::Package.basenames_to_live_ids # loop through the install pkgs D3::Client::Receipt.all.values.each do |rcpt| # is there a live pkg for this basename? if live_basenames_to_ids[rcpt.basename] live_id = live_basenames_to_ids[rcpt.basename] live_pkg_data = D3::Package.package_data[live_id] else D3.log "Skipping update for #{rcpt.edition}: no currently live package for basename", :info next end # are we rolling back? Not if the recpt is in pilot. if live_pkg_data[:id] < rcpt.id if rcpt.pilot? D3.log "Skipping rollback of #{live_pkg_data[:edition]}, #{rcpt.edition} is in pilot", :info next else rollback = true end # no we aren't rolling back else # skip unless the live id is higher than the rcpt id unless live_pkg_data[:id] > rcpt.id D3.log "No update for #{rcpt.edition}", :debug next end end # skip any frozen receipts if rcpt.frozen? D3.log "Skipping update check for #{rcpt.edition}(#{rcpt.status}): currently frozen on this machine.", :warn next end # check the puppy queue if needed if live_pkg_data[:reboot] queued_id = puppy_in_queue(live_pkg_data[:basename]) if queued_id && queued_id >= live_pkg_data[:id] D3.log "Skipping auto-update of puppy-queue item #{live_pkg_data[:edition]}, there's a newer one in the queue already", :info next end # if queued_id && queued_id >= live_pkg.id end # if live_pkg.reboot? # mention rollbacks if rollback D3.log "Rolling back #{rcpt.edition} (#{rcpt.status}) to older live #{live_pkg_data[:edition]}.", :warn else D3.log "Updating #{rcpt.edition} (#{rcpt.status}) to #{live_pkg_data[:edition]} (#{live_pkg_data[:status]})", :warn end # are we bringing over a custom expiration period? expiration = rcpt.custom_expiration ? rcpt.expiration : nil # heres the pkg live_pkg = D3::Package.fetch id: live_basenames_to_ids[rcpt.basename] begin cloud = cloud_dist_point_to_use(pkg: live_pkg) live_pkg.install( admin: rcpt.admin, expiration: expiration, verbose: verbose, force: force, puppywalk: .puppies, alt_download_url: cloud ) D3.log "Done updating #{rcpt.edition} (#{rcpt.status}) to #{live_pkg.edition} (#{live_pkg.status})", :info rescue JSS::MissingDataError, JSS::InvalidDataError, D3::InstallError D3.log "Skipping update of #{rcpt.edition} to #{live_pkg.edition}: #{$ERROR_INFO}", :error D3.log_backtrace rescue D3::PreInstallError D3.log "There was an error with the pre-install script for #{live_pkg.edition}: #{$ERROR_INFO}", :error D3.log_backtrace rescue D3::PostInstallError D3.log "There was an error with the post-install script for #{live_pkg.edition}: #{$ERROR_INFO} NOTE: #{live_pkg.edition} was installed, but may not work.", :error D3.log_backtrace end # begin end # D3::Client::Receipt.all.values.each ensure D3::Client.unset_env :auto_update end # begin..ensure end |
.update_rcpts ⇒ void
This method returns an undefined value.
Update any receipt data that might be changed in the matching package on the server, including:
-
status
-
pre- or post-remove scripts
-
removability
-
prohibiting processes
-
expiration details
Also update
-
last usage for expiring pkgs
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 |
# File 'lib/d3/client/class_methods.rb', line 268 def self.update_rcpts D3.log 'Updating receipts', :warn D3::Client::Receipt.all.each do |basename, rcpt| pkgdata = D3::Package.find_package rcpt.edition, :hash unless pkgdata # if this pkg is missing, mark it so... D3.log "Receipt '#{rcpt.edition}' is missing from d3. Updating receipt.", :info rcpt.status = :missing rcpt.update next end need_update = false # Are we rolling back to a prev version? # If the pkgdata[:status] is :pilot and the # rcpt.status is NOT :pilot, then we are. rolling_back = (pkgdata[:status] == :pilot) && (rcpt.status != :pilot) # status unless rolling_back if rcpt.status != pkgdata[:status] # update the status rcpt.status = pkgdata[:status] D3.log "Updating status for #{rcpt.edition} to #{pkgdata[:status]}", :info need_update = true end # if end # unless # pre-remove script if rcpt.pre_remove_script_id != pkgdata[:pre_remove_script_id] rcpt.pre_remove_script_id = pkgdata[:pre_remove_script_id] D3.log "Updating pre-remove script for #{rcpt.edition}", :info need_update = true end # if # post-remove script if rcpt.post_remove_script_id != pkgdata[:post_remove_script_id] rcpt.post_remove_script_id = pkgdata[:post_remove_script_id] D3.log "Updating post-remove script for #{rcpt.edition}", :info need_update = true end # if # removability if rcpt.removable? != pkgdata[:removable] rcpt.removable = pkgdata[:removable] D3.log "Updating removability for #{rcpt.edition}", :info unless rcpt.removable? rcpt.expiration = 0 D3.log "#{rcpt.edition} is not expirable now that it's not removable", :info end need_update = true end # if # expiration if rcpt.removable? unless rcpt.expiration_paths_match? pkgdata[:expiration_paths] rcpt.expiration_paths = pkgdata[:expiration_paths] D3.log "Updating expiration path(s) for #{rcpt.edition}", :info need_update = true end # if if (rcpt.expiration != pkgdata[:expiration].to_i) && !rcpt.custom_expiration rcpt.expiration = pkgdata[:expiration].to_i D3.log "Updating expiration for #{rcpt.edition}", :info need_update = true end # if end # if removable # prohibiting_processes # make sure they are all arrays as of v3.0.12 unless rcpt.prohibiting_processes.is_a? Array rcpt.prohibiting_processes = JSS.to_s_and_a(rcpt.prohibiting_processes)[:arrayform] need_update = true end if rcpt.prohibiting_processes.sort != pkgdata[:prohibiting_processes].sort rcpt.prohibiting_processes = pkgdata[:prohibiting_processes] D3.log "Updating prohibiting_processes for #{rcpt.edition}", :info need_update = true end # if rcpt.update if need_update end # each do basename, rcpt end |
.validate_pkg_in_cloud(url, pkg) ⇒ Boolean
given a cloud url and a D3::Package is the pkg available at that url?
798 799 800 801 802 803 804 805 806 807 808 809 810 811 |
# File 'lib/d3/client/class_methods.rb', line 798 def self.validate_pkg_in_cloud(url, pkg) full_url = "#{url}/#{pkg.filename}" dummy_install_target = Pathname.new('/Volumes/' + Time.now.asctime) jamf_cmd = "#{JSS::Client::JAMF_BINARY} install -package #{Shellwords.escape pkg.filename} -path #{Shellwords.escape full_url} -target #{Shellwords.escape dummy_install_target}/ -showProgress -verbose" Open3.popen2e(jamf_cmd) do |_stdin, stdout_err, wait_thr| stdout_err.each do |line| if /^\d*+\.\d*+% / =~ line Process.kill('KILL', wait_thr.pid) return true end # end if /^\d*+\.\d*+% / =~ line end # end stdout_err.each do |line| return false end # end Open3.popen2e(jamf_cmd) do |_stdin, stdout_err, wait_thr| end |